PCMan BOFing

Picture this… you are having a crack at a CTF comp, and you have managed to smash most of the miscellaneous, web, forensic, and trivia challenges. The scoreboard shows that you have had a pretty good run, but then.. one by one other teams start to leap frog you on the ladder! What is going on!?! Opening up the CTF challenges tab it’s pretty obvious why your points accumulation has stopped dead… the dreaded Binary challenges!

Binary exploitation is a weak area for me, so I have decided to randomly choose a vulnerability from exploit-db and have a bit of a dabble in this space.. at least gain enough knowledge to be a little dangerous. I am writing this post as a reference for me to be able to look back on, but if you are keen to learn a bit of binary exploitation too then hopefully these write-ups will be helpful for you.

First up… I am going to have a crack at an application called PCMan FTP Server 2.0.7 (server). This application has a number of known buffer overflow (BOF) vulnerabilities (CVE-2013-4730), and my goal is to see if I can create my own exploit without referring to anyone else’s work.

The following is what I will be using for this exercise:

  • The vulnerable PCMan FTP Server 2.0.7. Grab it from exploit-db
  • Immunity Debugger which you can grab from here
  • The mona.py plug-in for Immunity. Grab it here
  • A windows box of some form. I will be using Windows 7 SP1 x64 (DEP disabled! <-- important)

Once you have followed the how to install and configure bouncing balls in the readme files, let’s rock and roll!

First things first… start the server.

pcman_init

The CVE entry for this application states that the USER command is vulnerable to a BOF, however almost all input for the server seems to be vulnerable to a BOF so I will concentrate on the PUT input method. Let’s start by creating a simple fuzzer to help us find roughly where the BOF occurs.

Next, open up the Immunity Debugger (immunity) and attach the running server process.

immunity_init_attach

Be sure to run the program in immunity by pressing F2 or pressing the ‘go’ arrow on the toolbar.

Now.. let’s kick off our fuzzer and see if the server buckles over.

BAM! Sending a buffer length of somewhere between 2000 and 2050 characters causes the application to crash. Let’s check out how our registers look in immunity.

registers_init

Nice. You can see that we have overwritten EIP with our buffer, so our exploit could possibly be a simple case of manipulating EIP and pointing it to an address which holds JMP ESP or similar.

Let’s start building our exploit. First, we need to find the offset, which is the point where we can start to overwrite EIP. We know from our fuzzer that it is somewhere between 2000 and 2050 characters long, so let’s create a python script and send 2050 “A” (\x41 in hex) characters to our server….

… and execute it to make sure we can trigger the crash.

Voila!

pcman_crash_dialog

In order to find our offset, we will use the pattern_create.rb script to generate a pattern length of 2050 characters.

… and replace our buffer of “A” characters with the generated pattern.

Start up the server again, attach immunity to the process, and fire off our modified exploit. Let’s take a look at the registers now.

registers2

In order to find the offset where we have overwritten EIP, we can use the pattern_offset.rb script by feeding it the hex value stored in EIP when we crashed the server.

Great! Let’s test the offset by sending 2008 “A” characters as rubbish, and check if we can fill EIP with “B” (\x42 in hex) characters.

registers3

Now we are on a roll! As you can see, the value of EIP is our 4 “B” characters. So what does this mean? Well, if we can control the value of EIP, then we can control the execution flow of the program. Our goal now is simple, we need to tell the program to jump to a register which holds our shellcode. In this case, let’s see if we can find a useful jump to take us to ESP. We will call on mona’s help here to find any jmp esp results by executing !mona jmp -r ESP

mona_jmp_esp_limited

We can see in the results that we do have a jmp esp at 0x0043410d, and that this location is not protected by ASLR. However, we are looking at a BOF on user input, and the \x00 will be interpreted as a NULL character, ending our control of the program execution. There is a way we could use this address and perform a partial overwrite, but that is beyond my current knowledge and out of scope for this exercise. I will look into this at a later date and write another post based around EIP partial overwrites etc.

So for now, we need to find another instruction to jmp esp. Let’s instruct mona to look at all modules for jmp esp by executing !mona jmp -m * -r esp.

mona_jmp_esp

Now there are a lot to choose from! The downside of using any system modules in this case is that they are all protected by ASLR, which means that once we reboot the system or there is a significant change, the address value we choose will no longer exist. As stated above regarding EIP partial overwrites, this is outside of the scope of this write-up. Once I understand how to work with partial overwrites and how to bypass ASLR, I will write an follow-up to this post and share the knowledge.

So let’s pick the following location (yours will be a different address):

Before we go any further, a quick recap what we have so far.

  • The amount of rubbish we need to send in order to get to our offset
  • An address which we can use to force the program to jump to ESP

junk_eip_diagram

Next up, we need a payload for our exploit. Our missing pieces are a NOP sled (a handful of no operation codes (“\x90” in hex)) and some shellcode. But first, we need to find if there are any bad characters which we need to avoid in our shellcode. To do this, we will use mona once again by executing !mona bytearray -cpb '\x00' to generate a list of all characters. Note we ask mona to exclude the NULL (“\x00”) character as we already know this will break our execution.

bytearray_create

Now we will build our exploit, filling EIP with 4 “B” characters and placing the characters from the bytearray.txt file which mona generated into the variable which will hold our final shellcode.

Start up the server… attach immunity to the process… and then run the exploit. Now search for the first full address after our EIP, which is 0x0018F558 in my case, and this will be the address we use to help mona find bad characters which we cannot use in our final shellcode.

bytearray_address

Issue the following command in immunity to have mona test for bad characters….. !mona compare -f C:\mona_logs\PCManFTPD2\bytearray.bin -a 0x0018F558

bytearray_badaddress

… and as you can see, mona has determined that 0x0a is possibly a bad character which we should avoid. Remove this from our payload, and rinse and repeat the above steps until mona cannot locate any further bad characters.

bytearray_nobadaddress

Nice! Now that we know what characters to avoid in our shellcode, we can generate a payload, with the help of msfvenom, to create a sexy sexy reverse TCP shell.

Okay.. recap. We now have junk to get us to offset, an address to jump ESP, a NOP sled, and now a payload to deliver!

junk_eip_nop_payload_diagram

The next obvious step? Put it all together and build our exploit!

Now let’s set up a meterpreter listener for our reverse TCP connection, execute our exploit, and cross all of our bits in the hope of getting a shell!

GAME OVER!! A wild sexy sexy shell appears!

Moving forward I will write another post with the same server, but this time with DEP enabled. We will try to bypass ASLR and even have a crack at a partial EIP overwrite. But until then, I hope you enjoyed the writeup….

Tight lines and happy hacking!