Hacking/Shellcode/Egg hunt/w32 SEH omelet shellcode
Omelet shellcode is a form of egg hunt shellcode, which will search user-land address space for multiple smaller eggs and recombine them into one larger block of shellcode and execute it. This is useful in situation where you cannot inject one block into a target process of sufficient size to store your shellcode in one piece but you can inject multiple smaller blocks and execute one of them.
How it works
When the omelet shellcode is executed, it installs an SEH handler to handle access violations. It then starts scanning memory by reading memory from address 0 one byte at a time upwards to address 0x8000,0000 looking for the first byte in each egg, which contains the size of the eggs.
When scanning causes an access violation, the SEH handler adds 0xFFFF to the address being read (the size of a page -1 byte) to skip over the non-readable page. If the address being read by the scanning code becomes bigger than 0x7FFF,FFFF, the scanning stops and the reconstructed shellcode can be executed (more on this below). Otherwise, it resets the stack to prevent stack exhaustion caused by recursive exceptions, re-installs itself as the SEH handler and continues scanning.
When the byte being read is equal to the size, it reads the DWORD following this byte and XORs this with the three marker bytes (bits 31-8) and one byte 0xFF (LSB). If this is the header of an egg, the resulting DWORD value should be the index of the egg: between 0 (inclusive) and the total number of eggs (exclusive). If it is not an egg, scanning continues with the next byte.
Once the egg is found, its index (calculated with the XOR) is multiplied by its size to get the offset of the egg in the original shellcode. To memory region allocated for the stack is looked up and the egg is stored at the lowest address in this region plus the offset. Once each egg has been found and its data copied to the stack, the shellcode should be completely reconstructs on the "bottom" of the stack.
When the scan has reached 0x8000,0000, all of user-land memory on Windows has been scanned (except if the /3GB switch is used of course) and all the eggs should have been processed. The SEH handler detects this and calls the reconstructed shellcode on the stack to execute it.
- This version works only on Windows 32-bit platforms and processes running in WoW64 because it uses the Windows specific Structured Exception Handler (SEH) feature to handle access violations caused by scanning memory.
- This version may not work on Windows installations that are using the /3GB switch, because they assume user-land address space ends at address 0x8000,0000. On systems with /3GB enabled, the user-land memory may run up to address 0xC000,0000, so some eggs may not be found before the shellcode is executed, causing the shellcode to be only partially reconstructed and fail to execute correctly.
I originally coded this years ago for a vulnerability in the way Winamp loaded certain malformed playlists. This vulnerability only allowed injection of small chunks of data in each playlist entry, each one too small for normal shellcode. Also, the chunks would each get loaded at an unpredictable location and not in any predetermined order. I developed a primitive version of omelet egg-hunt shellcode to get around this; which would execute one block, which would find the other blocks. I've created this project based on the original code, with a few improvements (mainly in the size of the egg-hunter code)
- Download the code: here.
- Download Python: here.
- Download NASM: here (if you want to make modifications to the .asm source and recompile it).
How to create an exploit using omelet shellcode
Creating the omelet shellcode and eggs
In order for omelet shellcode to work, your shellcode needs to be cut into eggs and each egg needs to have a header that contains its length, its index and 3 marker bytes that are used to detect them amongst all the other data in the user-land process address space. The omelet shellcode also needs to know the size of the eggs, how many eggs there are and what 3 bytes should be used to find them. The omelet shellcode itself is found in the "w32_SEH_omelet.asm" file and the code that
- Compile "w32_SEH_omelet.asm" using NASM to "w32_SEH_omelet.bin":
- nasm.exe -f bin -o "w32_SEH_omelet.bin" "w32_SEH_omelet.asm" -w+error
- (the code archive comes with a pre-compiled version of "w32_SEH_omelet.bin").
- Create a file with the binary shellcode you want to use in your exploit and call this shellcode.bin.
- Create a text file with the omelet shellcode and the eggs:
- w32_SEH_omelet.py w32_SEH_omelet.bin shellcode.bin w32_SEH_omelet_output.txt
You can optionally specify the size of each egg as the fourth argument and the 24-bit value to use as the marker as the fith argument, eg. to have 64 byte eggs marked with 0xBADA55, use this:
- w32_SEH_omelet.py w32_SEH_omelet.bin shellcode.bin w32_SEH_omelet_output.txt 64 0xBADA55
Using the omeley shellcode and eggs
The data in the "w32_SEH_omelet_output.txt" file will look something like this:
// This is the binary code that needs to be executed to find the eggs, // recombine the orignal shellcode and execute it. It is 82 bytes: omelet_code = "\x31\xFF\xEB\x23\x51\x64\x89\x20\xFC\xB0 ... \xFF\x50\x08"; // These are the eggs that need to be injected into the target process // for the omelet shellcode to be able to recreate the original shellcode // (you can insert them as many times as you want, as long as each one is // inserted at least once). They are 64 bytes each: egg0 = "\x3B\xFF\x76\x08\x28\x33\xC9\x64\x8B\x71\x30\x8B ... \x57\x51\x57"; egg1 = "\x3B\xFE\x76\x08\x28\x8D\x7E\xEA\xB0\x81\x3C\xD3 ... \x24\x03\xCD"; egg2 = "\x3B\xFD\x76\x08\x28\x0F\xB7\x3C\x79\x8B\x4B\x1C ... \x47\xF1\x01"; egg3 = "\x3B\xFC\x76\x08\x28\xAB\xAB\x57\x54\x52\x52\x52 ... \x40\x40\x40";
You can now copy+paste the strings into your exploit. Make sure that the exploit injects each eggX string into the user-land address space at least once before your exploit executes the omelet shellcode. also make sure that the target process does not overwrite any of them before the omelet shellcode is finished executing. Your exploit should execute the code in the omelet_code string to make it search the eggs, recombine your shellcode and execute it.