Windows SEH Overflow (EasyChat)
Scenario
You have been tasked by your red team manager, to refresh your Windows exploit development skills. Specifically, he provided you with a machine (172.16.5.120) that features a vulnerable to SEH overflow version of the EasyChat server. An exploit skeleton* is also provided to you. Your task is to fully exploit the SEH-based overflow vulnerability of the EasyChat server.
*Find below the exploit skeleton that causes the application to crash.
import os, sys, socket
ip = "172.16.5.120"
port = 80
socket = socket.socket(socket.AF_INET , socket.SOCK_STREAM)
socket.connect((ip , port))
buffer = "A" * 725
request = "POST /registresult.htm HTTP/1.1\r\n\r\n"
request += "Host: 172.16.5.1"
request += "User-Agent: Mozilla/5.0 (X11; Linux i686; rv:45.0) Gecko/20100101 Firefox/45.0"
request += "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
request += "Accept-Language: en-US,en;q=0.5"
request += "Accept-Encoding: gzip, deflate"
request += "Referer: http://172.16.5.1/register.ghp"
request += "Connection: close"
request += "Content-Type: application/x-www-form-urlencoded"
request += "UserName=" + buffer +"&Password=test&Password1=test&Sex=1&Email=x@&Icon=x.gif&Resume=xxxx&cw=1&RoomID=4&RepUserName=admin&submit1=Register"
socket.send(request)
data = socket.recv(4096)
print data
socket.close()Goals
Fully exploit the vulnerable EasyChat server
Spawn calc.exe as a proof of concept
What you will learn
Exploiting SEH-based stack overflows
Recommended tools
ImmunityDbg
Mona.py
Python
Notepad++
Network Configuration & Credentials
Vulnerable machine: 172.16.5.120
SOLUTIONS
Below, you can find solutions for each task. Remember though that you can follow your own strategy (which may be different from the one explained in the following lab).
Task 1: Recognize the exploitable conditions
Let's try to figure out if we are really dealing with an SEH-based overflow and also, what offset exactly is needed to overflow the SEH. Let's launch the application (You might need to click the confirmation window before it starts listening for incoming connections).

Let's attach a debugger to the EasyChat process, as follows.

After attaching, remember to press Run (F9) since the application will be in a paused state.
Let's now launch the exploit against the application.

Let's also pass the exception to the application.

It certainly looks like the EIP can be controlled via SEH overwrite.
Feel free to use Immunity's "View -> SEH chain" functionality yourself to witness the SEH overwrite.
Task 2: Find offset to the seh/eip
Let's try to figure out the offset to the SEH structure using Mona's pattern_create, as follows.

We can find the complete pattern inside the Immunity Debugger folder on a file called pattern.txt. The default Immunity Debugger location is:
C:\Program Files\Immunity Inc\Immunity Debugger
Let's add the pattern into ours exploit, as follows.

After we restart the application and reattach the debugger, we launch the latest exploit. Once an exception is encountered, it is passed to the application.

To identify the offset, we pass the displayed EIP to Mona's pattern_offset.

We now know that we need to overwrite 221 bytes. This is until the current SEH. If you recall, there is also an nSEH record before the SEH, which is also 4-bytes long. We should thus remember that we start overwriting the exception handler structure at 217 bytes. Let's modify the buffer and launch the modified exploit against the target in order to confirm if our calculations were correct.

Before passing the exception to the program, let's go to view -> SEH chain.

We can see that the SEH structure was properly overwritten. Also, we can scroll down the stack view to see it.

After passing the exception to the program, we successfully overwrite EIP with C's

Task 3: Move the execution flow past the SEH entry
The next thing that will be required during the SEH exploitation, is the POP-POP-RET gadget. We can quickly find it using mona, as follows.

Since the output is pretty large, you can also find it in the default Immunity Debugger directory as an seh.txt file.

Let's choose any gadget that ends with a regular ret (ret X will corrupt the stack) and let's incorporate it into the exploit. Moreover, since the gadget will cause the program to start executing whatever is in the nSEH, let's place breakpoints there so in case we successfully alter the execution flow, we will know about it.

Upon encountering an exception, do not immediately pass it to program. Let's first scroll down the stack and find the overwritten SEH structure. Go to the SEH pointer and right-click. Select "Follow in disassembler" from the drop-down menu.

You can see the instructions that are placed at this address (exactly those that were members of the chosen gadget).

Select the first POP instruction and right-click it. From the drop-down menu select Breakpoint -> Memory, on access.

As the breakpoint is placed, we can now pass the exception (Shift + F9) to the program. The execution will stop exactly at this instruction. From this point onwards, we will use the Step Into (F7) instruction, that makes the debugger go just to next instruction.

After pressing F7, we will land at the second POP instruction. We can see that the stack value was popped to the respective register. Press F7 once again, so you land on the RET instruction.

As we already know, RET causes the program to execute whatever the stack pointer is now pointing to. What is that? First, make sure you have your stack window aligned to ESP. Right-click on the ESP address and choose "Follow in Stack"

Now, right click on the top address on the stack and choose "Follow in Dump"

You can observe that those breakpoints that were put in the place of the nSEH, are now going to be executed.

Press Step Into once again.

And we are executing the breakpoints!
Now, since we know that the nSEH can be executed, we should change it to something useful, that will help us omit the SEH pointer and start executing whatever lies past it.
We can use the standard trick of short jump-ing 6 bytes forward. The opcodes for it are:
EB 06. In order to pad the remaining 2 bytes, we can use NOPs. This translates to the following.

Moreover, we add a shellcode placeholder containing one break point. If we will be able to reach the shellcode, the debugger will stop.
Let's launch the exploit and pass the exception to the program. We are executing shellcode!

Task 4: Discover any bad characters
Before we implement the final shellcode, let's check for the presence of bad characters. We will send a buffer of all ASCII's instead of shellcode.

After passing the exception to the program, we can inspect the stack for malformed bytes. There are two (\x25 and \x2b) which were changed to some other bytes.

Task 5: Finalize the exploit
Knowing which characters are bad for this software, we can finally generate shellcode using msfvenom. We can also add it to the exploit, replacing the single breakpoint.
msfvenom -p windows/exec cmd=calc.exe exitfunc=thread -b "\x00\x25\x2b" -f c

Let's launch the latest exploit against the software without attaching a debugger to it. Calc should show up!

Last updated