Windows Exploitation - Beating the German
The program that I bring today took me longer that expected to crack down. It's my first attempt to really exploit a binary in windows; last time it was all about overwriting a variable. It's been a fairly daunting week but the relief made it worth. Instead of trying to spawn a remote shell or anything more sophisticated, we will try to run calc.exe as part of the PoC. The platform I have chosen this time is
Windows XP SP2
with DEP in his default settings (for essential Windows programs and services). For development purposes I used some well known tools:
OllyDbg,
masm,
and our old friend
Python
(version 2.6).
The vulnerability itself is a classic stack based buffer overflow where we will try to overwrite the return address and redirect execution to our buffer. The binary was compiled without any kind of mitigation measure like
/GS
and so on...The vulnerability is caused by the improper sanitization of user input and later feeding to libc's sprintf(). The program allocates a 1024 bytes long buffer in the stack and writes the first program argument (argv[1]) alongside some constant strings in there. After a small analysis in the debugger we notice that the distance from the beginning of the buffer up to the
ret
value of the function is 1036 bytes; If we discount the length of the constant string that the program includes (23 bytes), we effectively have 1013 bytes to fill.
At this point the solution looks pretty straightforward; overwrite the
ret
value with an address inside our buffer where we will place our shellcode. But unfortunately, our address space layout makes the stack fall within a range where the first byte is null (0x00XXXXXX) which remember effectively ends the copy process, hence we need to find a workaround. The most extended solution for this kind of situation is to simply find a piece of code somewhere else in memory which we can re-use in our exploit. For this matter, we will place a breakpoint in the debugger right at the
retn
instruction and analyze the situation. We will notice at this point that
esp
is pointing right to our
ret
value in the stack. We will take advantage of this and try to make execution continue after the
ret
value so we have a chance to place the shellcode after the
ret
value (e.g. in a higher memory address). For this purpose the combo "push esp, retn" looks great. In the memory dump of the debugger we look for this instruction sequence across the different modules loaded: in my particular case I picked
msvcrt.dll
which is the
Commom Runtime Library of the Microsoft Visual Studio.
In this exploit I will use the address
0x77c35459
in order to redirect flow to continue after executing program's retn instruction. At this point a critical issue arises, a typical windows shellcode that would launch a process like calc.exe takes roughly about 150 bytes and we simply don't have that much space. To overcome this we need to build a sort of launchpad or trampoline to redirect flow somewhere else where we can have enough space for our shellcode. What better place than the buffer we are overflowing itself? with its 1000+ byte length looks just right for the job in hand. To build this launchpad I used masm and created a little mock program that functionally does nothing but will provide us the right hex values to be inserted in our exploit. In my case I designed a 3-line asm sequence that looks as follows:
.text:0040100A mov eax, esp
.text:0040100C sub ax, 39Ch
.text:00401010 jmp eaxSince this sequence will be placed right after the
ret
value on the stack, all we do here is calculate the address of our shellcode based on the position of
esp.
At this point all that's left to build is the shellcode, which in my case I opted to pick from the
metasploit project
(How nice sharing is? :-)). This shellcode just pops up the windows calculator and closes the process that spawned it.
So let's recap, we have the buffer to fill, we have the ret value to
msvcrt.dll,
we have the launchpad to the shellcode and we have the shellcode. The structure of the call will be as follows:
Shellcode | Padding | ret2msvcrt | Trampoline.
Now using Python to create a script that will build the call to exploit our program is quite straightforward. You can download both the binary and my solution from
here.
I understand this exploit could be improved in several ways, most notably using a NOP sled instead of calculating the exact address of the shellcode, but anyway I hope you guys enjoyed it and keep adding NOPs!
P.S: A quick fun push by the masm guys. As shown in
this
picture they're not very flattered by the way some AV vendors behave with their product.