In my likely impossible challenge to ever understand one of Nico Waisman’s talks, I found corelanc0d3r’s site. Wow. Awesome tutorials on everything from direct EIP overwrites to ROP.
His first challenge is to exploit EasyRMtoMP3, some silly little utility that has a known stack buffer overflow when reading lines from .m3u files. His tutorial shows how to exploit it in Windows XP SP3, without ASLR and DEP and all that stuff in the way. I’ll document here the challenges I had to overcome in exploit this reliably in Vista SP2. I won’t rehash the vulnerability itself (he did a great job), but rather list the differences you need to make it work on a more current Windows OS for anyone who finds themselves following his tutorials like I did. In case you’re looking for new techniques, get ready for disappointment: there is absolutely nothing new or novel about any of this.
Step 1: Finding offsets from the start of the overflowed buffer to the saved EIP. Nothing different needs to be done here – the same Metasploit pattern-finding technique works on Vista. However, the output is different. My offset value is 26073 (base10).
Step 2a: Find a way to get to our shellcode. The same calc.exe shellcode is on the stack, but we can’t overwrite EIP with its address because it’s address is 0x000FF65C, emphasis on the 00. This is an unbounded string copy vulnerability, so we can’t have any NULLs in our payload. Without ASLR, this should still be easy. Our shellcode very conveniently lives right at ESP, so all we have to do is find a
JMP ESP instruction anywhere in any of the application’s DLL’s, just like Peter did in his tutorial. I anticipated that I wouldn’t have a problem with ASLR because there is no way this little utility’s author would have known to link the executables or DLL’s with the /dynamicbase flag, which is how you enable ASLR. I was right in my expectation about the author, but wrong in my expectation that I wouldn’t still be affected.
Running the program 3 times shows 3 different addresses for the MSRMCc_1 module, despite the fact that it’s not ASLR aware:
|001D0000||MSRMCc_1||C:Program FilesEasy RM to MP3 ConverterMSRMCcodec01.dll|
|003D0000||MSRMCc_1||C:Program FilesEasy RM to MP3 ConverterMSRMCcodec01.dll|
|001C0000||MSRMCc_1||C:Program FilesEasy RM to MP3 ConverterMSRMCcodec01.dll|
As I’m sure people smarter than me already know, this was because of DLL fixup/rebasing. All executable modules have a “preferred” address to live, but when there’s a collision with another existing module they can generally be adjusted (slightly). Because Windows has a ton of DLL’s involved in every process, and they’re randomly placed due to ASLR, there’s a decent chance application DLL’s will generate conflicts and therefore must be “fixed up” to nearby addresses.
So – are we forced to have an unreliable exploit? Nope! Turns out 1 of the application DLL’s can’t be rebased, and therefore must live at it’s preferred address. The output from the pvefinaddr plugin for Immunity Debugger shows us how we discovered that (click to see whole picture):
This is awesome. We now have a target: MSRMfilter03.dll. Now we just need to find our
Step 2b: Getting redirection to ESP. So now that we have our target DLL, the next step is to find the location inside the DLL of a
JMP ESP. The simple way to do that is to search for the bytes of the instruction in the DLL using OllyDbg/ImmDbg’s Search for->Binary string. You have to know what bytes to search for, though, and the easiest way to figure that out is to replace some random code in the DLL with the assembled instruction for
JMP ESP and then look at its contents. If you did that, you’d know the value we’re looking for is the byte sequence FF E4. Surprisingly, this DLL does not contain this byte sequence anywhere (even when looked at totally unaligned).
So, we improvise. For this exploit to work, at the end of the day, you just need some instructions that redirect the user to the address stored in ESP. Another set of instructions that would do that is
PUSH ESP; RET. The
PUSH ESP will copy the address of our shellcode (ESP) onto the top of the stack. Then, our RET instruction simply pops that address off of the top of the stack and transfers control to it. This byte sequence, 54 C3, is found many times in this DLL, and we pick one of the locations that doesn’t have a NULL in it: 0x1001B058. This technique and many others for figuring out “how the hell do I get to shellcode?” are talked about later in corelanc0d3r’s tutorial series.
Step 3: Fix our shellcode problem. So now we know where our shellcode lives and how we’re going to redirect to it. But, to my chagrin, the exploit still fails. The problem turned out to be some undocumented requirement by Metasploit’s calc.exe shellcode. In his exploit for this issue, the tutorial author used a NOP sled but never indicated why. Everything in our exploit is precise; there is no guessing involved so there should be no need for NOP sleds. As was pointed out on his forum, this is because the shellcode executes the following instruction near the beginning:
This “FSTENV” instruction saves 28 bytes worth of state at ESP-0xC. Unfortunately, that 28 bytes ends up overlapping with our shellcode, and overwrites 3 bytes of it that we haven’t executed yet. The tutorial author probably just used a NOP sled from the beginning to give himself a little wiggle room and never again looked at why it was used or needed, so he never saw this problem. So, to make sure the shellcode doesn’t partially overwrite itself we need to introduce a 3 byte NOP sled. Our final payload now looks like this:
- Fix the shellcode’s to not crash after calc.exe executes (crashes after calc pops right now)
- Repair the application stack and return the vuln function (as if a normal m3u was encountered)
- Overwrite the malicious .m3u file to contain the same text (to destroy the evidence of the exploit)