This blog series has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:
Student ID: SLAE-877
To get the code provided in this exercise:
% git clone https://github.com/droberson/SLAE.git
The code will be within the Assignment-3 directory.
What is an Egg Hunter?
Egg hunter shellcodes are one example of a “staged” shellcode. Often, there will be limited buffer to work with, so staged shellcodes will have a smaller portion that gets executed first, then somehow loads a bigger code that wasn’t an original part of the exploit.
A great example of staged payloads is Metasploit’s Meterpreter. Meterpreter is a fairly robust set of features that do everything from provide normal shell interaction to taking screenshots of a desktop remotely. This would be very difficult if not impossible to implement in limited buffers available for most exploits, so a small stager is executed first which receives the additional components of Meterpreter via other means.
Egg hunters are a simple example of this multi-staged concept. A small code stub is executed which searches memory for a token (egg). The egg marks the address of the beginning of the second stage of the payload.
I opted for the simplest form of egg hunter I could find for demonstration purposes. First, I wrote a shellcode that simply printed a message to stdout rather than spawning a shell. This can be trivially changed to any shell code your heart desires, but I opted for the write() shellcode just to make testing and development easy. I don’t need to spawn a shell to demonstrate that this works.
BITS 32 ;; egg.. 0x424a424a inc edx dec edx inc edx dec edx ;; write "hi there" to stdout xor eax, eax xor ebx, ebx xor ecx, ecx xor edx, edx add eax, 4 ; write() inc ebx ; stdout push byte 0x0a ; newline push 0x65726568 push 0x74206968 mov ecx, esp ; address for "hi there\n" add edx, 9 ; strlen("hi there\n") == 9 int 0x80 ;; exit(0) xor eax, eax inc eax dec ebx ; ebx was still '1' for stdout, decrease for '0' int 0x80
I didn’t comment this as heavily as previous examples, because I feel it is straightforward enough. I added the exit() call to make the program exit cleanly rather than segfaulting.
The egg I chose shouldn’t alter the program’s flow in most cases. This can be any 4 byte combination as long as it executes and doesn’t crash the program. More advanced egg hunters can recognize these strings and skip past them. This basic egg hunter I wrote actually executes the egg along with the second stage.
Next, I write the actual egg hunter. This ended up being only 12 bytes, which is pretty small for a shellcode.
BITS 32 ; If the egg is changed here, it must be changed in the shellcode as well mov ebx, 0x424a424a ; EGG: inc edx ; dec edx ; inc edx ; dec edx loop: inc eax ; increase memory address by 1 byte cmp DWORD [eax], ebx ; is this our egg? jne loop ; nope, continue searching jmp eax ; egg found, jump to it
This simple program just looks for 0x424a424a (our egg), and redirects execution flow to the point in memory that it was located.
Tying it all together
Using the shellcode written above and test.c, I pieced together this proof of concept:
Running this code executes the write(stdout, “hi there\n”, 9) shellcode:
% ./egghunter Egg hunter length: 12 Shellcode length: 41 hi there