Purpl3F0x Secur1ty

Pentesting, reverse engineering, and phishing & malware analysis.

21 June 2019

OSCE Prep - Vulnserver GMON - SEH Overwrite (No Egghunter)

by purpl3f0x

Previously, I wrote about performing the vulnserver.exe GMON SEH overflow, using an egghunter to overcome the space limitations. After a night of frustration and much learning, I re-created the exploit without the egghunter.

This will be a short post because I'm only going to cover the differences between this exploit and the egghunter exploit.

The Main Changes

So I start out by "resetting" the main buffer the remove the egghunter and the shellcode, for now. I change the value of "nSeh", which previously held an instruction to jump backwards 50 bytes, and now have it set to jump forward 6 bytes (two bytes for the NOPs at the end, and 4 bytes for the "SeH" buffer. That's just to start out of course:

After testing the jump I kept hitting this weird instruction starting with "BOUND EAX", which didn't immediately stop execution flow, but was a little weird. I change the jump later but for a different reason.

So, to restate the main issue that was covered in the previous post, we only have 28 bytes of space left after this jump; nowhere near enough for shellcode. Since I'm not simply jumping back to an egghunter, I need to jump backwards VERY far back up the stack to hit shellcode. Considering the size of the payload, a "JMP SHORT" is out of the question. So research began on how to make a bigger jump.

I found this helpful resource that detailed how to make that jump.

At first, I was confused about what was going on, I didn't know why it worked, but it just did. So then I took the time to read through what was happening, and stepped through my debugger one instruction at a time while reading this write up. I'll now break the process down myself (explaining things to others helps me remember stuff)

So, I'm going to place a small bit of shellcode just after "Seh", and name the variable "backjump". I'm also going to change my short forward jump to 15 bytes instead of just 6:

Let's breakdown the shellcode in the "backjump" variable:

\x59                        POP ECX
\xFE\xCD                DEC CH
\xFE\xCD                DEC CH
\xFE\xCD                DEC CH
\xFF\xE1                JMP ECX
\xE8\xF2\xFF\xFF\xFF        CALL [relative -0D]

Firstly, and most importantly to understanding this, we're jumping 15 bytes to SKIP the first 5 instructions in this shellcode. If we were to start at POP ECX and try to continue, everything would crash. We want to land on that CALL instruction. This CALL instruction is just redirection execution back up to the POP ECX instruction, but more importantly, it is storing a "return" value on the stack, which we will manipulate.

As the above screenshot shows, the function call caused the value of 00C0FFF2 to get PUSHed onto the stack. This is the address of the first "C". Function calls do this so that once the function is done, the program can jump back to where it's supposed to be. But we're not doing that obviously. Let's look at the next 4 instructions:

\x59                        POP ECX
\xFE\xCD                DEC CH
\xFE\xCD                DEC CH
\xFE\xCD                DEC CH

First, we're going to POP ECX. This is going to take the return value that we just PUSHed onto the stack, and POP it into ECX:

Now, we step into the three DEC CH instructions. Let's take a moment to understand what those are doing.

As shown here, CH is a sub-register of ECX. It represents bits 15-8 of the register, or in other words, the second-least significant byte. When we run "DEC CH", we're dropping the value of CH by 1. At first that doesn't sound like much, but since the first bit of CH is the 8th bit of ECX, we're effectively lowering the total value of ECX by 256. As you can see, we're going to do that three times, dropping ECX by a total of 768 bytes, more than enough for shellcode.

Now for the final step. Now that we've changed ECX, it's time to tell the program to jump to the instruction found at address 00C0FCF2. Guess what's waiting there?

That's right, it's a NOP sled! Ready to catch the vague jump and make sure we slide head-first into our reverse shell shellcode~!

At this point I set up my netcat listener, press F9 to resume normal execution, and:



This was quite frustrating during the first hour or so, but once I started understanding it, I found that I actually really liked this. I'm tickled that I actually understand what's happening and can explain it. I can chalk up this jumping technique to another tool to put in my toolset if I need to make such a jump again. Soon I'll probably try out some more vulnhub, or maybe even go hunting on Exploit-DB for some known-vulnerable programs and try to exploit them without reading the provided exploit.

tags: Exploit Dev - Security Research