Exploiting Buffer Overflow
3. Exploiting Buffer Overflows
So far we have seen how to find a buffer overflow and how it works. So how can we exploit this vulnerability? Since we already know how the good password program works, we will try to exploit it. The purpose will be to craft a payload that will allow us to run calc.exe. We already know the size of the input that allows us to overwrite the return address. When using the following input, we overwrite EIP with ABCD: AAAAAAAAAAAAAAAAAAAAAAABCD
As you can see in the following screenshot, when we use the previous input and the program crashes, ESP points to the exact location after the return address (0028FE90).
So the stack looks like the following:
At this point, EIP points to 44434241 (ABCD), while ESP points to OTHER. In order to execute our shellcode, we will have to overwrite the EIP (ABCD) with the address of our shellcode.
Since ESP points to the next address after the return address location in memory (OTHER), we can place the shellcode starting from that location! Basically, we need to fill the first 22 bytes (local vars + EBP), with junk data (NOP’s), rewrite the EIP and then insert the shell code.
3.1 Finding the Right Offset
In the previous example, it was easy to find to right offset where to overwrite the EIP address. In real exploitation process, the amount of characters needed in order to crash an application may vary in size.
We can check by using various searching methods (e.g. binary search), or we can use some tools.
Tools that may be in use:
pattern_create and pattern_offset (Ruby)
The purpose of these scripts are really simple.
pattern_create receives a number and outputs a pattern that is as long as the input.
If we feed this output to our vulnerable target application, there will be an error message that tells us where the error takes place (which is usually the value of EIP register being overwritten)
pattern_offset receives a memory address and outputs how much offset is necessary to overwrite that address.
3.2 Overwriting the EIP
Now that know the correct size of our payload, we have to overwrite the EIP with a value. Remember that the value we overwrite will be used by the RET instruction to return.
We want to return to our shellcode so that it gets executed.
At this point, our shellcode is stored at the memory address pointed by ESP, therefore, returning to our shellcode means jumping to that address. The problem is that the address in the stack changes dynamically, so we cannot use it to build the exploit.
What we can do is find a JMP ESP (or CALL ESP) instruction that is in a fixed location of memory.
This way when the program returns, instead of ABCD, it will execute a JMP ESP (or CALL ESP), and it will automatically jump to the area where out shellcode is stored.
In environment where ASLR is not enabled, we know that kernel32.dll functions are located at fixed addresses in memory; this allows us to perform a JMP ESP or a CALL ESP to the process address space, a line in kernel32.dll.
(kernel32.dll is the 32-bit dynamic link library found in the Windows operating system kernel. It handles memory management, input/output operations, and interrupts. When Windows boots up, kernel32.dll is loaded into a protected memory space so other applications do not take that space over. Other .dll s may also help, not only this one).
We can safely jump to this line and back from the kernel32 to the address in ESP (that holds the first line of our shell code).
There are different tools and techniques that we can use to detect the address of a CALL/JMP ESP. One of them simply disassemble the .dll and then search for the instruction.
To disassemble a .dll you can load it into Immunity Debugger (or IDA) an then search for one of two commands: CALL ESP or JMP ESP.
Another tool that we can use to find CALL ESP and JMP ESP instructions is findjmp2, which receives the target .dll and the registry name we want to search
You can also use Mona to do this.
Example: You can see the goodpwd.exe. The variable command is conmpsed as follows: Junk bytes + EIP + shellcode Also, notice that at the beginning of t he shellcode we added some NOP s (\x90). Therefore, once the JMP ESP is executed, the first instruction that will be executed is a NOP. The program will then continue to slide down the NOPs and execute the actual shellcode.
Program flow:
| | . . . | | |-|------------------------------| | |(2)| junk |<-(1) We start injecting here| |I| junk | | |I| . . . | | |I| junk | | |I| junk | | |I| junk (EBP was here) | | |I-->| \x3B\x7D\x26\x77 |(3)-> (kernelbase.dll) 0x77267D3B; JMP ESP| |ESP->| shellcode (\x90\x90\x90\x90) |<--I(4) EIP will go here, because (3)| | | shellcode (\x90\x90\x90\x90) | | | | shellcode (...) | | |
Note: Use Windows XP to simulate buffer overflow without DEP and ASLR protection.
Last updated