def main(sVaultFolder, sMasterkey, sSystem, sSecurity, sSoftware = None, boolOutput = True): ## Step 1: prepare DPAPI data (System MK pool) mkp = masterkey.MasterKeyPool() mkp.loadDirectory(sMasterkey) reg = registry.Regedit() secrets = reg.get_lsa_secrets(sSecurity, sSystem) dpapi_system = secrets.get('DPAPI_SYSTEM')['CurrVal'] mkp.addSystemCredential(dpapi_system) mkp.try_credential_hash(None, None) ## Step 2: Parse and DPAPI decrypt Policy.vpol vpol_filename = os.path.join(sVaultFolder, 'Policy.vpol') with open(vpol_filename, 'rb') as f: vpol_blob = parsePolicy(f.read()) vpol_cleartext = decrypt_blob(mkp, vpol_blob) if not vpol_cleartext: exit('[-] Unable to decrypt Policy.vpol') bKeyAES128, bKeyAES256 = parsePolicyEntries(vpol_cleartext) ## Step 3: Parse and AES decrypt VCRD sUsername = '' arrResult = [] for xfile in os.listdir(sVaultFolder): if xfile.lower().endswith('.vcrd'): filepath = os.path.join(sVaultFolder, xfile) if boolOutput: print('---- Working on ' + xfile + ' ----') with open(filepath, 'rb') as vcrdfile: bIV, bData, sSchemaType = parseVCRD(vcrdfile.read()) ## parseVCRD verifies the vault type (GUIDs at the top of this file) if bKeyAES256 and bData: cipher = AES.new(bKeyAES256, AES.MODE_CBC, iv = bIV) bDecrypted = cipher.decrypt(bData) dicContainers = parseDecryptedAttribute(bDecrypted) ## dicContainers[ContainerID] = bData if dicContainers[1].decode(errors='ignore').startswith('N\x00G\x00C\x00'): ## Should be "NGC Local Accoount Logon Vault Resource" in utf-16le if boolOutput: print('[+] Schema Type : ' + sSchemaType) print('[+] User SID : ' + parseSID(dicContainers[2])) if sSoftware: sUsername = getUsername(sSoftware, parseSID(dicContainers[2])) if boolOutput: print('[+] Username : '******'[+] Schema Type : ' + sSchemaType) print('[+] HEX decrypted data : ' + dicContainers[3].hex()) try: print('[+] Decoded value : ' + dicContainers[3].decode('utf-16le',errors='ignore')) except: pass if boolOutput: print('#'*50) if arrResult == []: print('[-] No vaults found') return (sUsername, arrResult)
parser.add_option('--usermasterkey', metavar='DIRECTORY', dest='usermasterkeydir') parser.add_option('--sid', metavar='SID', dest='sid', help=r'Carved from the User Masterkey folder, if possible') parser.add_option('--password', metavar='PASSWORD', dest='password', help='Optional: Will use empty password when not provided') parser.add_option('--pwdhash', metavar='HASH', dest='pwdhash') parser.add_option('--credhist', metavar='FILE', dest='credhist') (options, args) = parser.parse_args() check_parameters(options, args) reg = registry.Regedit() secrets = reg.get_lsa_secrets(options.security, options.system) dpapi_system = secrets.get('DPAPI_SYSTEM')['CurrVal'] #print('[+] SYSTEM DPAPI key: {}'.format(dpapi_system.hex())) mkp1 = masterkey.MasterKeyPool() mkp1.loadDirectory(options.systemmasterkeydir) mkp1.addSystemCredential(dpapi_system) mkp1.try_credential_hash(None, None) mkp2 = masterkey.MasterKeyPool() mkp2.loadDirectory(options.usermasterkeydir) if options.credhist: mkp2.addCredhistFile(options.sid, options.credhist) if options.password: mkp2.try_credential(options.sid, options.password) if options.pwdhash: mkp2.try_credential_hash(options.sid, bytes.fromhex(options.pwdhash)) for root, _, files in os.walk(options.wifi_dir): for file in files:
parser.add_option('--sid', metavar='SID', dest='sid') parser.add_option('--credhist', metavar='FILE', dest='credhist') parser.add_option('--password', metavar='PASSWORD', dest='password') parser.add_option( '--pwdhash', metavar='HASH', dest='pwdhash', help='Example for empth hash: da39a3ee5e6b4b0d3255bfef95601890afd80709' ) parser.add_option('--entropy_hex', metavar='HIVE', dest='entropy_hex') (options, args) = parser.parse_args() check_parameters(options, args) mkp = masterkey.MasterKeyPool() mkp.loadDirectory(options.masterkeydir) if options.sid: 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)) else: reg = registry.Regedit() secrets = reg.get_lsa_secrets(options.security, options.system) dpapi_system = secrets.get('DPAPI_SYSTEM')['CurrVal']
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: oBlob.decrypt(oMK.get_key()) else: oBlob.decrypt(bytes.fromhex(options.mkhex)) if oBlob.decrypted: bKey = oBlob.cleartext if bKey: print('[+] Decryption succes!') print(' Clear Key: {}'.format(bKey.hex()))
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)
help="DPAPI_SYSTEM string. 01000000...") parser.add_argument("--pkey", required=False, help="Private domain KEY", dest="pkey") parser.add_argument("--debug", required=False, action="store_true", dest="debug") # help="lines with base64-encoded password blobs") options = parser.parse_args() if options.masterkeydir: mkp = masterkey.MasterKeyPool() mkp.loadDirectory(options.masterkeydir) sysdecr = 0 if options.sysmasterkeydir and options.sysfile and options.secfile: systemmkp = masterkey.MasterKeyPool() systemmkp.loadDirectory(options.sysmasterkeydir) reg = registry.Regedit() secrets = reg.get_lsa_secrets(options.secfile, options.sysfile) dpapi_system = secrets.get('DPAPI_SYSTEM')['CurrVal'] systemmkp.addSystemCredential(dpapi_system) sysdecr = systemmkp.try_credential_hash(None, None) if options.pkey: decrn = mkp.try_domain(options.pkey) if decrn > 0: print("Decrypted: " + str(decrn))