Registry hive credential dumping: how SAM, SYSTEM and SECURITY interlock

  • windows
  • credential-access
  • post-exploitation
  • privilege-escalation
  • detection

Proof of concept on GitHub

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.

The three hives interlock through the SYSTEM boot key The SYSTEM hive holds the boot key, which decrypts the SAM into local NT hashes and the SECURITY hive into LSA secrets including a cleartext autologon password and cached domain credentials. Without SYSTEM the other two are only ciphertext. SYSTEM hive holds the boot key SAM local NT hashes pass-the-hash, crack SECURITY LSA secrets: autologon cleartext + cached domain creds (DCC2) decrypts decrypts SYSTEM is the key ring: without it, SAM and SECURITY are only ciphertext
Why you copy all three. SYSTEM carries the boot key that decrypts both the SAM (local hashes) and the SECURITY hive (LSA secrets, a possible cleartext autologon password, cached domain logons). A backup missing SYSTEM leaks nothing usable.

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:

  1. Stand up a throwaway Windows VM. Create a local account with a password you do not use anywhere real.
  2. Turn on automatic logon for that account (Sysinternals Autologon, or the Winlogon registry values), using that throwaway password. This seeds the DefaultPassword LSA secret.
  3. From an elevated prompt, reg save the three hives as above.
  4. Copy them off, run secretsdump ... LOCAL, and find your throwaway account's NT hash and the DefaultPassword cleartext in the output. Seeing your own known password come back out is the moment the mechanism clicks.
  5. Now switch hats. With Sysmon installed and command-line auditing on, repeat step 3 and confirm the reg.exe save events and the hive access show up. Tune a rule until it fires cleanly, then try the esentutl and 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

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 DefaultPassword LSA 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 CachedLogonsCount on servers that do not need offline logon, so the SECURITY hive holds fewer DCC2 hashes.
  • Protect the privilege that enables it. reg save of these hives needs administrative or backup rights. Keep local admin membership minimal and keep SeBackupPrivilege off 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 referencing SAM, SYSTEM or SECURITY. 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 -encode or -decode against a file that is not a certificate, especially shortly after a hive save.
  • Shadow-copy creation off-schedule. vssadmin create shadow or 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.

Proof of concept on GitHub

Back to all techniques