def get_hbootkey(cls, samhive: registry.RegistryHive, bootkey: bytes) -> Optional[bytes]: sam_account_path = "SAM\\Domains\\Account" if not bootkey: return None sam_account_key = samhive.get_key(sam_account_path) if not sam_account_key: return None sam_data = None for v in sam_account_key.get_values(): if v.get_name() == 'F': sam_data = samhive.read(v.Data + 4, v.DataLength) if not sam_data: return None revision = sam_data[0x00] if revision == 2: md5 = hashlib.md5() md5.update(sam_data[0x70:0x80] + cls.aqwerty + bootkey + cls.anum) rc4_key = md5.digest() rc4 = ARC4.new(rc4_key) hbootkey = rc4.encrypt(sam_data[0x80:0xA0]) return hbootkey elif revision == 3: # AES encrypted iv = sam_data[0x78:0x88] encryptedHBootKey = sam_data[0x88:0xA8] cipher = AES.new(bootkey, AES.MODE_CBC, iv) hbootkey = cipher.decrypt(encryptedHBootKey) return hbootkey[:16] return None
def get_bootkey(cls, syshive: registry.RegistryHive) -> Optional[bytes]: cs = 1 lsa_base = "ControlSet{0:03}".format(cs) + "\\Control\\Lsa" lsa_keys = ["JD", "Skew1", "GBG", "Data"] lsa = syshive.get_key(lsa_base) if not lsa: return None bootkey = '' for lk in lsa_keys: key = syshive.get_key(lsa_base + '\\' + lk) class_data = syshive.read(key.Class + 4, key.ClassLength) if class_data is None: return None bootkey += class_data.decode('utf-16-le') bootkey_str = binascii.unhexlify(bootkey) bootkey_scrambled = bytes([ bootkey_str[cls.bootkey_perm_table[i]] for i in range(len(bootkey_str)) ]) return bootkey_scrambled
def get_user_keys(cls, samhive: registry.RegistryHive) -> List[interfaces.objects.ObjectInterface]: user_key_path = "SAM\\Domains\\Account\\Users" user_key = samhive.get_key(user_key_path) if not user_key: return [] return [k for k in user_key.get_subkeys() if k.Name != "Names"]
def get_user_hashes(cls, user: registry.CM_KEY_NODE, samhive: registry.RegistryHive, hbootkey: bytes) -> Tuple[bytes, bytes]: ## Will sometimes find extra user with rid = NAMES, returns empty strings right now try: rid = int(str(user.get_name()), 16) except ValueError: return None sam_data = None for v in user.get_values(): if v.get_name() == 'V': sam_data = samhive.read(v.Data + 4, v.DataLength) if not sam_data: return None lm_offset = unpack("<L", sam_data[0x9c:0xa0])[0] + 0xCC lm_len = unpack("<L", sam_data[0xa0:0xa4])[0] nt_offset = unpack("<L", sam_data[0xa8:0xac])[0] + 0xCC nt_len = unpack("<L", sam_data[0xac:0xb0])[0] lm_revision = sam_data[lm_offset + 2:lm_offset + 3] lmhash = None if lm_revision == b'\x01': if lm_len == 20: enc_lm_hash = sam_data[lm_offset + 0x04:lm_offset + 0x14] lmhash = cls.decrypt_single_hash(rid, hbootkey, enc_lm_hash, cls.almpassword) elif lm_revision == b'\x02': lm_exists = lm_len == 56 if lm_len == 56: lm_salt = sam_data[lm_offset + 4:lm_offset + 20] enc_lm_hash = sam_data[lm_offset + 20:lm_offset + 52] lmhash = cls.decrypt_single_salted_hash( rid, hbootkey, enc_lm_hash, cls.almpassword, lm_salt) # NT hash decryption nt_len = unpack("<L", sam_data[0xac:0xb0])[0] nthash = None nt_revision = sam_data[nt_offset + 2:nt_offset + 3] if nt_revision == b'\x01': if nt_len == 20: enc_nt_hash = sam_data[nt_offset + 4:nt_offset + 20] nthash = cls.decrypt_single_hash(rid, hbootkey, enc_nt_hash, cls.antpassword) elif nt_revision == b'\x02': if nt_len == 56: nt_salt = sam_data[nt_offset + 8:nt_offset + 24] enc_nt_hash = sam_data[nt_offset + 24:nt_offset + 56] nthash = cls.decrypt_single_salted_hash( rid, hbootkey, enc_nt_hash, cls.antpassword, nt_salt) return lmhash, nthash
def get_user_name(cls, user: interfaces.objects.ObjectInterface, samhive: registry.RegistryHive) -> Optional[bytes]: V = None for v in user.get_values(): if v.get_name() == 'V': V = samhive.read(v.Data + 4, v.DataLength) if not V: return None name_offset = unpack("<L", V[0x0c:0x10])[0] + 0xCC name_length = unpack("<L", V[0x10:0x14])[0] if name_length > len(V): return None username = V[name_offset:name_offset + name_length] return username