
Registry hive credential dumping: how SAM, SYSTEM and SECURITY interlock
If you have ever wondered why guides tell you to copy three registry hives to dump local Windows credentials and not one, this is the post. The three files are useless apart, and understanding why turns a memorized incantation into something you can reason about, detect, and defend. The broad map of where Windows keeps secrets is in Windows credential access; here I zoom all the way into the registry-hive row of that table: what each hive holds, the key that binds them, why the parse is an offline operation and what that means for the blue team, how to practice it on a box you own, and how to detect it.
Three hives, and why you need all three
The HKEY_LOCAL_MACHINE subtree is not one file. Windows assembles it at boot from several hive files in C:\Windows\System32\config\. Three of them carry credential material.
SAM (HKLM\SAM), the Security Account Manager, holds the local accounts and their password material. Nothing in it is plaintext, and it is not even a bare NT hash: each account's hash is encrypted with a key that is derived per machine. On its own the SAM gives you account names and ciphertext.
SYSTEM (HKLM\SYSTEM) holds the whole machine configuration, and buried in it are the pieces of the boot key (historically called the syskey). The boot key is not one readable value. It is split across the class-name attributes of four keys under CurrentControlSet\Control\Lsa, named JD, Skew1, GBG and Data, each obfuscated, and it has to be reassembled and descrambled in a fixed order. That reconstructed boot key is what decrypts the SAM hashes and the SECURITY secrets. This is the reason SYSTEM is mandatory: it is the key ring for the other two.
SECURITY (HKLM\SECURITY) holds the LSA secrets and the cached domain logons. The LSA secrets are a mixed bag: service account passwords in reversible form, the machine account secret, and, the one that often matters most, the DefaultPassword secret. When a host is set to log in automatically, the account password is stored here and comes back as cleartext. The hive also carries the domain cached credentials (MSCache v2, also called DCC2) that let a domain user sign in when no domain controller is reachable.
So the dependency is: SYSTEM unlocks SAM (local hashes) and unlocks SECURITY (service passwords, a possible cleartext autologon password, cached domain hashes). That is why every guide copies the set, and why a backup that grabs only one of them leaks nothing.
Inside the boot key and the hive file
The detail most writeups skip is how those four scattered values become a working key, and it is worth seeing once because it explains why the whole thing is a deterministic offline computation and not a secret the OS hands out.
The four class-name strings under ...\Control\Lsa\{JD,Skew1,GBG,Data} are hex text. Concatenated they form a 16-byte scrambled key, which is then reordered by a fixed, published permutation (the byte at position 8 goes first, then 5, then 4, and so on) to produce the real 16-byte boot key. There is no randomness and no per-read challenge: given the SYSTEM hive, anyone computes the identical boot key every time. That boot key, combined with a per-machine value from the SAM and two constant salt strings, is hashed to derive the key that actually decrypts each account record (RC4 on older builds, AES-128-CBC on Windows 10 and later). The same boot key decrypts the LSA secret blobs in SECURITY.
The files themselves are a documented on-disk format. A hive begins with a 4096-byte base block whose first four bytes are the ASCII signature regf, followed by sequence numbers, a timestamp, the offset of the root cell, and the hive's own embedded file name in UTF-16. After the base block come hbin bins, each 4096-byte aligned, holding the cells: nk key nodes, vk values, sk security descriptors, and the subkey-list cells that link them. You do not need to parse this by hand (the tools do), but knowing the regf signature is how you confirm a copied or reassembled hive is intact before spending time on it, and knowing the base block is a fixed snapshot is the clue to the next section.
Why the parse is offline, and what that means for defenders
The live hives are held open by the kernel, so you never read C:\Windows\System32\config\SAM as a file while Windows is running. Instead you ask the registry to serialize a consistent point-in-time copy (RegSaveKey, which is what reg save calls), or you lift the file out of a Volume Shadow Copy. Either way you get a stable snapshot, and every step after that, the boot-key reconstruction, the decryption, the hash extraction, happens on a different machine.
That offline-ness is the whole reason this path persists in a world of EDR, and it is the point a defender has to internalize. Controls that watch process memory, that protect lsass.exe, or that recognize a named credential tool by signature never see the decryption, because it does not happen on the monitored host. The only thing that happens on the host is a copy of three files. So a defender cannot treat "we protect LSASS" as covering this: the detectable moment is the hive access itself and the data leaving, not the credential extraction. That reframes the control set around file and command-line telemetry, which the Detection section lays out.
DCC2 is not an NT hash
The two credential types that come out of these hives behave very differently, and conflating them wastes time.
A local account's NT hash is MD4 of the UTF-16 password. It is directly usable: it authenticates over NTLM without being cracked (pass-the-hash), and it cracks relatively fast with a wordlist. That is the SAM payoff.
A cached domain credential (DCC2 / MSCache v2) from SECURITY is PBKDF2-HMAC-SHA1 with roughly ten thousand iterations wrapped around the older DCC1 value. It is not passable at all (there is no protocol that accepts it), and the iteration count makes it slow to crack. Its value is mostly intelligence: it proves which domain users have logged on to the box. Treating a DCC2 like a passable hash is a common beginner error.
Saving the hives (practice on a machine you own)
From an elevated prompt on your own lab VM, the registry serializes the copies for you:
reg save HKLM\SAM sam.save /y
reg save HKLM\SYSTEM system.save /y
reg save HKLM\SECURITY security.save /y
reg save needs the backup privilege, which a local administrator or SYSTEM holds. There is more than one way to obtain a copy of a locked hive, and they matter because each produces a different signal for the blue team:
| Method | How it gets a locked hive | Telemetry it tends to leave |
|---|---|---|
reg save HKLM\... |
RegSaveKey serializes a consistent snapshot |
reg.exe process with save and a hive name on the command line (4688 / Sysmon 1) |
esentutl /y /vss |
copies the open file via a shadow | esentutl.exe command line referencing config\SAM |
| Volume Shadow Copy | reads config\SAM from a snapshot |
shadow-copy creation (vssadmin / WMI), then a file read under the snapshot path |
| raw file copy | only works offline or from a mounted image | file-system access to config\SAM outside a backup window |
Same three files every time, four different command lines.
Moving a hive as text, and putting it back together
A .save hive is binary. When a copy has to travel over a text-only medium, the bytes are converted to text first; the built-in certutil encoder does this, wrapping them in base64 with a certificate-style header:
certutil -encode sam.save sam.b64
On the receiving side you strip the header lines and base64-decode back to bytes. A large hive (the SYSTEM hive is routinely tens of megabytes) may arrive in several pieces that have to be concatenated in order before decoding. The companion hivekit is a small, dependency-free helper that does only that boring reassembly: it joins base64 parts, drops the certutil framing, decodes, and checks the leading regf magic so you know the result is a real hive. It does not touch a target, dump anything, or parse secrets.
python3 hivekit.py --out system.save part00.b64 part01.b64 part02.b64
Parsing offline
With the three files on your own machine, the Impacket secretsdump tool reads them in LOCAL mode:
impacket-secretsdump -sam sam.save -system system.save -security security.save LOCAL
It reconstructs the boot key from SYSTEM, decrypts the SAM into local account NT hashes, and walks SECURITY for the LSA secrets and cached logons. Watch for a DefaultPassword line: that is the cleartext autologon password, and it is frequently reused elsewhere. The tools in this space (Impacket, and the mimikatz lsadump::sam and lsadump::secrets commands) are named here, not carried; the point is the mechanism and what each hive contributes.
Practice it safely, and watch your own detections
The best way to understand this is to run it against a VM you built and then look at the trace it left:
- Stand up a throwaway Windows VM. Create a local account with a password you do not use anywhere real.
- Turn on automatic logon for that account (Sysinternals Autologon, or the
Winlogonregistry values), using that throwaway password. This seeds theDefaultPasswordLSA secret. - From an elevated prompt,
reg savethe three hives as above. - Copy them off, run
secretsdump ... LOCAL, and find your throwaway account's NT hash and theDefaultPasswordcleartext in the output. Seeing your own known password come back out is the moment the mechanism clicks. - Now switch hats. With Sysmon installed and command-line auditing on, repeat step 3 and confirm the
reg.exe saveevents and the hive access show up. Tune a rule until it fires cleanly, then try theesentutland shadow-copy variants and watch how the signal changes.
That loop teaches the attack and the detection in one sitting, on a host you own, with a password that matters to nobody.
Inspiration and further reading
- LOLBAS on
certutil.exeas a built-in encoder and decoder: lolbas-project.github.io. - The Impacket project and
secretsdump: github.com/fortra/impacket. - HackTricks on dumping SAM and LSA secrets: book.hacktricks.xyz.
- MITRE ATT&CK: T1003.002 Security Account Manager, T1003.004 LSA Secrets, and T1550.002 Pass the Hash.
- Sysinternals Autologon, which stores the password as the
DefaultPasswordLSA secret rather than in the open: learn.microsoft.com/sysinternals/downloads/autologon.
Defense
Every step above leaves a place to stop it.
- Make a recovered local hash worthless. Deploy LAPS (or an equivalent) so every host has a unique, rotating local Administrator password. Then a hive dumped from one machine authenticates to exactly that one machine, which breaks the pass-the-hash fan-out that makes this worth doing. This is the single highest-value control here.
- Keep autologon off. If a host does not truly need automatic logon, remove it, because that
DefaultPasswordLSA secret is a cleartext credential sitting in a hive. Where autologon is unavoidable, use a dedicated low-privilege account whose password is reused nowhere. - Tier your admin model. A workstation or app-server local admin credential should never also open a domain controller or a tier-0 asset. Segmentation of credential scope limits how far one dumped hive travels.
- Limit cached domain logons. Lower
CachedLogonsCounton servers that do not need offline logon, so the SECURITY hive holds fewer DCC2 hashes. - Protect the privilege that enables it.
reg saveof these hives needs administrative or backup rights. Keep local admin membership minimal and keepSeBackupPrivilegeoff accounts that have no backup role.
Detection
The extraction is quiet but not silent, and because the parse is offline (see above), the host-side signals are all you get, so collect them deliberately.
- Hive access on the three names. Alert on
reg.exe save,esentutl.exe, or Volume Shadow Copy activity referencingSAM,SYSTEMorSECURITY. This needs process-creation logging with the full command line: Windows event 4688 (enable "Include command line in process creation events") or Sysmon event 1. - The built-in encoder in anger.
certutil -encodeor-decodeagainst a file that is not a certificate, especially shortly after a hive save. - Shadow-copy creation off-schedule.
vssadmin create shadowor the WMI equivalent outside a backup window, followed by a read under the shadow path. - The payoff, pass-the-hash. A local-account logon (
--local-auth, NTLM, logon type 3) from an unusual source is where a dumped hash gets used. Correlate it back to the hive save and you have the whole chain.
A starting Sigma-style sketch for the first signal, to adapt to your pipeline:
title: Registry hive save of SAM/SYSTEM/SECURITY
logsource: { product: windows, category: process_creation }
detection:
sel_reg:
Image|endswith: '\reg.exe'
CommandLine|contains|all: [' save ', 'HKLM\']
CommandLine|contains: ['\SAM', '\SYSTEM', '\SECURITY']
sel_esent:
Image|endswith: '\esentutl.exe'
CommandLine|contains: 'config\'
condition: sel_reg or sel_esent
falsepositives: [ 'legitimate backup software (baseline and exclude it)' ]
level: high
Most of this is invisible without command-line process logging and Sysmon, so the first defensive move is simply turning those on.
Use
Authorized and educational use only: your own systems, a lab you control, or an engagement with written permission. Practice against a VM you built so you can watch each hive contribute to the result and then watch your own detections fire. The companion code only reassembles and validates a base64 blob you already hold; it carries no extraction capability and is not for use against systems you do not own.