Query Details
// =========================================================
// HUNT-14 | AD-NTDS-VSS-Dump-History-90d
// Description : Full historical audit of processes and
// commands (EventID 4688) consistent with
// NTDS.dit extraction via VSS, ntdsutil,
// diskshadow, esentutl, or reg save on DCs.
// Correlates with 4670 (sensitive object
// permission changes) and 4663 (Object Access)
// to reduce false positives.
// Period : 90 days
// Use Case : Forensic audit, credential theft
// post-incident investigation, NTDS dump paths
// Tables : SecurityEvent
// =========================================================
let Period = 90d;
// Build DC list from historical TGT issuances
let DCList = SecurityEvent
| where TimeGenerated > ago(Period)
| where EventID == 4768
| summarize by DCName = toupper(Computer);
// Process executions with NTDS dump signatures
let DumpProcesses = SecurityEvent
| where TimeGenerated > ago(Period)
| where EventID == 4688
| where Computer has_any (DCList) or Computer contains "DC"
| extend CmdLower = tolower(CommandLine)
| where CmdLower has_any (
"vssadmin create shadow",
"ntdsutil",
"diskshadow",
"esentutl",
"ifm",
"ntds.dit",
"system32\\config\\sam",
"reg save hklm\\sam",
"reg save hklm\\system",
"shadow copy",
"shadowcopy",
"\\windows\\temp\\",
"\\temp\\ntds",
"\\programdata\\ntds"
)
| extend
Actor = strcat(SubjectDomainName, "\\", SubjectUserName),
ActorNorm = tolower(SubjectUserName),
ParentProcess = ParentProcessName,
Process = NewProcessName,
DumpMethod = case(
CmdLower has "vssadmin", "VSSAdmin_ShadowCopy",
CmdLower has "ntdsutil", "Ntdsutil_IFM",
CmdLower has "diskshadow","DiskShadow",
CmdLower has "esentutl", "Esentutl_JetDB",
CmdLower has "reg save", "RegistryHive_SAM_SYSTEM",
"Generic_NTDS_Pattern"
);
// Correlate with object access on NTDS-related paths (4663)
let NTDSObjectAccess = SecurityEvent
| where TimeGenerated > ago(Period)
| where EventID == 4663
| where ObjectName has_any ("ntds.dit", "SAM", "SYSTEM", "SECURITY")
| summarize
NTDSAccessCount = count(),
AccessPaths = make_set(ObjectName, 10)
by AccessHost = toupper(Computer);
DumpProcesses
| join kind=leftouter (NTDSObjectAccess) on $left.Computer == $right.AccessHost
| summarize
DumpAttempts = count(),
DumpMethods = make_set(DumpMethod, 10),
CommandLines = make_set(CommandLine, 20),
Actors = make_set(Actor, 10),
Processes = make_set(Process, 10),
ParentProcesses = make_set(ParentProcess, 10),
NTDSFileAccess = take_any(NTDSAccessCount),
AccessedPaths = take_any(AccessPaths),
LastSeen = max(TimeGenerated),
FirstSeen = min(TimeGenerated)
by Computer
| extend
ConfirmedDump = (isnotnull(NTDSFileAccess) and NTDSFileAccess > 0)
| extend
RiskScore = (DumpAttempts * 20)
+ iff(ConfirmedDump, 50, 0)
+ (array_length(DumpMethods) * 10),
RiskLevel = case(
ConfirmedDump and DumpAttempts >= 2, "Critical - NTDS_Dumped_Confirmed",
ConfirmedDump, "Critical - NTDS_FileAccess_Detected",
DumpAttempts >= 3, "High - Multiple_Dump_Attempts",
DumpAttempts >= 1, "Medium - Dump_Command_Observed",
"Low"
)
| project
Computer,
RiskLevel,
RiskScore,
ConfirmedDump,
DumpAttempts,
DumpMethods,
Actors,
CommandLines,
AccessedPaths,
FirstSeen,
LastSeen
| order by RiskScore desc
This KQL query is designed to perform a forensic audit over the past 90 days to identify potential unauthorized attempts to extract the NTDS.dit file, which is critical for credential theft investigations. Here's a simplified breakdown of what the query does:
Define the Time Period: The query looks at security events from the last 90 days.
Identify Domain Controllers (DCs): It first identifies all domain controllers by examining historical Ticket Granting Ticket (TGT) issuances (EventID 4768).
Detect Suspicious Processes: It then searches for process executions (EventID 4688) on these domain controllers that match known patterns of NTDS.dit extraction methods, such as using tools like vssadmin, ntdsutil, diskshadow, esentutl, and registry save commands.
Correlate with Object Access: The query correlates these suspicious processes with object access events (EventID 4663) related to NTDS.dit and other sensitive files (SAM, SYSTEM, SECURITY) to reduce false positives.
Summarize Findings: For each domain controller, it summarizes the number of dump attempts, methods used, actors involved, and any access to NTDS-related files. It calculates a risk score based on these factors and assigns a risk level (Critical, High, Medium, Low).
Output: The final output lists each domain controller with its associated risk level, risk score, whether a confirmed dump occurred, the number of dump attempts, methods used, actors involved, command lines observed, accessed paths, and the first and last seen timestamps of these activities.
The query helps security teams quickly identify and prioritize potential security incidents involving NTDS.dit extraction attempts.

David Alonso
Released: March 24, 2026
Tables
Keywords
Operators