SEH
SEH (Structured Exception Handling) is the mechanism Windows uses for exceptions.
They are implemented as a linked list, and each node contains a pointer to an exception handler.
The last node is the default handler, which crashes the application.
Thread Environment Block
The TEB is a data structure containing information about the current thread, and that includes the current SEH frame.
The FS register will point to the TEB. We can access the SEH frame at FS:[0]
.
Make sure you have WinDBG and MSVC installed.
|
|
$ cl main.cpp
Compile the code and open the executable in WinDBG.
You can use !exhain
to view the SEH chain, and use d FS:[0]
to view the TEB.
We dump the first record in the chain and the last. Notice how each part a record contains the following:
4 bytes which point to the next handler (nSEH).
4 bytes that point to the current handler.
I have color coded the image to make it easier to see.
Using the current one as an example:
00d9f910
(10f9d900
in little endian) which is nSEH.
00061cb0
(b01c0600
in little endian) is the pointer to the handler.
Do notice how the last nSEH is FFFFFFFF. If it is reached, the application will crash.
Exploitation
We can overwrite the SEH record to obtain code execution.
We will use this vulnerability as an example: https://www.exploit-db.com/exploits/49089
The link contains a download link for the application, as well as an exploit.
The vulnerability is located on the code that parses a .wav file.
What we want to do is overwrite nSEH with a JMP instruction, and SEH with POP POP RET. The handler will be called, it will pop 8 bytes of the stack, the return will jump to where our nSEH is (which has been replaced by a JMP) is located and start executing the JMP, landing on a NOP sled and eventually our shellcode.
Now, open the application in x64dbg. The binary has anti debugging functionalities, so make sure you’re using the ScyllaHide plugin. I used msf-pattern_create to check how many bytes I needed to overwrite nSEH. We need 4132 bytes.
|
|
Run the script to generate the wav file and open the program under x64dbg.
Go to Batch Convert Mode and add the wav we created. When the application crashes switch to the SEH tab on the debugger.
Great! It seems we have the correct offset.
For the next steps make sure you install the ERC plugin.
Now we want to overwrite nSEH with a JMP instruction.
We can use ERC for this.
ERC --assemble JMP 10
JMP 10 = EB 08
|
|
Next we will need to search the binary for a POP POP RET sequence of instructions.
Type this in the x64dbg command input:
ERC –-SEH
I went with 0x0040652f
.
SEH = struct.pack("<I", 0x0040652f)
Now all that’s left is to add our shellcode. I will use msfvenom to generate it:
msfvenom -p windows/exec CMD=calc.exe -v shellcode -f python
Now our exploit should look like this:
|
|
Run it and try to add the file to the application. A calculator will pop up.