Egg Hunter Shellcode — Security Tube Linux Assembly Expert 32bit - Exercise 3
In the last post we saw how do we go about crafting a reverse shell TCP shellcode. In this post we will look into the egg hunter shellcode crafting. This is exciting in a sense that it touches on a few fundamental OS concepts such as virtual memory address space and process integrity.
To understand the concept of an egg hunter, please have a look at this seminal resource — http://www.hick.org/code/skape/papers/egghunt-shellcode.pdf
In short, an egg-hunter is a piece of code(shellcode) that scavenges the VMA(Virtual Memory Address) space of a process to find the egg and then do the necessary action. In our case this action would be to execute the payload following the egg in memory. This payload could be anything arbitrary and is open to your creativity. Now you might ask, why do we need to take this path of exploitation? Well, the simplest reason is space constraints(where the controlled overflow-buffer cannot fit in, all-of-our typical payload) and the second reason is staging (breaking apart the payload into stages, where one stage would be injected and will be waiting passively for the second stage, typically the hunter code that would search for this previously injected egg in the process address space and execute it). Isn’t this exciting? We have a number of possibilities now.
Now for the details of the implementations. Almost all modern multi-user operating systems do not allow user code to access parts of the memory address space arbitrarily. This is the fundamental process address space integrity that the OS has to uphold. Each process has a huge VMA space that is dependent on the architecture. For simplicity an x86-32bit processor has a process address space of 2^³² i.e roughly 4GB. But only parts of this address space is mapped to real/physical memory/backing store. So large chunks of the address space has holes/gaps, so to speak. If a process tries to access this space we get the infamous SIGSEGV(Segmentation error), meaning the OS kills the process by delivering this SIGSEGV signal. So how can we scan the entire process address space safely to find the egg without getting bitten by the OS? Turns out we can abuse a couple of system calls such that the OS will not kill the offending process(the process that invoked the system calls). We go on scanning page by page where each page is of PAGE_SIZE(viz. 4096 bytes) and is configured when the kernel is built. A page in this context is the smallest granular unit that the OS uses when allocating/manipulating memory space for a process.
According to Skape’s paper he has identified 2 system calls, namely:
int access(const char *pathname, int mode);
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
Please refer to the man pages as to what is the purpose of these system calls. In short, we can pass the address of the range of memory space we want to scan and these system calls do not SIGSEGV, they just throw an EFAULT error that — you guessed it — will *not* kill the process and let us handle the error and keep going on scanning the next memory block — brute scan basically.
I am going to use the access() syscall. Note: I did try to implement it with the other syscall, sigaction() but ended up preferring the former more — just plain choice — nothing else.
Algorithm:
- Setup the syscall viz. $eax — the syscall number, $ebx, $ecx arguments.
- Invoke the access() syscall and check for EFAULT errors.
- If an EFAULT, then the address space is not mapped/not accessible, move to the next PAGE of memory, caveat is, if the address lies within the page boundary then it means the entire page is not accessible. The way its been checked is by validating 4 bytes ahead, such that we can safely catch the errors if the address is falling beyond the page boundary and if not check the ‘n’ and ‘n+4’ addresses for the egg tag. Remember that the egg tag is 8 bytes long, so if the ‘n+4’ address is invalidated then the ‘n’ address definitely does not have the egg tag, right? So its when we jump to the next page.
- If the ’n’ address has the 4 bytes of the egg and the ‘n+4’ address has the remaining 4 bytes of the eggs then we have located the egg-tag, else we need to increment the ’n’ to ‘n+1’ and continue. This holds true as long as the above (3) constraint is satisfied.
- Jump to the payload once we have located the egg-tag/egg-code.
Note: I am using the egg-code and egg-tag interchangeably. They both mean the same semantically, with the only difference being an egg-code is a marker that is an executable code in itself. Ex: ‘\x90\x90\x50\x50’ which is assembly ‘nop’(‘\x90’) instruction and ‘push eax’(‘\x50’) instruction respectively, whereas an egg-tag can be any arbitrary 8 bytes code. Ex: ‘\x49\x53\x48\x55\x49\x53\x48\x55’.
Without further ado, lets get into the nuts and bolts.
If you see the above code its hardly deviated from Skape’s original implementation, simply because its one of the most optimal implementation of the technique and if you try a little harder on your own to optimize the code size you would in fact end up with something very similar like Skape’s code.
If you pay close attention, we can see that the payload is of a port binding shellcode with the ip/port being 127.0.0.1/31337 as illustrated in the ‘netstat’ command. See if you can recognize the 8-bytes of egg-code injected in the payload above, ’90 50 90 50 90 50 90 50'. You can generate the payload with whatever tool you want, even using ‘msfvenom’ infact and prepend the egg-code/tag.
If you like doing stuff on the cmdline like me you can do something like this to inject the egg-code with a simple echo/cat combination. Below are examples of two payloads, one is a port binding shellcode and the other is a reverse TCP shellcode.
Split into 2 screen grabs for clarity.
Please check the following github repo for the entire set of source files and helper scripts to generate and test the shellcode.
https://github.com/vikrant-navalgund/SLAE32
This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification.
Student ID: SLAE -1100