Your First Buffer Overflow

Schuyler Dorsey
7 min readAug 17, 2017

--

Let us take a look at a simple buffer overflow exploit. It is important for both the Red Team and the Blue Team to understand how buffer overflow exploits work. The Red Team needs to understand how they work so they understand how their attack vectors work and most importantly, are not labeled as ‘script kiddies’.

The Blue Team needs to understand the buffer overflow so they understand their enemy, can better understand how to protect against them, and can understand the very real threat of this attack vector.

TL;DR this software does not properly validate input and because of this, we will gain full code execution on the remote machine.. leading to full administrative control.

For this exploit, we will use Kali Linux as our attacker VM and Windows XP as our victim VM. We will use Windows XP as it lacks many of the current mitigations such as ASLR. ASLR can certainly be bypassed but we do not want to worry about it for our first buffer overflow; this will allow us to better understand and study the process.

Our first buffer overflow will be against Ability FTP. Ability FTP has a known overrun vulnerability in the STOR and APPE commands.

There are also several pre-made exploits available online at places like Exploit-DB.

Exploit-DB has an added bonus of also supplying a download link to the vulnerable version of the application. So we can download Ability 2.34 from the Exploit-DB page here.

So download Ability 2.34 and install it in your Windows XP VM. Since the vulnerability is against STOR and APPE and these commands can only be used after authenticating to the server, we should also create a dummy account. For ease, we can create a user account with the username “ftp” and the password “ftp”.

With Ability ready, let us create our Python skeleton exploit. This first script will connect to the FTP server, authenticate as FTP and then send a buffer of 1500 bytes (1500 A’s here) via the APPE command. Finding the right number of bytes to send a command is another process known as fuzzing but we will skip that step for this post.

Our target VM is located at 10.10.10.73.

After we run our script against the VM, we get a crash.

Now let us crash it again but with a debugger attached. So install Immunity Debugger if you do not already have it. After you install it, reopen Ability server and then attach Immunity to it. To attach it, go to File > Attach.

Then select Ability.

After you attach it, it should appear as follows. The top-right window shows your registers and the bottom-right shows the stack.

Hit the play button in the toolbar to resume execution of the application. Now let us send the same Python script again and see how it looks in Immunity.

As you can see, we have over-written quite a bit with our buffer of A’s. The main two to observe are EIP and ESP. EIP points to the next instruction on the stack to be executed. And we can see we have plenty of our buffer located where ESP points. What if we could control EIP and have it jump to where ESP points as we control that buffer?

Let us adjust our Python script. Before we can attempt to change where EIP points, we must first understand which 4 bytes in our 1500 byte buffer are overwriting that location. To do this, we can use the Metasploit Framework to generate a 1500 byte cyclical pattern.

Now we will take this 1500 byte pattern and use it in a new Python script.

Now use Immunity to restart Ability. You can go to Debug > restart. Then click Play and it will resume application flow once again. Send the new Python script and see how it crashes in Immunity.

As you can see, we have once again overwritten where EIP points; it is now 33674232. We can plug this string back into MSF to determine where in the 1500 byte pattern this string lies.

The string is located after 968 bytes in the pattern. With this information, we can edit out Python skeleton to verify. We can send 968 A’s, 4 B’s and 528 C’s. Remember to always keep your total buffer length the same as different buffer lengths can cause the crash to behave differently.

Let’s send this script after Ability is ready; as you will see, we have verified we control where EIP points. EIP will be pointing to our 4 B’s.

Now we need to change our B’s to something more useful. We need a command which will jump to an area we control; in this case, we control where ESP points so we should JMP to ESP. In Immunity, we can click the E to show the modules loaded at crash time. For this example, we will open User32.dll and search for JMP ESP. We find a match!

Copy the address for later re-use. Restart the program via Immunity; go back to JMP ESP address and select it. We can set a breakpoint on it by pressing F2 with it highlighted. It will stop program execution once the address is called. This allows us to ensure we have hit our breakpoint.

We send it again and it crashes. But as we can see in Immunity at the bottom of the window, we hit our breakpoint!

Now we need to adjust our buffer to send useful shellcode to give us a shell. As you can see in the stack at crash, there is approximately 16 bytes between where EIP points and where ESP starts. There are a couple ways to calculate where to place the shellcode. For this first post though, we will just use NOPS.

*NOTE* NOPS are by far not the best way to do this. Many AV and IDS systems detect NOP sleds. A more precise method would be to calculate the number of bytes and adjust our script accordingly.

But to make this easy, we will use 50 NOPS (\x90). We also need to generate meaningful shellcode. Once again, we can turn to the MSF. Using msfpayload and msfencode, we can generate shellcode which connects back to us on port 443 and gives us shell access. In this command, we specify -b to tell msfencode what the ‘bad bytes’ are so it will avoid using these bytes in the resulting shellcode.

There is a specifc process to find bad bytes but that is out of scope of this module. For now, we will just use some universal bad codes which should always be avoided, \x00 and \xff.

With this shellcode and knowing what we need to do as far as NOPS, we can create our final Python script.

Before we send it, we need to setup a listener on our Kali machine. We can setup a simple listener via Netcat with the command:

nc -lvp 443

Back on the Windows XP vm, close Immunity. Re-open just Ability and start the FTP server. On your Kali machine, with Netcat listening, run the Python script. Within seconds, you will receive your remote shell under the same user context the FTP server was running. In this case, the FTP server was running under the admin account which is a local administrator; we have full administrative control of the XP vm.

This is just the start of the rabbit hole when it comes to buffer overflow exploits. Over time, we will explore several other exploits and strategies.

--

--