Buffer Overflow attack on PCMan FTP Server 2.07 using the Metasploit Framework and Corelan Team’s Mona Script

(For a more basic Buffer Overflow example, go to my previous example by clicking here, to read sample exploit code please go to my github by clicking here)

Origin of concept

The concept of our exploit is based on Koby’s PCMan buffer overflow exploit with the ftp ‘GET’ command on Windows XP. The exploit and vulnerable application can be found here

https://www.exploit-db.com/exploits/38003/

Summary of Modifications made

In this report, we do not follow Koby’s exploit fully, but we do exploit the same vulnerability. It might be hard to grasp all the things we modified, so we will summarise it here.

  1. We have tested on 3 platforms, Windows XP, Windows 8.1 and Windows 10. All the exploits we found for PCMan were in either Windows XP(most) or Windows 7(few).
  2. We added Corelan Team’s mona script in Immunity Debugger of vulnerable machine to obtain ESP and EIP offset instead of through the Metasploit framework’s pattern_offset in attacker machine
  3. We tested the exploit using python code similar to that of koby’s, and also generated ruby code to use in conjunction with metasploit framework and its meterpreter
  4. We used different shellcode, and these shellcode were generated from metasploit.
  5. Instead of ‘GET’, we also generated exploits that used different ftp methods such as ‘LS’,’ABOR’,’MDIR’,’MKDIR’. These gave us different offsets that we could use the same exploit to attack.
  6. We used ftp_pre_post to fuzz the PCMAN ftp server, and generated an exploit using mona.py. This means that we can send data without using FTP methods (e.g ‘GET’).
  7. We used mona suggest and mona findmsp for our ‘different’ exploit. This means that we used different tools to build our exploit as compared to koby.

Machines and OS

Attacker machine: Kali Linux 2.0
Vulnerable machine: Windows XP SP3, Windows 8.1, Windows 10
Connection: Tested on D-link router connecting separate laptops and also VMware hosting multiple OS.

The Exploit

Finding a vulnerability

Koby used metasploit framework’s auxiliary ftp fuzzer module (ftp_pre_post). The PCMan server crashes here.

Blogpost.png

 

Fig 1.1 MSF’s auxiliary ftp_pre_post fuzzer

In fact, we can already go to the vulnerable machine to build an exploit as the fuzzer sends data with a pattern where we can set find an offset with.

However, we can try writing our own python code to send 5000 ‘A’s over to see what our code can overwrite.

5000A

 

Fig 1.2 This is how we connect and send data using python sockets.

immunitydebugger
Fig 1.3 Immunity Debugger CPU Dashboard

We can see the EIP was overwritten here.

Instead of sending 5000 ‘A’ characters, we use msf’s tool, pattern_create.rb to generate a long buffer string so that we can find out where exactly is the EIP overwritten.

Finding the offset

offset

 

Fig 1.4 Immunity Debugger Register view (Pattern)

As we can see from the image above, 0012EDB8 is where ESP is pointing at this point in time. The program is stuck because the EIP address is overwritten by the pattern we generated. At this point in time, we would want to overwrite the EIP with an address that points to a jmp esp instruction. So the Immunity Debugger is very useful at this point. We can do one of the following

  1. Go back to Kali Linux to use msf to find out the offset by feeding the “address” at EIP, “396F4338” to rb. This is what Koby did in the original exploit.
  2. We can use the mona script by Corelan.be to find out the offset value. I personally prefer this because I get much more information. This is done by using “!mona findmsp” in the command line of Immunity Debugger.

I will do it the second way. First, I set a working folder for the mona.py script. Then findmsp.

>!mona config –set workingfolder c:\pclog\%p

>!mona findmsp

Findmsp produces a large text file as it walks through the stack, but the most important part lies here.

findmsp

Fig 1.5 Corelan Team’s Mona script “findmsp” output

From this, we can deduce two important things.

  1. EIP lies at offset 2006
  2. ESP lies at offset 2014

The reason these two are important is because we will overwrite EIP after 2006 characters, and then ESP after 2014 characters.

Building our Exploit

Hence our exploit code should look something like this in python.

exploit

Fig 1.6 Python exploit code

We added some no-ops so that we can form a layer of “no-operations” till we start running our shellcode, which is within the payload. The payload will then surely lie after offset 2014. In this case, if we examine the stack, there is no need for 15 No-Ops. For most FTP methods tested, 4 No-Ops is adequate to position the shell code to start exactly at the address ESP is pointing to.

The original exploit by Koby uses this to produce the shellcode.

kobystyle

Fig 1.7 Payload generation via msf

This is extremely simple, and our team have decided to run it in a different way, using more of corelan.be’s mona script.

!mona suggest” allows us to run findmsp and create an example metasploit exploit.rb at the same time. We also did these in our attempt to exploit on platforms Windows 8.1 and Windows 10, which we will discuss in the later part of this report. The Corelan.be website does not give us a detailed way on how to do a network tcp exploit, so we did it by trial and error, according to how they did a file format exploit (similar to the file reading of abc taught in class).

When !mona suggest is run, an option window appears.

monasuggestwindow

Fig 1.8 Corelan Team’s Mona script “suggest” will prompt this pop-up in Immunity Debugger

We choose tcp because we are exploiting through ftp. We then enter a port number, which can be changed later in msf console when we build.

Once exploit.rb is created, we transfer the exploit.rb from the Vulnerable machine Windows XP to Kali Linux’s

usr/share/metasploit-framework/modules/exploits/windows folder.

Every time we make an edit to the template exploit, we will

Msf > reload_all

Msf> use exploit/windows/exploitwxp

Where msf is the metasploit framework console.

We then go on to edit the exploit.

blankexploit

Fig 1.9 MSF view, using ruby exploit created by mona‘s method “suggest”

We then set RHOST to be 192.168.153.130 (Address on the vulnerable windows XP machine).

We also set RPORT to 21, because it is the port exposed for ftp.

Configuring our exploit

When we run, it does not seem to work. We need to make more edits. There are three main reasons why the exploit doesn’t work. These were tested through our own testing, and not via any tutorial.

Configuration 1

  1. Our previous exploit tested by the ftp get method, after logging in. Mona did not know that and only created the exploit based on its own knowledge of the stack and offset. So the generated exploit looks like this.

step1

Fig 1.10.1 Ruby code connecting to server without logging in

In order to solve this, we had to add some extra ruby code.

step1.5.PNG

Fig 1.10.2 Ruby code connecting to server without logging in

 

 

 

Configuration 2

  1. The payload might contain bad characters such as null bytes.

step2

Fig 1.11.1 Ruby code generating payload with bad characters present

 

In order to solve this, we use the bad characters declared in the successful koby exploit. Null bytes and bad characters will cause the exploit to fail as a proper full buffer string cannot be sent over at one go. This will be discussed more in part 3.

step3

Fig 1.11.2 Ruby code generating payload with bad characters present

Configuration 3

  1. Upon opening the exploit.rb file, we find that the jmp esp instruction was already chosen for us, to be

step4

Fig 1.11.1 Ruby code with a jmp esp instruction address starting with a null byte

By default, !mona suggest uses the very first jmp esp instruction found within the app. This is not what we want. In fact, we want to get an address that does not contain any null bytes. In this situation, the program crashes and immunity Debugger shows such a message.

step5 errormsg

Fig 1.11.2 Error message in Immunity Debugger

We will get to see a different effect in Windows 8 and 10 when they face such an address. Hence, from this we also learn that Windows sets a very good protection mechanism just by having the app’s memory address to start with a null byte. Writing to the stack for an attacker becomes much harder.

Therefore, we look for another jmp esp instruction. We do this with the understanding of koby’s exploit method, to use mona jmp –r esp. This returns possible jmp/call/push esp instructions that the machine is able to run from the PCMan program. This is fundamentally a windows XP vulnerability, and we will see the difference when compared to windows 8 and 10 later.

findjmpesp

Fig 1.11.3 Output of mona’s jmp –r esp on Windows XP SP3

Do note that the PCMan app can access system instructions outside of itself.

Here we choose a jmp esp instruction that does not start with a null byte. It does not matter which we choose, as all are accessible, and EIP merely calls a jmp esp and then starts to run the instructions stored in ESP.

newjmpesp

Fig 1.11.4 Fig 1.11.1 Ruby code with a jmp esp instruction address from a dll outside of PCMAN

Exploit success

Essentially Upon running

meterpreter

Fig1.12 The directory is created. Meterpreter can also be used for executing other dangerous shellcode

Using other Shellcode

We used the msf framework to generate a payload to replace the reverse tcp payload (If we do not want to use meterpreter). This time, to generate a calculator on the ftp server machine’s side.

calcpayload

Fig 1.13 Generating other payload

We replace the payload in our exploit with this, and the calculator opens on the Windows XP machine. We have also tried it with opening a message box. Basically shellcode in the windows payload from metasploit work. Here are a few snapshots

calc

Fig 1.14 Opening a calculator on the vulnerable machine

customgreeting

Fig 1.15 Initiating a popup message on vulnerable machine

Running in Windows 8 and 10

EIP is an instruction pointer. If we overwrite EIP with an instruction, the program will run that instruction. If we overwrite EIP with an address that points to a Jmp esp instruction, the jmp esp instruction will be called and it will start executing whichever instruction is seen at ESP.

This is an image when !mona jmp-r esp is run.

find810

Fig 2.1 Output of mona’s jmp –r esp in Windows 8 and 10

We can notice the big difference between the possible jmp/call/push esp commands as compared to Windows XP (in Fig 1.11.3). PCMan seems to be unable to access instructions outside of itself.

For Windows 8 and 10, jmp esp instructions lie at addresses starting with \x00. Which would mean the strings will automatically terminate upon entry of this null byte into the ftp instruction, be it ‘GET’ or ‘RENAME’ etc. Using jmp esp instructions that started with \x00 in windows XP also failed the exploit. Attempts to set the EIP to random addresses found in the disassembler also met with INT3 commands which caused the program to break or some random non-existent address or unexecutable command. The shellcode will also not be able to be reached.

An example of INT3 is as such

int3

Fig 2.2 Program breaking at INT3 command

Basically the idea is that if I want to send a payload after the EIP overwrite, the address should not have null bytes. Because of little Endian, the last character sent will be a null byte if the address starts with null. The string will be terminated before the payload. We can only allow null bytes in addresses if we insert the shellcode before overwriting EIP with an address that startsnull. This explanation was obtained from the link specified below.

https://www.corelan.be/index.php/2009/07/19/exploit-writing-tutorial-part-1-stack-based-overflows/

The images below show what happens when we declare badchars in our exploit, so that badchars will not be added. Bad chars include null byte as mentioned above. As we can see, even though we added badchars to be excluded from our shellcode, the strings still break up and are not able to send fully. It does not even crash the program.

beforebadchars

Fig 2.3.1 Before adding BADCHARS

afterbadchars

Fig 2.3.1 After adding BADCHARS

Hence no matter what, if there are null bytes or bad characters in the JMP ESP instruction address, we will not be able to do it. Therefore since !mona jmp –r esp is unable to find us such an address, we look at all the executable modules that PCMan uses. This can be done in the immunity debugger through

>View>Executable Modules

Then we proceeded to find JMP ESP instructions in those executable modules. Below is a picture of what we found.

findindebugger

Fig 2.4 Finding the JMP ESP instruction through attaching executable modules

Therefore we used this address, and we could do a jmp esp at EIP. This address 75F913E7 will then be used to overwrite EIP, and the exploit will now work on Windows 8.1 and 10.

Defense mechanism

 

With our futile attempts to edit the buffer size, we were not able to patch the program. However we chanced upon a possible fix. We noticed that in an earlier version of the FTP server, no amount of fuzzing would cause a buffer overflow. We read the server config file, which was largely different from the one in 2.07.

1vs2

Fig 3.1 Comparison between PCMan 1.0b (left) and PCMan 2.07 (right) Server.ini file

We therefore replaced 2.07’s server config file with the old one, and changed StartupWithGUI = 1 (true) and removed ScreenMaxLine. This was all trial and error, in a desperate attempt to find a patch.

altered

Fig 3.2 Altered PCMan 2.07 Server.ini file

avg

Fig 3.3 AVG prompts breach upon “nc 10.124.3.236 4444” entry from Kali Linux

However, this was not consistent and we could not identify the reason AVG could detect it, because no known attack signatures were indicated on the AVG prompt. This could be just due to luck. Therefore, the best way we could do is to not allow anonymous logins. Other ways we were not able to try was to add stack canaries, increase buffer size allocated (changing buffer size in Server.ini did not help) or disallow executable stack.

Conclusion

Through this project/tutorial, we have learnt how to use assembly instructions such as JMP ESP to redirect the flow of the vulnerable program, and execute our shellcode. This assembly instruction could lie in one of the executable system modules (such as SHELL32.dll). We also learnt how to make use of a powerful debugging tool such as the Immunity debugger, and run custom python scripts(such as the mona script by Corelan team) to reach our end objective. We also saw how to detect and remove bad characters that will hamper our plans of attacking the vulnerable machine.  We also noticed how different OSes might protect their users from vulnerable programs, such “startnull” addresses, and hiding system modules from attackers. However, if the vulnerable program configures itself to use lots of system modules, the onus is on the vulnerable program to protect itself from attackers by restrict the calling of modules or instructions that lie outside the program itself.

Do leave a comment for any clarification or feedback!

Leave a comment