DPAPI / SAM / LSA / NTDS
Windows secrets differ in where and how they are stored and protected, including SAM, LSA, NTDS, and DPAPI. This page follows where Impacket obtains the material and which implementation decrypts it. For where credentials remain on a host, see Windows Credentials.
Secret acquisition paths and decoders are separate. The
secretsdump command orchestrates them; actual decryption is in
impacket/examples/secretsdump.py.
DPAPI itself is in dpapi.py /
dpapi_ng.py and
the dpapi command.
Layers
Section titled “Layers”flowchart TB
SYS["SYSTEM hive class: JD Skew1 GBG Data"] --> BK["boot key"]
BK --> SAMK["SAM hashed boot key"]
BK --> LSAK["LSA encryption key / PolEKList"]
BK --> PEK["NTDS PEK"]
SAMK --> UH["User LM/NT hash protected by RID-DES or AES"]
LSAK --> SEC["LSA Secrets / NL$KM / cached logon"]
PEK --> NTDS["NTDS hash / Kerberos key / trust key"]
DPAPI_SYS["DPAPI_SYSTEM in LSA"] --> MK["DPAPI Master Key"]
UserKey["SID + password or NT/SHA1"] --> MK
DomainPVK["domain backup private key BKRP"] --> MK
MK --> Blob["DPAPI_BLOB / Credential / Vault"]
Connect new acquisition methods (VSS, WMI shadow, Key List) to the same raw-record contract instead of embedding them in a decoder.
Boot key
Section titled “Boot key”LocalOperations.getBootKey() and the equivalent RemoteOperations process:
- Determine
ControlSet00NfromSelect\Current - Concatenate the class names (16 UTF-16 hex characters) for
Control\Lsa\{JD,Skew1,GBG,Data} - Permute with
[8,5,4,2,11,9,13,3,0,6,1,12,14,10,15,7]
A .reg text file lacks class names, so it cannot provide the boot key.
That is why secretsdump -system requires a binary REGF hive.
The NoLmHash policy is Control\Lsa\NoLmHash in the same ControlSet.
SAMHashes reads SAM\Domains\Account.
- The domain key is in the
Fvalue (DOMAIN_ACCOUNT_F). Older data uses RC4 (SAM_KEY_DATA), while newer data uses AES (SAM_KEY_DATA_AES). Constants on the RC4 path are!@#$%^&*()qwerty...and0123456789012345678901234567890123456789 - Users have a
Vvalue (USER_ACCOUNT_V) under their RID key. Their hashes are protected by two DES keys derived from the RID withCryptoCommon.deriveKey, or by AES SamDecryptNTLMHash/transformKeyare incrypto.py([MS-SAMR] 2.2.11.1.1)
Output uses domain\user:rid:lmhash:nthash:::. History has separate entries.
LSA Secrets and Cached Logons
Section titled “LSA Secrets and Cached Logons”LSASecrets opens the SECURITY hive with the boot key.
- Older hosts:
PolSecretEncryptionKey - Newer hosts:
PolEKList(AES) Policy\Secrets\*\CurrVal(LSA_SECRET/LSA_SECRET_XP) contains_SC_*(service passwords),$MACHINE.ACC,DPAPI_SYSTEM,NL$KM, and others- Cached logons are
NL_RECORDentries underCache, decrypted withNL$KM; Vista and later use DCC2 (NL$IterationCount)
regsecrets does not touch NTDS. It retrieves only this SAM + LSA path
through Remote Registry.
NTDSHashes normalizes two input paths into the same logical records.
| Path | Material | Characteristics |
|---|---|---|
ESE (-ntds / VSS) | ntds.dit | Reads tables with ese.py |
| DRSUAPI | IDL_DRSGetNCChanges | Does not copy the file; keeps a cursor in a resume file |
| Key List | RODC krbtgt AES + KERB_KEY_LIST_REQ | Long-term keys of authorized accounts |
The boot key protects the PEK (Password Encryption Key).
The beginning of pekList distinguishes generations.
| Header | Approximate OS Version | Decryption |
|---|---|---|
\x02... | 2012 R2 or earlier | MD5(bootkey + KeyMaterial repeated 1000 times) + RC4 → PEK list |
\x03... | 2016 and later | AES(bootKey, IV=KeyMaterial) → (index, 16-byte PEK)* |
For each account’s NT/LM hash, remove the PEK layer (RC4, with the PEK index
in the 8–10-byte header), then remove another DES layer derived from the RID.
Some data from 2016 onward uses AES. supplementalCredentials can contain
Kerberos AES/DES keys, WDigest, and sometimes plaintext passwords. Trusts derive
inter-realm keys (AES + RC4) from TDO authentication information (-trust-keys).
AES derivation emits both the FQDN salt {REALM_FQDN}krbtgt{PARTNER_FQDN} and,
when the NetBIOS/flat name is known, a (trust account) key salted with that
flat name; missing flat names omit the trust-account key instead of guessing it
from the DNS label.
DRSUAPI returns attributes by ID, so a missing attribute does not necessarily
mean an empty hash. -just-dc-user / -ldapfilter / -skip-user affect both
acquisition and output.
A master key sits between passwords and the secrets they protect.
| Structure | File / Location | Decryption Material |
|---|---|---|
MasterKeyFile / MasterKey | Protect\<SID>\GUID | SID+password, NT/SHA1, DPAPI_SYSTEM, domain PVK |
DPAPI_BLOB | Credential, Vault attributes, generic blobs | Master key SHA1, etc. |
CREDHIST_FILE | CREDHIST | Chain of previous user keys |
VAULT_VPOL / VAULT_VCRD | Policy / Credential | Vault key in vpol → vcrd attributes |
PREFERRED_BACKUP_KEY | LSA / BKRP | domain RSA backup key |
DPAPI_SYSTEM | LSA secret | Machine / user machine keys |
deriveKeysFromUser(sid, password) produces three candidates.
- HMAC-SHA1(SHA1(UTF-16 password), SID+\0)
- HMAC-SHA1(MD4(UTF-16 password), SID+\0) — NT hash path
- Two PBKDF2-SHA256 stages plus HMAC-SHA1 for Protected Users
Match blobs to master keys by GUID. Do not report a candidate plaintext as successful if its MAC does not match.
Windows LAPS / DPAPI-NG use dpapi_ng.py and
GKDI (GkdiGetKey). The flow is:
- Encrypted LDAP attribute →
EncryptedPasswordBlob+KeyIdentifier(root key ID, L0/L1/L2) - GKDI RPC with an SD for the target SID
- Derive the KEK from
GroupKeyEnvelope(FFC DH or ECDH, SP 800-108) - Use AES unwrap to obtain the CEK, then decrypt the password with it
GetLAPSPassword crosses
this boundary (LDAP → CMS → GKDI → DPAPI-NG). Legacy LAPS stores
ms-Mcs-AdmPwd as a plaintext attribute and does not use GKDI.
The domain backup key can be retrieved remotely through dcerpc.v5.bkrp
(dpapi.py backupkeys). Conversion to PVK / PKCS#1 uses
privatekeyblob_to_pkcs1.
Acquisition Paths (Remote)
Section titled “Acquisition Paths (Remote)”RemoteOperations gathers the material.
| Method | Action | Side Effects |
|---|---|---|
| Remote Registry | Save hives | Temporary files |
VSS / ntdsutil | Create a snapshot | Services, shadow copy |
WMI shadow (-use-remoteSSWMI) | Download SAM/SYSTEM/SECURITY(/NTDS) from a remote snapshot | Snapshot |
| DRSUAPI | Replicate | DC load, replication audit logs |
| Key List | RODC number + AES | Kerberos audit logs |
cleanup() removes services, temporary files, and resume state even on exception paths.
Checks When Making Changes
Section titled “Checks When Making Changes”- Preserve boot key class-name reading and permutation
- Do not read AES and RC4 SAM/LSA/PEK formats using one shared assumption
- Keep output schemas for SAM / cached logons / NTDS / trusts distinct
- Do not add decrypted hashes or keys to debug logs
- Related tests:
tests/SMB_RPC/test_secretsdump.py

