NTLM Decrypt

Run Settings
LanguagePython
Language Version
Run Command
import sys import base64 import struct import string import collections flags_tbl_str = """0x00000001 Negotiate Unicode 0x00000002 Negotiate OEM 0x00000004 Request Target 0x00000008 unknown 0x00000010 Negotiate Sign 0x00000020 Negotiate Seal 0x00000040 Negotiate Datagram Style 0x00000080 Negotiate Lan Manager Key 0x00000100 Negotiate Netware 0x00000200 Negotiate NTLM 0x00000400 unknown 0x00000800 Negotiate Anonymous 0x00001000 Negotiate Domain Supplied 0x00002000 Negotiate Workstation Supplied 0x00004000 Negotiate Local Call 0x00008000 Negotiate Always Sign 0x00010000 Target Type Domain 0x00020000 Target Type Server 0x00040000 Target Type Share 0x00080000 Negotiate NTLM2 Key 0x00100000 Request Init Response 0x00200000 Request Accept Response 0x00400000 Request Non-NT Session Key 0x00800000 Negotiate Target Info 0x01000000 unknown 0x02000000 unknown 0x04000000 unknown 0x08000000 unknown 0x10000000 unknown 0x20000000 Negotiate 128 0x40000000 Negotiate Key Exchange 0x80000000 Negotiate 56""" flags_tbl = [line.split('\t') for line in flags_tbl_str.split('\n')] flags_tbl = [(int(x,base=16),y) for x,y in flags_tbl] def flags_lst(flags): return [desc for val, desc in flags_tbl if val & flags] def flags_str(flags): return ', '.join('"%s"' % s for s in flags_lst(flags)) VALID_CHRS = set(string.letters + string.digits + string.punctuation) def clean_str(st): return ''.join((s if s in VALID_CHRS else '?') for s in st) class StrStruct(object): def __init__(self, pos_tup, raw): length, alloc, offset = pos_tup self.length = length self.alloc = alloc self.offset = offset self.raw = raw[offset:offset+length] self.utf16 = False if len(self.raw) >= 2 and self.raw[1] == '\0': self.string = self.raw.decode('utf-16') self.utf16 = True else: self.string = self.raw def __str__(self): st = "%s'%s' [%s] (%db @%d)" % ('u' if self.utf16 else '', clean_str(self.string), self.raw.encode('hex'), self.length, self.offset) if self.alloc != self.length: st += " alloc: %d" % self.alloc return st msg_types = collections.defaultdict(lambda: "UNKNOWN") msg_types[1] = "Request" msg_types[2] = "Challenge" msg_types[3] = "Response" target_field_types = collections.defaultdict(lambda: "UNKNOWN") target_field_types[0] = "TERMINATOR" target_field_types[1] = "Server name" target_field_types[2] = "AD domain name" target_field_types[3] = "FQDN" target_field_types[4] = "DNS domain name" target_field_types[5] = "Parent DNS domain" target_field_types[7] = "Server Timestamp" def main(): st_raw = sys.stdin.read() try: st = base64.b64decode(st_raw) except e: print("Input is not a valid base64-encoded string") return if st[:8] == "NTLMSSP\0": print("Found NTLMSSP header") else: print("NTLMSSP header not found at start of input string") return ver_tup = struct.unpack("<i", st[8:12]) ver = ver_tup[0] print("Msg Type: %d (%s)" % (ver, msg_types[ver])) if ver == 1: pretty_print_request(st) elif ver == 2: pretty_print_challenge(st) elif ver == 3: pretty_print_response(st) else: print("Unknown message structure. Have a raw (hex-encoded) message:") def opt_str_struct(name, st, offset): nxt = st[offset:offset+8] if len(nxt) == 8: hdr_tup = struct.unpack("<hhi", nxt) print("%s: %s" % (name, StrStruct(hdr_tup, st))) else: print("%s: [omitted]" % name) def opt_inline_str(name, st, offset, sz): nxt = st[offset:offset+sz] if len(nxt) == sz: print("%s: '%s'" % (name, clean_str(nxt))) else: print("%s: [omitted]" % name) def pretty_print_request(st): hdr_tup = struct.unpack("<i", st[12:16]) flags = hdr_tup[0] opt_str_struct("Domain", st, 16) opt_str_struct("Workstation", st, 24) opt_inline_str("OS Ver", st, 32, 8) print("Flags: 0x%x [%s]" % (flags, flags_str(flags))) def pretty_print_challenge(st): hdr_tup = struct.unpack("<hhiiQ", st[12:32]) print("Target Name: %s" % StrStruct(hdr_tup[0:3], st)) print("Challenge: 0x%x" % hdr_tup[4]) flags = hdr_tup[3] opt_str_struct("Context", st, 32) nxt = st[40:48] if len(nxt) == 8: hdr_tup = struct.unpack("<hhi", nxt) tgt = StrStruct(hdr_tup, st) output = "Target: [block] (%db @%d)" % (tgt.length, tgt.offset) if tgt.alloc != tgt.length: output += " alloc: %d" % tgt.alloc print(output) raw = tgt.raw pos = 0 while pos+4 < len(raw): rec_hdr = struct.unpack("<hh", raw[pos : pos+4]) rec_type_id = rec_hdr[0] rec_type = target_field_types[rec_type_id] rec_sz = rec_hdr[1] subst = raw[pos+4 : pos+4+rec_sz] print(" %s (%d): %s" % (rec_type, rec_type_id, subst)) pos += 4 + rec_sz opt_inline_str("OS Ver", st, 48, 8) print("Flags: 0x%x [%s]" % (flags, flags_str(flags))) def pretty_print_response(st): hdr_tup = struct.unpack("<hhihhihhihhihhi", st[12:52]) print ("LM Resp: %s" % StrStruct(hdr_tup[0:3], st)) print ("NTLM Resp: %s" % StrStruct(hdr_tup[3:6], st)) print ("Target Name: %s" % StrStruct(hdr_tup[6:9], st)) print ("User Name: %s" % StrStruct(hdr_tup[9:12], st)) print ("Host Name: %s" % StrStruct(hdr_tup[12:15], st)) opt_str_struct("Session Key", st, 52) opt_inline_str("OS Ver", st, 64, 8) nxt = st[60:64] if len(nxt) == 4: flg_tup = struct.unpack("<i", nxt) flags = flg_tup[0] print ("Flags: 0x%x [%s]" % (flags, flags_str(flags))) else: print ("Flags: [omitted]") if __name__ == "__main__": main()
Editor Settings
Theme
Key bindings
Full width
Lines