Savant Web Server 3.1 – EBP Overwrite Walkthrough

In preparation for my OSCE exam I’ve been looking around for vulnerable software to hone my skills. In doing so I came across Savant Web Server 3.1 which needed to be exploited with a method I had never used.

To work along you’ll need :

Working Files

For the purposes of brevity I won’t walk through the process of fuzzing or finding the appropriate offset. There are a ton of great resources on this online that will explain those processes better than I would. I will, however, include a SPIKE file that should cause a crash and subsequent Proof of Concept python code.

Getting Started

After launching our proof of concept code we take a look at our registers. We see that EIP has been cleanly overwritten, and EBP appears to have our “junk” variable A’s located in it.

ESP does not seem to point to a valuable address and inspecting the stack shows us that our buffer is nowhere close to ESP so a simple JMP ESP instruction won’t do us much good.

So we have something in EBP that looks like it could be useful but it’s nowhere near ESP. Remembering that EBP (Base Pointer) points to the bottom of the stack while ESP points to the top, if we’re able to get into the A’s we might find ourselves with some space to fire an egghunter.

A simple JMP EBP would be nice, but searching through the executable and it’s attached modules leaves no love (remember that this is Vista so ASLR is enabled, so system DLL’s are not a viable option). What we’re looking at here is an Off-by-One Exploit.

Using Mona we look for loaded modules that have no ASLR enabled.

What we discover is that Savant.exe is the only enabled module without ASLR enabled. Now looking at the dump above we see that in the stack there are 4 bytes, and then a pointer to the beginning of our evil buffer. In the picture above we see that memory address 0x01D7EA50 points to 0x01D7EAA4, which is the GET portion of the string we send (or the HTTP Method).

The tasks we need to accomplish are as follows :

  • Remove the top 4 bytes off the top of the stack
  • Get EIP to execute the next instruction off the top of the stack (which will essentially point to the beginning of our string – GET)
  • Perform a short jump over the 0’s that immediately follow the GET command to get us into our A’s and provide ~ 254 bytes of space to work with.

Manipulating the Stack

We know that POP commands will remove the top 4 bytes from the top of the stack and place them into a register. We also know that the RET function will return to the value on the top of the stack. These two commands are exactly what we want as we have 4 bytes we don’t want, and then immediately following we have 4 bytes which we control. What we want is a POP <register>, RET command sequence.

Right click on Immunity and select Search For > Sequence of Commands. The following will be your values, noting that “r32” will search for any 32 bit register. When picking a register to POP the value into, it’s in your best interest to pick one that doesn’t look like it has much relevant data in it.

The following are our registers at crash time.

In this case I have the luxury of two registers with little (or no) information in them so I’ll pick ECX. I’ve found a POP ECX, RETN command sequence at 0x00419330. Let’s update our exploit code, set a breakpoint at the address and then run it again.

We hit our breakpoint at 0x00419330. We step through it by hitting F7 and notice the top 4 bytes are popped off the stack and into ECX as expected. Before executing the RETN instruction Immunity tells the instruction will “Retun to 01C8EAA4”. Our stack looks as follows

Okay so our POP ECX, RETN seems to be working as hoped. Now we need to jump over those 0’s to get into our buffer, which is easier said than done. Something in the software seems to be mangling some of the JMP op-codes. A simple JMP op code of FF get’s mangled to 9F, so it looks like we need to look into conditional jumps based on the status of EFLAGS on crash time. I tried a number of seemingly appropriate conditional jumps based on EFLAGS status before I was able to find one that was not getting bungled by the executable which was “Jump Not Greater” which will trigger if the Signed Flag and Zero Flag are both set to zero.

We launch our payload, step through the POP ECX, RETN and conditional jump and land right in our buffer. Now we’ve got ~254 bytes to work with – we could launch calc.exe and call it a day, but we want a reverse shell. We don’t have enough space to insert reverse TCP shellcode (Typically around 351 bytes), but we do have enough space to put an egg hunter.

The Egg Hunter

I will modify our code to insert a simple egg hunter that will search for the string W00TW00T in memory and then launch into our shellcode.

This code will serve as a test to see if items following the “\r\n\r\n” of the code will be loaded into memory. If you allow this code to run in it’s entirety it will cause a crash, but all I’m hoping to do is ensure my Egg Hunter works and that text following the “\r\n\r\n” is loaded into memory.

The exploit code is launched, and I place a breakpoint on the last instruction of the Egg Hunter (JMP EDI). Once the breakpoint is hit, I right click on EDI and select “Follow in Dump”, scroll up a bit and find my “T00WT00W”. This confirms that the Egg Hunter works, and it looks like there’s quite a bit of space to insert further shellcode after.

The Final Push

All that’s left to do now is generate our reverse shellcode using msfvenom and modify the exploit to include it.

After setting up our Netcat listener and using our exploit, we are greeted with a reverse shell (queue happy dance).

Thanks for reading – I hope this was informative!