├── .gitignore ├── README.md ├── fuzzer.py ├── seed └── test.hwp └── tmp └── test.hwp /.gitignore: -------------------------------------------------------------------------------- 1 | tmp/*.* 2 | result/*.* 3 | seed/*.* -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | NewFuzzer 2 | ========= 3 | 4 | HWP Document Fuzzer (Simple OLE Structure Parser) 5 | 6 | Requirement 7 | - Winappdbg http://winappdbg.sourceforge.net/ 8 | - OleFIleIO_PL http://www.decalage.info/python/olefileio 9 | - python disassembler http://sourceforge.net/projects/winappdbg/files/additional%20packages/diStorm/diStorm%201.7.30%20for%20Python%202/ 10 | 11 | pip install winappdbg olefileio-pl 12 | 13 | how to install pip on windows? 14 | - http://stackoverflow.com/a/9038397 15 | 16 | using the sublimetext2 to edit source code. 17 | 18 | http://www.sublimetext.com/2 19 | -------------------------------------------------------------------------------- /fuzzer.py: -------------------------------------------------------------------------------- 1 | #-*- coding: utf-8 -*- 2 | """ 3 | HWP Fuzzer 4 | """ 5 | 6 | import OleFileIO_PL as OLE 7 | import os 8 | import shutil 9 | import time 10 | from random import sample, uniform, choice 11 | import winappdbg 12 | from winappdbg import * 13 | from threading import Thread 14 | from hashlib import md5 15 | 16 | def pick(): 17 | pick_file = choice(os.listdir("seed")) 18 | try: 19 | shutil.copy(os.getcwd()+"\\seed\\"+pick_file, "tmp") 20 | except: 21 | emptyTemp() 22 | finally: 23 | shutil.copy(os.getcwd()+"\\seed\\"+pick_file, "tmp") 24 | 25 | return pick_file 26 | 27 | def mutation(dest_file): 28 | """ 29 | 30 | :param dest_file: 뮤테이션 할 파일 경로 전달 31 | """ 32 | dest_file = os.getcwd()+"\\tmp\\"+dest_file 33 | find_list = [] 34 | mutate_position = [] 35 | # HWP파일의 OLE구조에서 Bindata, BodyText, BinOLE 스토리지 하위 스트림 분석 36 | # 해당 스트림의 상위 16바이트를 Magic으로 사용하고 사이즈를 구함 37 | ole = OLE.OleFileIO(dest_file) 38 | ole_list = ole.listdir() 39 | 40 | for entry in ole_list: 41 | if "BinData" in entry and not ".OLE" in entry[1]: 42 | find_list.append((ole.openstream("BinData/"+entry[1]).read(16), ole.get_size("BinData/"+entry[1]))) 43 | """ 44 | if "BodyText" in entry: 45 | find_list.append((ole.openstream("BodyText/"+entry[1]).read(16), ole.get_size("BodyText/"+entry[1]))) 46 | if "BinOLE" in entry: 47 | find_list.append((ole.openstream("BinOLE/"+entry[1]).read(16), ole.get_size("BinOLE/"+entry[1]))) 48 | if "Workbook" in entry: 49 | find_list.append((ole.openstream("Workbook").read(16), ole.get_size("Workbook"))) 50 | """ 51 | ole.close() 52 | print find_list 53 | 54 | fuzz_offset = [] 55 | fuzz_byte = xrange(256) 56 | with open(dest_file, 'rb') as f: 57 | hwp = f.read() 58 | 59 | hwp_write = bytearray(hwp) 60 | hwp_length = len(hwp) 61 | # 파일에서 Magic의 오프셋을 검색하여 리스트에 저장 62 | for magic, size in find_list: 63 | if hwp.find(magic) != -1: 64 | offset = hwp.find(magic) 65 | mutate_position.append((offset, size)) 66 | 67 | # 해당 스트림 사이즈의 0.1 ~ 3% 변조 할 오프셋 선택 68 | for offset, size in mutate_position: 69 | fuzz_offset += sample(xrange(offset, offset+size), int(size*uniform(0.001, 0.03))) 70 | 71 | # 변조 72 | for index in fuzz_offset: 73 | if index >= hwp_length : continue 74 | hwp_write[index] = choice(fuzz_byte) 75 | # 파일로 저장 76 | try: 77 | with open(dest_file, 'wb') as f: 78 | f.write(hwp_write) 79 | return True 80 | except IOError as error: 81 | print error 82 | return False 83 | 84 | def handle(event): 85 | global proc 86 | global flag 87 | global crash_count 88 | code = event.get_event_code() 89 | proc = event.get_process() 90 | if ExceptionEvent(event.debug, event.raw).get_exception_code() in exceptions: 91 | print "[+] w00t!!! Crash!!" 92 | 93 | flag = True 94 | crash = Crash(event) 95 | crash.fetch_extra_data( event, takeMemorySnapshot = 0 ) 96 | # 유니크 크래시 찾는 부분 97 | unique = crash.signature[3] 98 | if unique in unique_list: 99 | print "[-] Duplicate Crash" 100 | proc.kill() 101 | else: 102 | crash_count += 1 103 | unique_list.append(unique) 104 | report = crash.fullReport() 105 | key = md5(unique).hexdigest() 106 | try: 107 | os.mkdir(r"result\%s" % key) 108 | with open(r"result\%s\log.txt" % key, "w") as f:f.write(report) 109 | shutil.copy(os.getcwd()+"\\seed\\"+target_file.split('\\')[-1], "result\\%s\\seed.%s" % (key, target_file.split(".")[-1])) 110 | shutil.copy(os.getcwd()+"\\tmp\\"+target_file.split('\\')[-1], "result\\%s\\mutate.%s" % (key, target_file.split(".")[-1])) 111 | except:pass 112 | finally:proc.kill() 113 | 114 | def debuggee(): 115 | with Debug(handle, bKillOnExit=True) as dbg: 116 | dbg.execl('"%s" "%s"' % (program, os.getcwd()+"\\tmp\\"+target_file)) 117 | dbg.loop() 118 | 119 | def runloop(): 120 | thread = Thread(target=debuggee) 121 | thread.start() 122 | while True: 123 | if flag: 124 | thread.join() 125 | break 126 | if time.time() > maxTime and not flag: 127 | try: 128 | proc.kill() 129 | except: 130 | os.system("taskkill /f /im %s" % program.split('\\')[-1]) 131 | thread.join() 132 | break 133 | time.sleep(0.5) 134 | 135 | def emptyTemp(): 136 | while len(os.listdir("tmp")) != 0 : 137 | for x in os.listdir("tmp"): 138 | try: 139 | os.remove(r"tmp\%s" % x) 140 | except: 141 | pass 142 | 143 | timeLimit = 3 144 | exceptions = 0x80000002, 0xC0000005, 0xC000001D, 0xC0000025,\ 145 | 0xC0000026, 0xC000008C, 0xC000008E, 0xC0000090,\ 146 | 0xC0000091, 0xC0000092, 0xC0000093, 0xC0000094,\ 147 | 0xC0000095, 0xC0000096, 0xC00000FD, 0xC0000374 148 | unique_list = [] 149 | 150 | program = r"C:\Program Files\HNC\HOffice9\Bin\Hwp.exe" 151 | crash_count = 0 152 | iter=0 153 | while True: 154 | iter +=1 155 | flag = False 156 | target_file = pick() 157 | mutation(target_file) 158 | os.system('cls') 159 | print "Iteration : %d / Crash : %d" % (iter, crash_count) 160 | maxTime = time.time() + timeLimit 161 | runloop() 162 | emptyTemp() 163 | -------------------------------------------------------------------------------- /seed/test.hwp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cdpython/NewFuzzer/af75bb13f1ee833c79bea9fbc9b2d4ddc1432162/seed/test.hwp -------------------------------------------------------------------------------- /tmp/test.hwp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cdpython/NewFuzzer/af75bb13f1ee833c79bea9fbc9b2d4ddc1432162/tmp/test.hwp --------------------------------------------------------------------------------