OSCE Prep - Integard Exploit
So with all my lab exercises done it's time to venture outside the course material and do some extra practice. I went to Exploit-DB and looked up some Windows x86 buffer overflow posts that have links to the vulnerable software. The first thing I tried had a complicated setup just to get the application working so I abandoned it and moved onto something called Integard. From what I understand, it looks like it's an outbound proxy that's meant to stop devices from visiting undesirable websites. It runs an HTTP server locally and remotely, and has a login page to administrate it. The vulnerability lies there, in the password field, which doesn't limit how much input can be fed into it, and will crash the server. It's a pretty straight-forward buffer overflow, don't have to get too fancy, but then again, all the tricks necessary to topple this server were things I learned and practiced in the OSCE labs, so maybe to me it didn't feel too complex. I did however, learn not to go in too cocky and be lazy with the early steps. I wasted 2-3 hours on non-functional payloads all because I missed a single bad character. Had it not been for that, I'd have completed this before lunch, but instead, I was working on this until past 6PM. I ended up finding TWO ways to exploit it, which felt pretty good since the PoC on Exploit-DB was an SEH overwrite, and I couldnt' find any POCs for EIP overwrite, which is what I got when fuzzing. So let's get into the technical details~
Part 1 - Fuzzing with Boo-Gen and Boo-Fuzz
Since this is an HTTP attack, I started out similarly to how I started on the HP NNM fuzzing from the OSCE labs. I started by capturing an HTTP POST request in Burp Suite and then copying it to a file:
Then using Boo-Gen, I used this file to create the fuzzer:
As indicated by the arrow, I'm only fuzzing the password field. I fire this up and let it run its course:
It took about 15 seconds to get a crash that sort of appeared to be an EIP overwrite. I checked the SE Handler window in Immunity and did not have an SEH overwrite, so I ran with this and decided to see if it really was an EIP overwrite. According to Boofuzz, this crash resulted after sending about 2500 bytes:
So, the first lesson I learned at this stage; Always adhere to the proper HTTP format. I tried this for half an hour and didn't get a crash. I looked back at Boofuzz and noticed that "Content-Length" ended with two sets of \r\n, but my fuzzer only had one. After adding that in, I replicated the crash:
I neglected to catch it in this screenshot, but EIP was overwritten as "41414141", indicating that this mass of A's had overtaken EIP. So I went to the usual next step.
Part 2: Taking control of EIP
Time to look for the offset overwritting EIP with Pattern_Create and Pattern_Offset.
EIP was overwritten by this string, which came out to an offset of 832 bytes:
I modified the exploit to only send 832 A's, 4 B's, and then additional padding with C's, and ran the exploit again:
EIP was accurately overwritten with the four B's, and ESP is pointing to the buffer of C's. So far it's looking like a routine EIP overwrite.
For the JMP ESP I went looking within integard.dll, and found my jump:
I tested this, and reliably landed within the buffer of C's, so I moved to the final step (or so I thought), and added a reverse shell payload. At this point, the main buffer looked like this:
It's at this point that I felt the pain of not looking for bad characters. Everything I tried failed. I wasted hours trying to figure it out. Even after finding MOST of the bad characters, I found that reverse and bind shells didn't work. Both would succeed initially; reverse shells connected back to my Kali VM, and bind shells would open and listen on ports. But the moment that either shell tried to spawn the cmd.exe process, it would die. So then I tried Meterpreter, but that kept crashing the server in strange ways.
I ran a "sanity check" by loading up the Metasploit module for Integard and tried it out with reverse and bind shells and got the same problem, but, Meterpreter would work. At this point I was thinking that for whatever reason, EIP overwrite was simply unexploitable. It was then that I abandoned this and started over with an SEH overwrite. It was during the redo that I found a bad character I had initially missed, and with that knowledge, I circled back to the EIP exploit and got a working Meterpreter shell:
Here is a link to the finalized exploit.
Part 3: SEH overwrite
Looking at the original exploit for MSF, I saw that it was an SEH overwrite. I figured that the reason I got an EIP overwrite is because the fuzzer was starting out with smaller payloads and getting the EIP crash first. Taking a blind stab at it, I doubled my 2500 A buffer to 5000 and tried it again:
This time I got the SEH overwrite. It's a little misleading, because EIP is still being overwritten as well, so I had to just ignore that and check the SE Handler in Immunity.
Quickly moving along, I used the same Pattern_Create tool to find where the offsets for SEH and nSEH are at:
Looks good. SEH and nSEH should be 4 bytes apart. As usual I tested for accuracy...
...and we have complete accuracy.
The next part is where things would normally get pretty complex, but I dealt with this exact situation in the OSCE labs.
I started out trying a POP POP RET from ntdll, at this address:
But this didn't work. I kept getting "Debugged program was unable to pass the exception". For a while I was getting very confused, and wasted another half hour here running in circles. It was then that I remembered to run the command "!mona modules", and found that ntdll has SafeSEH enabled. I haven't had to deal with SafeSEH yet, but now I understand exactly what it's meant to do. Fortunately, integard.exe and integard.dll do NOT have SafeSEH enabled, so I can use those. There are just two problems, one I can deal with thanks to the OSCE labs, one I cannot.
All of the address spaces in integard.dll start with "1000". There's a null byte right in the middle of the address. No-go.
All of the address spaces in integard.exe start with a null byte. That I can deal with. The trick is to drop the trailing padding of C's and just overwrite the first 3 bytes of SEH and let the program fill in the last 00 itself. As an experiment, I tried actually putting in the full address anyway, since there was nothing to truncate anymore, and it actually worked out.
Now I know I need to make some backwards jumps to leverage the huge buffer of A's to hit some shellcode. Luckily, I was able to simply recycle some code from the OSCE lab exercises:
This looks a bit jumbled up, so I'll explain how it works in a moment. For now, I just run this and make sure I reliably hit the "bigBackJump" and that it takes me back enough to hit a payload. Since it works as expected, I add in the meterpreter payload and some NOPs, so my backJump doesn't land in shellcode:
I run this and:
Another functional Meterpreter shell! Integard has been thoroughly busted~
Part 4: Explaining how I do backwards jumps
This is a technique I learned doing the GMON command overflow in Vulnserver, and I've reused it a couple of times and it works out pretty well. I'll break down how it all works here:
Firstly, as expected, I overwrote SEH with a POP POP RET to get the program to jump back 4 bytes and hit my nSEH overwrite, "\xEB\xD0\x90\x90", which in assembly is JMP SHORT -48 bytes, and two NOPs for padding.
When this jumps back, I hit that 50-byte NOP sled that I placed just under the shellcode, and slide on down to the variable called "jumpCall", which is just a forward jump using "\xEB\x09". This is so that I will jump to the CALL instruction inside of "bigBackJump". Here is where things get interesting.
As you can see here, the hex that makes up "bigBackJump" translates to POP ECX, DEC CH, DEC CH, DEC CH, JMP ECX, CALL -0D. There is a reason I'm jumping over everything and going right into the CALL.
As pictured above, when I execute the CALL, execution flow redirects to the POP ECX. At the same time, the CALL placed a return address onto the stack.
That return address is then POP'd int ECX.
The higher-end of the CX register, CH, is decremented 3 times. Each decrement of CH lowers the overall value of ECX by 256, totalling up to 768. This is explained in more depth in my GMON SEH post.
JMP'ing to the value now in ECX lands me in a huge NOP sled. I should probably tweak the function to jump only 512 bytes next time..
Eventually the NOP sled ends up hitting the start of the Meterpreter decoder, and from there of course, we get a shell.
The finalized exploit is here.
I spent my entire Saturday on this, all because I fell into the rabbit hole of once again over-thinking when things don't work right. I should have been more diligent in my bad character checks, and paid more attention to which modules have SafeSEH enabled. Other than that, this exercise was a pretty simple one. The EIP overwrite is pretty vanilla and straight forward, and the SEH isn't too bad if you can work with backwards jumps. It was defintely interesting to work with a target that was vulnerable to both types of attacks.
Boo-Gen HTTP fuzzer generator - https://github.com/h0mbre/CTP/tree/master/Boo-Gen
Boofuzz Python fuzzer - https://boofuzz.readthedocs.io/en/latest/
Integard vulnerability disclosure - https://www.coresecurity.com/content/integard-home-and-pro-remote-buffer-overflow-exploit
Exploit-DB Metasploit Module - https://www.exploit-db.com/exploits/14941
tags: Exploit Dev - Security Research - CVE-2010-5333