Query Details
# *Advanced Multi-Stage Windows Enumeration & Post-Exploitation Detector*
## Query Information
#### MITRE ATT&CK Technique(s)
| Technique ID | Title | Link |
| --- | --- | --- |
| T1522 | Unsecured Credentials | https://attack.mitre.org/techniques/T1522 |
| T1548 | Abuse Elevation Control | https://attack.mitre.org/techniques/T1548 |
| T1016 | Network Config Discovery | https://attack.mitre.org/techniques/T1548 |
| T1613 | Cloud/Container Discovery | https://attack.mitre.org/techniques/T1548 |
| T1082 | System Info Discovery | https://attack.mitre.org/techniques/T1548 |
#### Description
This query identifies potential post-exploitation behavior on Windows systems by monitoring for clusters of discovery and enumeration commands. Instead of alerting on single, potentially benign commands, it utilizes a behavioral scoring engine that categorizes activities such as credential hunting, Active Directory reconnaissance, and cloud metadata discovery.
By implementing extensive allowlists for common administrative tools (e.g., SCCM, Tanium, Monitoring Agents) and requiring a minimum threshold of unique command activity, the query effectively filters out "noise." It calculates a dynamic Risk Score and assigns a Severity level based on the criticality of the commands and the speed of execution (Burst Detection), making it a highly reliable tool for SOC analysts to detect active hands-on-keyboard attacks.
#### Author <Optional>
- **Name: Benjamin Zulliger**
- **Github: https://github.com/benscha/KQLAdvancedHunting**
- **LinkedIn: https://www.linkedin.com/in/benjamin-zulliger/**
#### References
-
## Defender XDR
```KQL
// ============================================================================
// Windows Discovery & Reconnaissance Detection — OPTIMIZED v2
// Detects post-exploitation enumeration with minimal false positives
// ============================================================================
let timeframe = 4h;
let threshold = 5; // Anzahl unterschiedlicher Einzelbefehle pro Zeitfenster
// --- ALLOWLISTS ---
let excludedAccounts = dynamic([
"SYSTEM", "NETWORK SERVICE", "LOCAL SERVICE", "SccmAdmin", "BackupUser"
]);
let excludedParentImages = dynamic([
"sccm-agent.exe", "monitoring-agent.exe", "taniumclient.exe", "qualysagent.exe",
"nessus.exe", "ansible-windows.exe", "salt-minion.exe", "msiexec.exe"
]);
// --- PATTERN DEFINITIONS ---
let suspiciousPatterns = dynamic([
// User & Group Discovery
"whoami /all", "whoami /groups", "net user", "net localgroup", "net group",
"quser", "query user", "cmdkey /list", "net accounts",
// Network & Domain Discovery
"ipconfig /all", "route print", "netstat -ano", "arp -a", "net view",
"nltest /domain_trusts", "nltest /dclist:", "nslookup", "dnscmd", "net share",
"adsiedit.msc", "ldp.exe", "setspn -q", "setspn -t",
// System & Config Discovery
"systeminfo", "hostname", "ver", "wmic qfe", "reg query", "sc query",
"tasklist", "driverquery", "gpresult /r", "auditpol /get",
// Privilege Escalation / Credential Hunting
"mimikatz", "procdump", "savedcredentials", "vaultcmd", "lazagne",
"PowerUp", "Get-GPPPassword", "findstr /s /i password", "dir /s *pass*",
// Cloud / Azure Discovery
"169.254.169.254", "az account get-access-token", "Get-AzADUser",
// Active Directory Recon
"Get-NetUser", "Get-NetComputer", "Get-DomainController", "Get-NetGroup",
"Get-ADUser", "Get-ADComputer", "Get-ADGroupMember"
]);
// --- MAIN QUERY ---
DeviceProcessEvents
| where TimeGenerated > ago(timeframe)
| where ProcessCommandLine has_any (suspiciousPatterns)
// ---- FP FILTER ----
| where AccountName !in (excludedAccounts)
| where InitiatingProcessFileName !in~ (excludedParentImages)
| where not(
InitiatingProcessFileName has_any ("windowsupdate.exe", "wusa.exe", "trustedinstaller.exe")
and ProcessCommandLine has_any ("update", "install")
)
// ---- Kategorisierung ----
| extend NormalizedCommand = case(
// High Risk
ProcessCommandLine has_any (
"mimikatz", "procdump", "vaultcmd", "Get-GPPPassword",
"savedcredentials", "lazagne", "PowerUp",
"findstr /s /i password", "dir /s *pass*"
), "Credential_Hunting",
ProcessCommandLine has_any (
"nltest", "setspn", "adsiedit", "ldp.exe",
"Get-DomainController", "Get-NetUser", "Get-NetComputer",
"Get-NetGroup", "Get-ADUser", "Get-ADComputer",
"Get-ADGroupMember", "net group /domain"
), "AD_Domain_Recon",
ProcessCommandLine has "169.254.169.254"
or ProcessCommandLine has "az account"
or ProcessCommandLine has "Get-AzADUser", "Cloud_Metadata_Discovery",
// Medium Risk
ProcessCommandLine has_any (
"net user", "net localgroup", "whoami /all",
"whoami /groups", "cmdkey", "quser", "query user", "net accounts"
), "User_Group_Enum",
ProcessCommandLine has_any (
"net share", "net view", "route print",
"netstat", "arp -a", "nslookup", "dnscmd"
), "Network_Share_Discovery",
ProcessCommandLine has_any (
"gpresult", "auditpol", "wmic qfe", "reg query", "sc query", "driverquery"
), "Policy_Security_Enum",
// Low Risk
ProcessCommandLine has_any (
"systeminfo", "hostname", "tasklist", "ver", "ipconfig"
), "System_Info_Discovery",
"General_Discovery"
)
// --- Aggregation ---
| summarize
UniqueCommandCount = dcount(ProcessCommandLine), // Anzahl unterschiedlicher Einzelbefehle
DetectedCategories = make_set(NormalizedCommand),
DetailedCommands = make_set(ProcessCommandLine, 20),
CommandCount = count(),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated),
ReportId = take_any(ReportId) // Single ReportId für Custom Detection
by DeviceId, DeviceName, AccountName
// Filter auf Schwellenwert
| where UniqueCommandCount >= threshold
// --- Risk Scoring ---
| extend RiskScore =
iif(set_has_element(DetectedCategories, "Credential_Hunting"), 4, 0)
+ iif(set_has_element(DetectedCategories, "AD_Domain_Recon"), 3, 0)
+ iif(set_has_element(DetectedCategories, "Cloud_Metadata_Discovery"), 3, 0)
+ iif(set_has_element(DetectedCategories, "User_Group_Enum"), 2, 0)
+ iif(set_has_element(DetectedCategories, "Network_Share_Discovery"), 2, 0)
+ iif(set_has_element(DetectedCategories, "Policy_Security_Enum"), 2, 0)
+ iif(set_has_element(DetectedCategories, "System_Info_Discovery"), 1, 0)
| extend ActivityDurationMinutes = datetime_diff('minute', LastSeen, FirstSeen)
// --- Severity Classification ---
| extend Severity = case(
RiskScore >= 10 and ActivityDurationMinutes between (1 .. 15), "Critical",
RiskScore >= 7, "High",
RiskScore >= 4, "Medium",
"Low"
)
| where Severity in ("Critical", "High", "Medium")
// --- Output ---
| project
Timestamp = FirstSeen,
DeviceName,
AccountName,
Severity,
RiskScore,
UniqueCommandCount,
CommandCount,
ActivityDurationMinutes,
DetectedCategories,
DetailedCommands,
DeviceId,
ReportId
| order by RiskScore desc
```
This query is designed to detect suspicious post-exploitation activities on Windows systems by monitoring for clusters of specific commands that are often used in reconnaissance and enumeration. Here's a simplified breakdown of what the query does:
Timeframe and Threshold: It looks at events within the last 4 hours and requires at least 5 unique suspicious commands to trigger an alert.
Allowlists: It excludes certain accounts and processes that are known to be legitimate, such as system accounts and common administrative tools, to reduce false positives.
Suspicious Patterns: The query defines a list of command patterns that are considered suspicious. These include commands for user and group discovery, network and domain discovery, system and configuration discovery, privilege escalation, credential hunting, cloud discovery, and Active Directory reconnaissance.
Filtering: It filters out events that match the suspicious patterns but are initiated by excluded accounts or processes.
Categorization: The query categorizes the detected commands into different risk levels, such as high risk (e.g., credential hunting), medium risk (e.g., user and group enumeration), and low risk (e.g., system info discovery).
Aggregation: It aggregates the data by device and account, counting the unique commands and categorizing the detected activities.
Risk Scoring: It calculates a risk score based on the categories of detected activities. Higher risk activities contribute more to the score.
Severity Classification: Based on the risk score and the duration of the activity, it classifies the severity of the detected behavior as Critical, High, Medium, or Low.
Output: Finally, it outputs the results, showing details such as the timestamp, device name, account name, severity, risk score, number of unique commands, total command count, activity duration, detected categories, and detailed commands.
This query is a powerful tool for security operations center (SOC) analysts to identify and respond to potential security threats by focusing on behavioral patterns rather than individual commands, thereby reducing false positives and improving detection accuracy.

Benjamin Zulliger
Released: March 10, 2026
Tables
Keywords
Operators