Skip to content

Back to the Technology Index

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.

Connect new acquisition methods (VSS, WMI shadow, Key List) to the same raw-record contract instead of embedding them in a decoder.

LocalOperations.getBootKey() and the equivalent RemoteOperations process:

  1. Determine ControlSet00N from Select\Current
  2. Concatenate the class names (16 UTF-16 hex characters) for Control\Lsa\{JD,Skew1,GBG,Data}
  3. 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 F value (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... and 0123456789012345678901234567890123456789
  • Users have a V value (USER_ACCOUNT_V) under their RID key. Their hashes are protected by two DES keys derived from the RID with CryptoCommon.deriveKey, or by AES
  • SamDecryptNTLMHash / transformKey are in crypto.py ([MS-SAMR] 2.2.11.1.1)

Output uses domain\user:rid:lmhash:nthash:::. History has separate entries.

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_RECORD entries under Cache, decrypted with NL$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.

PathMaterialCharacteristics
ESE (-ntds / VSS)ntds.ditReads tables with ese.py
DRSUAPIIDL_DRSGetNCChangesDoes not copy the file; keeps a cursor in a resume file
Key ListRODC krbtgt AES + KERB_KEY_LIST_REQLong-term keys of authorized accounts

The boot key protects the PEK (Password Encryption Key). The beginning of pekList distinguishes generations.

HeaderApproximate OS VersionDecryption
\x02...2012 R2 or earlierMD5(bootkey + KeyMaterial repeated 1000 times) + RC4 → PEK list
\x03...2016 and laterAES(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.

StructureFile / LocationDecryption Material
MasterKeyFile / MasterKeyProtect\<SID>\GUIDSID+password, NT/SHA1, DPAPI_SYSTEM, domain PVK
DPAPI_BLOBCredential, Vault attributes, generic blobsMaster key SHA1, etc.
CREDHIST_FILECREDHISTChain of previous user keys
VAULT_VPOL / VAULT_VCRDPolicy / CredentialVault key in vpol → vcrd attributes
PREFERRED_BACKUP_KEYLSA / BKRPdomain RSA backup key
DPAPI_SYSTEMLSA secretMachine / user machine keys

deriveKeysFromUser(sid, password) produces three candidates.

  1. HMAC-SHA1(SHA1(UTF-16 password), SID+\0)
  2. HMAC-SHA1(MD4(UTF-16 password), SID+\0) — NT hash path
  3. 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:

  1. Encrypted LDAP attribute → EncryptedPasswordBlob + KeyIdentifier (root key ID, L0/L1/L2)
  2. GKDI RPC with an SD for the target SID
  3. Derive the KEK from GroupKeyEnvelope (FFC DH or ECDH, SP 800-108)
  4. 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.

RemoteOperations gathers the material.

MethodActionSide Effects
Remote RegistrySave hivesTemporary files
VSS / ntdsutilCreate a snapshotServices, shadow copy
WMI shadow (-use-remoteSSWMI)Download SAM/SYSTEM/SECURITY(/NTDS) from a remote snapshotSnapshot
DRSUAPIReplicateDC load, replication audit logs
Key ListRODC number + AESKerberos audit logs

cleanup() removes services, temporary files, and resume state even on exception paths.

  • 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