By Sameera GP - Dec 10,2018
A buffer overflow takes place when more data is put into a fixed-length buffer than the buffer can handle. The extra information, which has to go somewhere, can overflow into adjacent memory space, corrupting or overwriting the data held in that space.
Practical demonstration of Buffer Overflow
• Windows Machine(Debugging Machine)
• Kali Machine(Attacking Machine)
• Immunity Debugger(Debugging tool)
• Brain Pan VM (http://vulnhub.com/entry/brainpan_1,51/)
Setting up Immunity Debugger
I’ll use Windows Media Player as an example program to introduce Immunity Debugger. If you want to follow along, open Windows Media Player and Immunity Debugger. In Immunity, click File –> Attach and select the name of the application/process (in my example, wmplayer). Note: you can also launch WMP directly from Immunity by clicking File –> Open and selecting the executable.
When application is loaded, immunity debugger opens default window, CPU view. As it can be seen on the picture, CPU screen is divided in four parts: CPU Instructions(1), Registers(2), Dump(3), Stack(4).
As you can see, the CPU window is broken up into four panes depicting the following information:
• The CPU Instructions – displays the memory address, opcode and assembly instructions, additional comments, function names and other information related to the CPU instructions
• The Registers – displays the contents of the general purpose registers, instruction pointer, and flags associated with the current state of the application.
• The Stack – shows the contents of the current stack
• The Memory Dump – shows the contents of the application’s memory
Assembly Code Background:
Assembly language is considered a low level language that is a human readable version of a computer’s architecture instruction set.
Normally code is written in a higher level programming language (C/C++) then it is compiled into machine code, which is just hex bytes that the CPU executes. These hex bytes can be represented by assembly code. When we start to look at Brainpan in Immunity debugger we will see both the assembly instructions and raw hex values.
When you hear “shellcode” these are raw machine instructions that are executed directly by the CPU without having to go through this compilation process. With this exploit example we will be demonstrating a stack-based buffer overflow. This allows us to take advantage of CPU registers to exploit the vulnerability. Registers are small amounts of memory available as part of the CPU.
Below is a quick overview of some common CPU registers
“Program Counter” EIP – Register that contains the memory address of the next instruction to be executed by the program. EIP tells the CPU what to do next.
Stack Pointer: ESP
Register pointing to the top of the stack at any time
Base Pointer: EBP
Stays consistent throughout a function so that it can be used as a placeholder to keep track of local variables and parameters.
“accumulator” normally used for arithmetic operations
“counter” normally used to hold a loop index
Used by memory transfer instructions
Points to last item on the stack
First things first, I fire off our 'netdiscover' tool to determine the IP address of the brainpan VM:
We can see our brainpan IP has the IP address of 192.168.32.141. We can now launch nmap at this host to determine what ports are currently open and their services. We do that with the following command:
Naturally, I want to check out the service running on port 9999 so we'll do that now with our trusty netcat utility:
As we have already pre-determined from the nmap output, this is indeed a custom service which means we may be able to exploit it later. For now, let’s go do some investigation on the webserver...
Browsing to port http://192.168.32.141:10000/ really doesn't give us too much information, so we decide to fire up DirBuster to see if it can dig up some hidden files or directories for us to play with:
Aha! We have a /bin/ directory. After browsing to this directory we quickly notice the 'brainpan.exe' file. The next step is to download this file to our local machine and analyse what is going on. We will post some command output below and discuss what's going on:
We can see that this is a legitimate Win32 application (running on Linux via WINE). We can also see some of the popular C programming functions being used.
Naturally, we move this file over to a Windows XP SP3 machine to do some further testing with Immunity Debugger. What do we know so far? We know this is a service that runs on port 9999, it's a win32 executable file, and it's most likely vulnerable to a buffer overflow due to the use of the 'strcpy' C programming function.
Let's go ahead and start writing a simple fuzzer for this program to see if we can get it to crash. The following python script will connect to the service and send 1000 "A"s to the service:
Once the program is attached, hit the play button or press F9 to continue normal execution of the program. Now we are ready to launch our exploit:
As expected, we see nothing on our attacking box... however, let's see what happened in Immunity Debugger on our WinXP machine:
Awesome! We have successfully overwritten the instruction pointer(EIP) with "A"s (0x41). For the newbies out there following along, this is an ideal situation as we can now control execution of this application from this point forward (assuming we can have suitable space for our shellcode and can reliably call it ;]).
Our next step is to determine exactly how many bytes we can fill into this buffer before EIP is overwritten, that way we can put whatever value we want into EIP. For this, we use following link to generate cyclic pattern.https://projects.jason-rush.com/tools/buffer-overflow-eip-offset-string-generator/
We will take this pattern and replace the 1000 "A"s in our exploit with this entire pattern, so our exploit now looks like:
Going back to our WinXP test machine, we close Immunity Debugger and brainpan.exe and repeat the process of attaching brainpan.exe to Immunity Debugger once again so we can launch this exploit against it yet again. Once this has been completed and we re-launch our updated exploit we will get the following from our registers in Immunity Debugger:
Now we copy the value that has overwritten EIP (35724134) and go back to our attacking machine and load it into EIP value, like so:
We know that it only takes 524 bytes to overwrite EIP with any value we want. Lets go ahead and edit our exploit to test this offset value and to determine if we have enough room for shellcode:
What this code will do is send 524 A's(x41), 4 B's(x42) and remaining C's(x43). We do this to determine if we are overwriting EIP with the B's and to see if we have room for our shellcode with the 1000 C's. Let's see what happens in Immunity Debugger after we run our exploit again:
We can see that EIP is now successfully overwritten by Bs and ESP now contains our Cs(where our shellcode will be later).
Since ESP points directly at our shellcode, we can search for a jmp/call esp within the binary's assembler. The reason we do this is so that we replace the B's with the address of jmp/call esp so that the instruction pointer will execute the jmp/call esp instruction. This will then direct the execution flow to our shellcode which resides in ESP. If you don't understand this, please refer to the link at the beginning of this write-up.
So lets go looking for our jmp/call esp within the binary file:
For That, go to immumity debugger, press “e” to see the executive files in the machine.select the vulnerable application.
Search for “jmp esp” instruction in the brainpan.exe file and note it down.
This jmp esp will definitely suffice for our exploit needs. All that is left is to generate our shellcode and then update our exploit with the necessary information. Let's generate our reverse shell shellcode now with msfpayload and msfencode
Now we will fix our exploit so that it looks like so:
[junk-----524 bytes]+[EIP - jmp esp]+ nops +[shellcode] +[rest junk]
We will now run our exploit against our test machine to see if we get a reverse shell on our attacking machine. Don't forget to run 'nc -lvvp 443' on your attacking machine before running the exploit:
Awesome! We have a reverse shell on our WinXP test machine! Now we need to generate a new shellcode for linux and run it against the brainpan machine. I will leave it to the reader as an exercise on how to figure that part out for themselves, however here is the output from my new exploit after doing everything I just mentioned above:
Now we have a reverse shell on the brainpan VM. This is only the tip of the iceberg as we now have to elevate privileges. Typically what I would do on a pen test is check to see what kernel is running and if the machine is x86 or x86_64. We can see that this is a fully updated and current kernel: