def dump_sam_secrets(sam_dump: bytes, boot_key: bytes) -> List[SAMEntry]: """ Dump secrets from a SAM registry hive. The hashes are are stored in an double-encrypted format, and must first be decrypted. :param sam_dump: The SAM registry hive as a bytes. :param boot_key: The boot key as bytes. :return: A list of LM and NT hashes for each user in the SAM registry hive of the target host. """ sam_registry = Registry(BytesIO(sam_dump)) hashed_bootkey: bytes = obtain_hashed_bootkey( domain_account_f=DomainAccountF.from_bytes( data=sam_registry.open(r'SAM\Domains\Account').value('F').raw_data() ), bootkey=boot_key ) sam_entries: List[SAMEntry] = [] rid_strings = ( value.name() for value in sam_registry.open(r'SAM\Domains\Account\Users').subkeys() if value.name() != 'Names' ) for rid_string in rid_strings: user_account_v = UserAccountV.from_bytes( data=sam_registry.open(f'SAM\\Domains\\Account\\Users\\{rid_string}').value('V').raw_data() ) lm_hash, nt_hash = obtain_hashes_for_rid( rid=int(rid_string, 16), double_encrypted_lm_hash=user_account_v.encrypted_lm_hash, double_encrypted_nt_hash=user_account_v.encrypted_nt_hash, hashed_bootkey=hashed_bootkey ) password_hint = '' with suppress(RegistryValueNotFoundException): password_hint = sam_registry.open( path=f'SAM\\Domains\\Account\\Users\\{rid_string}' ).value('UserPasswordHint').raw_data().decode(encoding='utf-16le') sam_entries.append( SAMEntry( rid=int(rid_string, 16), account_name=user_account_v.name, password_hint=password_hint, lm_hash=lm_hash, nt_hash=nt_hash ) ) return sam_entries
def get_security_policy_secrets( security_registry: Registry, policy_secrets_decryption_key: bytes, use_new_style: bool = True ) -> Dict[str, bytes]: security_policy_secret_keys = ( security_policy_key for security_policy_key in security_registry.open(r'Policy\Secrets').subkeys() if security_policy_key.name() != 'NL$Control' ) secret_name_to_secret_data: Dict[str, bytes] = dict() for security_policy_secret_key in security_policy_secret_keys: for value_type in ('CurrVal', 'OldVal'): encrypted_secret_data = security_policy_secret_key.subkey(value_type).value('(default)').raw_data() if not encrypted_secret_data: continue if use_new_style: secret_data = LSASecret.from_bytes( data=encrypted_secret_data ).blob(decryption_key=policy_secrets_decryption_key).secret else: raise NotImplementedError secret_name_to_secret_data[ security_policy_secret_key.name() + ('_history' if value_type == 'OldVal' else '') ] = secret_data return secret_name_to_secret_data
def get_boot_key(lsa_registry: Registry, from_root: bool = False): return transform_untransformed_boot_key( untransformed_boot_key=bytes.fromhex(''.join( lsa_registry.open(boot_key_path.name if not from_root else str( boot_key_path))._nkrecord.classname() for boot_key_path in BOOT_KEY_PARTS_PATHS)))
def load_interfaces(reg_file): try: reg_handle = Registry(reg_file) int_keys = reg_handle.open('Microsoft\\WlanSvc\\Interfaces') except Exception as e: print( "I could not open the specified SOFTWARE registry key. It is usually located in \Windows\system32\config but is locked by the OS." ) print("Error : ", str(e)) return {} profile_lookup = {} for eachinterface in int_keys.subkeys(): if len(eachinterface.subkeys()) == 0: continue for eachprofile in eachinterface.subkey("Profiles").subkeys(): profileid = [ x.value() for x in eachprofile.values() if x.name() == "ProfileIndex" ][0] metadata = eachprofile.subkey("MetaData").values() for eachvalue in metadata: if eachvalue.name() == "Channel Hints": channelhintraw = eachvalue.value() hintlength = struct.unpack("I", channelhintraw[0:4])[0] name = channelhintraw[4:hintlength + 4] profile_lookup[str(profileid)] = name return profile_lookup
def load_reg_history(self, path_to_reg): reg_handle = Registry(path_to_reg) for eachsubkey in reg_handle.open( r"Microsoft\Windows NT\CurrentVersion\NetworkList\Signatures\Unmanaged" ).subkeys(): reg_mac = eachsubkey.value("DefaultGatewayMac").value() if not reg_mac: continue BSSID = b':'.join( codecs.encode(reg_mac[i:i + 1], "hex") for i in range(0, 6)).decode().upper() SSID = eachsubkey.value("FirstNetwork").value() ProfileGuid = eachsubkey.value("ProfileGuid").value() nettype, first, last = resolver.get_profile_info( reg_handle, ProfileGuid) location = None if nettype == "Wireless": if SSID in self.Locations.ap_ssids: location = self.Locations.best_ssid_location(SSID) elif BSSID in self.Locations.ap_bssids: location = self.Locations.best_bssid_location(BSSID) assert not isinstance(location, list) if location: self.data.append( Event(first, location, f"{SSID} {BSSID}-First-Connect")) self.data.append( Event(last, location, f"{SSID} {BSSID}-Last-Connect")) return
def registry_wifi_to_BSSID(wifi_name, reg_path = r"c:\Windows\system32\config\SOFTWARE"): reg_handle = Registry(reg_path) subkeys = reg_handle.open(r"Microsoft\Windows NT\CurrentVersion\NetworkList\Signatures\Unmanaged").subkeys() for eachkey in subkeys: if eachkey.value("FirstNetwork").value().lower() == wifi_name.lower(): reg_mac = eachkey.value("DefaultGatewayMac").value() BSSID = b':'.join(codecs.encode(reg_mac[i:i+1],"hex") for i in range(0,6)).decode().upper() return BSSID
def getCryptUsername(sSoftware, sSID): with open(sSoftware, 'rb') as oFile: oReg = Registry(oFile) oRegKey = oReg.open( 'Microsoft\\Windows\\CurrentVersion\\Authentication\\Credential Providers\\{D6886603-9D2F-4EB2-B667-1971041FA96B}' ) for oKey in oRegKey.subkeys(): if oKey.name() in sSID: return oKey.subkey('UserNames').subkeys()[0].name() return '<Unknown>'
def get_encrypted_policy_secrets_encryption_key( security_registry: Registry) -> tuple[bytes, bool]: """ :param security_registry: :return: """ try: return security_registry.open(r'Policy\PolEKList').value( '(default)').raw_data(), True except RegistryValueNotFoundException: pass try: return security_registry.open(r'Policy\PolSecretEncryptionKey').value( '(default)').raw_data(), False except RegistryValueNotFoundException: pass # TODO: Add a proper exception. raise Exception
def registry_all_wireless(reg_path = r"c:\Windows\system32\config\SOFTWARE"): reg_handle = Registry(reg_path) subkeys = reg_handle.open(r"Microsoft\Windows NT\CurrentVersion\NetworkList\Signatures\Unmanaged").subkeys() result = [] for eachkey in subkeys: name = eachkey.value("FirstNetwork").value() reg_mac = eachkey.value("DefaultGatewayMac").value() if not int.from_bytes(reg_mac, "big"): continue BSSID = b':'.join(codecs.encode(reg_mac[i:i+1],"hex") for i in range(0,6)).decode().upper() result.append( (name,BSSID) ) return result
def load_interfaces(reg_file): try: reg_handle = Registry(reg_file) except Exception as e: log.info("I could not open the specified SOFTWARE registry key. It is usually located in \Windows\system32\config. This is an optional value. If you cant find it just dont provide one.") log.info(f"WARNING : {str(e)} ") return {} try: int_keys = reg_handle.open('Microsoft\\WlanSvc\\Interfaces') except Exception as e: log.info("There doesn't appear to be any wireless interfaces in this registry file.") log.info(f"WARNING : {str(e)} ") return {} ssid2bssid = {} for eachsubkey in reg_handle.open(r"Microsoft\Windows NT\CurrentVersion\NetworkList\Signatures\Unmanaged").subkeys(): DefaultGatewayMac = eachsubkey.value("DefaultGatewayMac").value() BSSID = b':'.join(codecs.encode(DefaultGatewayMac[i:i+1],"hex") for i in range(0,6)).decode().upper() if BSSID == "00:00:00:00:00:00": continue SSID = eachsubkey.value("FirstNetwork").value() ssid2bssid[SSID]=BSSID profile_lookup = {} for eachinterface in int_keys.subkeys(): if len(eachinterface.subkeys())==0: continue for eachprofile in eachinterface.subkey("Profiles").subkeys(): profileid = eachprofile.value("ProfileIndex").value() try: channelhintraw = eachprofile.subkey("MetaData").value("Channel Hints").value() except: continue hintlength = struct.unpack("I", channelhintraw[0:4])[0] ssid = channelhintraw[4:hintlength+4].decode() bssid = ssid2bssid.get(ssid) if bssid: profile_lookup[str(profileid)] = (bssid,ssid) return profile_lookup
def main(sSOFTWARE, boolOutput = True): with open(sSOFTWARE, 'rb') as oFile: oReg = Registry(oFile) oKey = oReg.open('Microsoft\\Windows\\CurrentVersion\\Authentication\\LogonUI\\NgcPin\\Credentials') arrSIDs = [] for oSubKey in oKey.subkeys(): sSID = oSubKey.name() bData = oSubKey.value('EncryptedPassword').value() arrSIDs.append((sSID, bData)) if boolOutput: print('[+] Found ' + str(len(arrSIDs)) + ' stored NgcPin Password(s) in the registry :\n') oKey = oReg.open('Microsoft\\Windows\\CurrentVersion\\Authentication\\Credential Providers\\{D6886603-9D2F-4EB2-B667-1971041FA96B}') arrUsers = [] for oSubKey in oKey.subkeys(): for oItem in arrSIDs: if oItem[0] == oSubKey.name(): sUsername = oSubKey.subkey('UserNames').subkeys()[0].name() if boolOutput: print('[+] SID : ' + oItem[0]) print('[+] Username : '******'=' * 20) return arrUsers
def load_registry_sids(reg_file): """Given Software hive find SID usernames""" sids = {} profile_key = r"Microsoft\Windows NT\CurrentVersion\ProfileList" tgt_value = "ProfileImagePath" try: reg_handle = Registry(reg_file) key_handle = reg_handle.open(profile_key) for eachsid in key_handle.subkeys(): sids_path = eachsid.value(tgt_value).value() sids[eachsid.name()] = sids_path.split("\\")[-1] except Exception as e: print(str(e)) return {} print("Loaded SIDS", sids) return sids
def get_domain_cached_credentials( security_registry: Registry, cached_credentials_decryption_key: bytes, use_new_style: bool = True ) -> List[DomainCachedCredentials2]: iteration_count = 10240 with suppress(RegistryValueNotFoundException): reg_iteration_count = struct_unpack('<L', security_registry.open(r'Cache').value('NL$IterationCount'))[0] iteration_count = reg_iteration_count & 0xfffffc00 if reg_iteration_count > 10240 else reg_iteration_count * 1024 registry_cache_entries = ( RegistryCacheEntry.from_bytes(cache_key.raw_data()) for cache_key in security_registry.open('Cache').values() if cache_key.name() not in {'NL$Control', 'NL$IterationCount'} ) domain_cached_credentials: List[Union[DomainCachedCredentials, DomainCachedCredentials2]] = list() for registry_cache_entry in registry_cache_entries: if registry_cache_entry.initialization_vector == b'\x00' * 16: continue # TODO: Make nicer? (and parse flags in class)? if registry_cache_entry.flags & 1 == 1: if use_new_style: decrypted_cached_entry_data = decrypt_aes( key=cached_credentials_decryption_key, value=registry_cache_entry.encrypted_data, initialization_vector=registry_cache_entry.initialization_vector ) else: raise NotImplementedError # TODO: For some reason impacket uses `encrypt()`. Confirm that `decrypt()` is correct. # decrypted_cached_entry_data = ARC4.new( # key=HMAC.new( # key=nlkm_key, # msg=registry_cache_entry.initialization_vector, # ).digest() # ).decrypt(ciphertext=registry_cache_entry.encrypted_data) else: # "Plain! Until we figure out what this is, we skip it" raise NotImplementedError def calc_padded_length(length: int) -> int: return length + (length & 0x3) if (length & 0x3) > 0 else length padded_user_length = calc_padded_length(registry_cache_entry.user_length) padded_domain_length = calc_padded_length(registry_cache_entry.domain_name_length) encrypted_hash = decrypted_cached_entry_data[:16] username = decrypted_cached_entry_data[72:72+registry_cache_entry.user_length].decode(encoding='utf-16le') dns_domain_name = decrypted_cached_entry_data[ 72+padded_user_length+padded_domain_length : 72+padded_user_length+padded_domain_length+registry_cache_entry.dns_domain_name_length ].decode(encoding='utf-16-le') if use_new_style: domain_cached_credentials.append( DomainCachedCredentials2( iteration_count=iteration_count, dns_domain_name=dns_domain_name, username=username, encrypted_hash=encrypted_hash ) ) else: domain_cached_credentials.append( DomainCachedCredentials( dns_domain_name=dns_domain_name, username=username, encrypted_hash=encrypted_hash ) ) return domain_cached_credentials