SEH Record Exploitation

A lot of programming languages, like C, C++, Java, Python, Ruby, etc, have exception support. In the event of an exception, the program searches back through the stack of function calls until an exception handler is found. Actually, the pointers to the exception handler are stored in the stack frame of each function. So, in effect, we have a function pointer on the stack that we can overwrite if we have a buffer overflow.

GS Stack Cookie

GS prevents the attacker from using an overwritten return address on the stack. It adds a stack cookie between the local variables and the return address, and checks if it has been changed at the end of the function. If it has, then it will not use the return address.

Bypassing GS

If we get the exception handler pointer to get called before the function returns, we’ll be able to exploit the buffer overflow despite the GS stack cookie. One way to do this, is to overflow the buffer with such a big string that it goes over the top of the stack, in order to cause an access violation exception. This will make the exception look for the exception handler pointer that we have overwritten in the stack. If we replace this pointer with the location of our shellcode, we would get control over the application, regardless of the GS cookie, since we would’ve never need to use the return address.

SEH Record

The SEH Record consists of eight bytes. It has two fields, the “next” field and the SEH function pointer. These two fields serve as arguments to the exception handler. We want the first field to point to the place in the stack were our shellcode is. Then we want the SEH function pointer to point to the first field, so that our shellcode gets called. Now we would need an instruction sequence that somehow points to the previous four bytes. This instruction sequence happens to be “Pop / Pop / Ret”. If we could get an address that points to the location of this instruction sequence into the SEH function pointer, eventually our shellcode will be executed.

How to make an SEH Record Exploit

  1. You need to overflow the buffer with a long enough string so that it overflows the stack. For convenience, you can create such string with the Metasploit tool “pattern_create.rb”. This will make it easier later, to find offsets you need to modify within the string, with the tool “pattern_offset.rb”. However, the use of these tools is not necessary.

  2. You need to find the address that points to your shellcode and to find out what is the offset within your string that ends up in the location of your shellcode.

  3. You have to look up the exception handler record’s address. To see all the current exception handler records, using WinDBG, you can use the command “!exchain”.

  4. You need to modify the eight bytes that make up the SEH Record. To do this, you need to find out what is the offset within your string that ends up in each of these two dwords. You will replace the first dword with the address pointing to your shellcode, and the second dword with the address pointing to the “pop / pop / ret” instruction sequence.

  5. That’s it. If done correctly, you should run your exploit against the application and take control over it.

Exploit Pseudocode Example

String = "Long_String"
Shellcode = “Some_Cool_Payload”
String[Shellcode_Offset] = Shellcode
String[First_dword_Offset] = Shellcode_Address
String[Second_dword_Offset] = POP_POP_RET_Address

WinDBG Example

Things to consider

If the “pop / pop / ret” instruction sequence that you chose is inside a SafeSEH protected module, the exploit will not work. In WinDBG, you can find which modules are protected, using the command “!nmod” from an extension called “narly”. Also, if DEP is in place, your shellcode will not be able to execute.

Useful WinDBG commands

  1. !exchain - Show you the addresses of the current exception handler records.

  2. !vprot - Shows you the memory protection info for a given address.

  3. !nmod - List SafeSEH, GS, DEP, and ASLR info about all loaded modules.

Other Tools (Metasploit)

  1. pattern_create.rb - Creates a pattern of a given length.

  2. pattern_offset.rb - Gives you the offset within a pattern created with the previous tool.