Threat Hunting Deep Dive — Queries, Hypotheses, and Playbooks
Threat Hunting Deep Dive — Queries, Hypotheses, and Playbooks
CIPHER training module: 50+ production hunting queries across KQL/SPL/EQL, hypothesis-driven hunting methodology, data source requirements, cadence frameworks, and technique-specific playbooks for the top 20 ATT&CK techniques.
Table of Contents
- Hunting Methodology Framework
- Hypothesis Templates
- Data Source Requirements
- Hunting Cadence Framework
- Hunting Queries — KQL (50+)
- Hunting Queries — SPL
- Hunting Queries — EQL
- Hunting Queries — Sigma (Cross-Platform)
- Technique-Specific Playbooks (Top 20 ATT&CK)
- Hunting Maturity Model
- Source Attribution
Hunting Methodology Framework
The Hunting Loop (ThreatHunter-Playbook / Sqrrl Model)
PLAN -> Define hypothesis, identify data sources, expected telemetry
EXECUTE -> Run queries, collect artifacts, pivot on findings
ANALYZE -> Interpret results, validate/refute hypothesis, identify gaps
REPORT -> Document findings, update detection coverage, feed back into SIEM
LOOP -> Refine hypothesis, pursue new leads
Hunt Types
| Type | Description | Example |
|---|---|---|
| Hypothesis-Driven | Start with a theory about adversary behavior | "Attackers are using renamed LOLBins to evade filename-based detection" |
| Intelligence-Driven | Start with threat intel (IOCs, TTPs from reports) | "DFIR Report shows LockBit using vssadmin shadow delete — hunt for that pattern" |
| Situational Awareness | Baseline-deviation hunting — find anomalies | "What processes are making outbound connections on non-standard ports?" |
| Entity-Driven | Focus on high-value targets (DCs, CAs, PAWs) | "What non-standard processes ran on domain controllers this week?" |
Key Principles
- Hunt for behaviors, not IOCs — IOCs are ephemeral; TTPs persist across campaigns
- Establish baselines before hunting — you cannot find abnormal without knowing normal
- Document everything — even null results prove coverage or reveal gaps
- Automate successful hunts — every validated hunt becomes a detection rule
- Stack and frequency analysis — rare events in large datasets surface adversary activity
Hypothesis Templates
Template Structure
HYPOTHESIS ID : TH-YYYY-NNN
TECHNIQUE : MITRE ATT&CK TID (Technique Name)
HYPOTHESIS : [If <adversary action>, then <observable telemetry>]
DATA SOURCES : [Required log sources]
PRIORITY : Critical | High | Medium | Low
HUNT FREQUENCY : Daily | Weekly | Biweekly | Monthly
EXPECTED OUTPUT : [What the query returns when adversary activity is present]
FALSE POSITIVES : [Known benign triggers]
VALIDATION : [How to confirm true positive]
ESCALATION : [What to do if confirmed]
Example Hypotheses
TH-2026-001: Credential Dumping via LSASS Access
TECHNIQUE : T1003.001 (LSASS Memory)
HYPOTHESIS : If an attacker dumps LSASS memory, then a non-standard process
will access lsass.exe with PROCESS_VM_READ permissions
DATA SOURCES : Sysmon EventID 10 (ProcessAccess), MDE DeviceProcessEvents
PRIORITY : Critical
HUNT FREQUENCY : Daily
EXPECTED OUTPUT : Processes accessing lsass.exe that are not known security tools
FALSE POSITIVES : AV/EDR agents, WerFault.exe, taskmgr.exe (legitimate dump)
VALIDATION : Check process hash reputation, parent chain, time of execution
ESCALATION : Isolate host, collect memory dump, check for lateral movement
TH-2026-002: Living-off-the-Land Binary Abuse
TECHNIQUE : T1218 (System Binary Proxy Execution)
HYPOTHESIS : If an attacker uses LOLBins for execution, then system binaries
(mshta, rundll32, regsvr32, certutil) will have anomalous
command-line arguments or network connections
DATA SOURCES : Process creation logs, network connection logs
PRIORITY : High
HUNT FREQUENCY : Weekly
EXPECTED OUTPUT : LOLBins with download URLs, encoded content, or DLL loads
FALSE POSITIVES : SCCM/Intune deployments, legitimate admin scripts
VALIDATION : Check URL reputation, decode encoded payloads, verify admin activity
ESCALATION : Block URL, investigate downloaded payload, scan endpoint
TH-2026-003: Lateral Movement via SMB
TECHNIQUE : T1021.002 (SMB/Windows Admin Shares)
HYPOTHESIS : If an attacker moves laterally via SMB, then a single device
will create anomalous numbers of SMB sessions to multiple
internal hosts in a short time window
DATA SOURCES : DeviceNetworkEvents (port 445), Windows Security Event 5140/5145
PRIORITY : High
HUNT FREQUENCY : Daily
EXPECTED OUTPUT : Devices with >50 unique SMB target IPs in 15-minute windows
FALSE POSITIVES : Vulnerability scanners, backup systems, SCCM
VALIDATION : Correlate with authentication events, check source device role
ESCALATION : Isolate source, check for credential theft, map blast radius
TH-2026-004: Persistence via Scheduled Tasks
TECHNIQUE : T1053.005 (Scheduled Task)
HYPOTHESIS : If an attacker establishes persistence, then new scheduled tasks
will be created from unusual parent processes or referencing
suspicious executables in writable directories
DATA SOURCES : Windows Security Event 4698, Sysmon 1, Task Scheduler logs
PRIORITY : High
HUNT FREQUENCY : Weekly
EXPECTED OUTPUT : Scheduled tasks created by non-standard processes, pointing to
%APPDATA%, %TEMP%, or %PUBLIC% paths
FALSE POSITIVES : Software installations, Group Policy updates
VALIDATION : Verify task action binary, check creation time vs business hours
ESCALATION : Remove task, investigate referenced binary, check persistence map
TH-2026-005: Data Exfiltration via DNS
TECHNIQUE : T1048.003 (Exfiltration Over Unencrypted Protocol)
HYPOTHESIS : If an attacker exfiltrates data via DNS, then DNS query volumes
or subdomain lengths will be anomalously high for specific domains
DATA SOURCES : DNS query logs, passive DNS, network captures
PRIORITY : High
HUNT FREQUENCY : Daily
EXPECTED OUTPUT : Domains with high query entropy, long subdomain labels, high
TXT record query volumes
FALSE POSITIVES : CDN domains, telemetry endpoints, DKIM verification
VALIDATION : Decode subdomain content, check domain registration date/reputation
ESCALATION : Block domain, identify source process, assess data loss scope
TH-2026-006: C2 Beaconing Detection
TECHNIQUE : T1071.001 (Web Protocols)
HYPOTHESIS : If C2 is active, then a process will make periodic outbound
connections with consistent intervals to low-prevalence IPs
DATA SOURCES : DeviceNetworkEvents, proxy logs, firewall logs
PRIORITY : Critical
HUNT FREQUENCY : Daily
EXPECTED OUTPUT : Processes with regular connection intervals (jitter analysis),
connecting to IPs with low global prevalence
FALSE POSITIVES : Update services, heartbeat monitors, cloud sync agents
VALIDATION : Analyze connection timing (coefficient of variation), check
destination IP/domain reputation, inspect process binary
ESCALATION : Block C2 IP, isolate host, begin incident response
Data Source Requirements
Minimum Viable Hunting Stack
| Data Source | Purpose | Key Fields | Collection Method |
|---|---|---|---|
| Process Creation | Execution, LOLBin abuse, tool usage | CommandLine, ParentProcess, Hash, User | Sysmon 1, MDE, EDR |
| Network Connections | C2, lateral movement, exfil | SrcIP, DstIP, DstPort, Process, BytesSent | Sysmon 3, MDE, Zeek |
| File Creation/Modification | Payload drops, persistence artifacts | FilePath, Hash, CreatingProcess | Sysmon 11, MDE, EDR |
| Registry Modifications | Persistence, defense evasion | Key, Value, ModifyingProcess | Sysmon 13, MDE, EDR |
| Authentication Events | Credential abuse, lateral movement | User, LogonType, SourceIP, Status | Windows 4624/4625/4648 |
| DNS Queries | C2 resolution, DGA detection, exfil | QueryName, QueryType, ResponseIP | Sysmon 22, DNS server logs |
| PowerShell Logging | Script-based attacks, encoded commands | ScriptBlockText, CommandLine | Event 4104 (ScriptBlock) |
| Image/DLL Loads | DLL hijacking, injection | LoadedDLL, LoadingProcess, SignatureStatus | Sysmon 7, MDE |
| Process Access | Credential dumping (LSASS) | SourceProcess, TargetProcess, AccessMask | Sysmon 10 |
| Pipe Events | C2 comms, lateral movement (PsExec) | PipeName, CreatingProcess | Sysmon 17/18 |
Enhanced Sources (High-Value)
| Data Source | Hunting Use Case |
|---|---|
| ETW Providers | .NET assembly loading, AMSI bypass detection |
| WMI Trace | WMI persistence, remote execution |
| Kerberos Logs (4768/4769/4771) | Kerberoasting, AS-REP roasting, Golden/Silver ticket |
| LDAP Queries | BloodHound/SharpHound reconnaissance |
| Certificate Services | ESC1-ESC8 AD CS abuse, certificate-based persistence |
| Cloud Audit Logs | Azure/AWS/GCP IAM abuse, resource creation anomalies |
| Email/Office Logs | Phishing, mail rule persistence, OAuth app consent |
Sysmon Configuration Priorities
Event 1 : Process Creation [CRITICAL — foundation of all hunting]
Event 3 : Network Connection [HIGH — C2, lateral movement]
Event 7 : Image Loaded [HIGH — DLL hijacking, injection]
Event 10 : Process Access [CRITICAL — LSASS credential theft]
Event 11 : File Create [HIGH — payload drops]
Event 13 : Registry Value Set [HIGH — persistence]
Event 17/18: Pipe Created/Connected [MEDIUM — lateral movement tools]
Event 22 : DNS Query [HIGH — C2 resolution]
Event 25 : Process Tampering [HIGH — process hollowing]
Hunting Cadence Framework
Cadence by Priority
| Cadence | Hunt Focus | Example Techniques |
|---|---|---|
| Daily (Automated) | Critical TTPs with high fidelity signals | LSASS access, shadow copy deletion, C2 beaconing, ransomware precursors |
| Weekly | Persistence mechanisms, defense evasion, encoded commands | Scheduled tasks, registry run keys, LOLBin abuse, encoded PowerShell |
| Biweekly | Lateral movement patterns, privilege escalation | PsExec/SMB sweeps, service creation, token manipulation |
| Monthly | Reconnaissance, data staging, exfiltration patterns | AD enumeration, DNS exfil, rare outbound connections |
| Quarterly | Full ATT&CK coverage gap analysis, new technique adoption | Purple team exercises, detection coverage heat map update |
Hunt Sprint Structure (1-Week Sprint)
Day 1 : Hypothesis formation, data source validation
Day 2 : Query development and initial execution
Day 3 : Result analysis, pivot queries, false positive tuning
Day 4 : Validation of findings, escalation of true positives
Day 5 : Documentation, detection rule creation, report delivery
Hunting Queries — KQL
Execution
HQ-KQL-001: Encoded PowerShell Command Execution
// T1059.001 + T1027 — Detect base64-encoded PowerShell commands and decode them
// Source: Bert-JanP/Hunting-Queries-Detection-Rules
let EncodedList = dynamic(['-encodedcommand', '-enc']);
let TimeFrame = 48h;
DeviceProcessEvents
| where Timestamp > ago(TimeFrame)
| where ProcessCommandLine contains "powershell" or InitiatingProcessCommandLine contains "powershell"
| where ProcessCommandLine has_any (EncodedList) or InitiatingProcessCommandLine has_any (EncodedList)
| extend base64String = extract(@'\s+([A-Za-z0-9+/]{20}\S+$)', 1, ProcessCommandLine)
| extend DecodedCommandLine = base64_decode_tostring(base64String)
| extend DecodedCommandLineReplaceEmptyPlaces = replace_string(DecodedCommandLine, '\u0000', '')
| where isnotempty(base64String) and isnotempty(DecodedCommandLineReplaceEmptyPlaces)
| summarize UniqueExecutionsList = make_set(DecodedCommandLineReplaceEmptyPlaces) by DeviceName
| extend TotalUniqueEncodedCommandsExecuted = array_length(UniqueExecutionsList)
| project DeviceName, TotalUniqueEncodedCommandsExecuted, UniqueExecutionsList
| sort by TotalUniqueEncodedCommandsExecuted
HQ-KQL-002: Suspicious Explorer Child Processes
// T1204.002 — User executes malicious file; explorer spawns suspicious children
// Source: Bert-JanP/Hunting-Queries-Detection-Rules
let Parameters = dynamic(['http', 'https', 'Encoded', 'EncodedCommand', '-e', '-eC', '-enc', "-w", "://"]);
let SuspiciousChildProcesses = dynamic(['cmd.exe', 'powershell.exe', 'bash.exe', 'csscript.exe', 'mshta.exe', 'msiexec.exe', 'rundll32.exe']);
DeviceProcessEvents
| where InitiatingProcessFileName =~ "explorer.exe" or InitiatingProcessVersionInfoOriginalFileName =~ "explorer.exe"
| where FileName in~ (SuspiciousChildProcesses) or ProcessVersionInfoOriginalFileName in~ (SuspiciousChildProcesses)
| where ProcessCommandLine has_any (Parameters)
| project-reorder Timestamp, DeviceName, ProcessCommandLine, InitiatingProcessCommandLine, AccountUpn, ProcessVersionInfoOriginalFileName
HQ-KQL-003: MSHTA Execution Hunting
// T1218.005 — Mshta.exe used to proxy execute malicious HTA/scripts
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName =~ "mshta.exe" or ProcessVersionInfoOriginalFileName =~ "mshta.exe"
| where ProcessCommandLine has_any ("http", "https", "javascript", "vbscript", ".hta")
| project Timestamp, DeviceName, AccountName, ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine
| sort by Timestamp desc
HQ-KQL-004: Rundll32 with Suspicious Arguments
// T1218.011 — Rundll32 proxy execution with suspicious DLL paths or exports
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName =~ "rundll32.exe"
| where ProcessCommandLine matches regex @"(?i)(\\appdata\\|\\temp\\|\\public\\|\\programdata\\|http|javascript|shell32|comsvcs)"
| where ProcessCommandLine !contains "shell32.dll,Control_RunDLL" // common legit use
| project Timestamp, DeviceName, AccountName, ProcessCommandLine, InitiatingProcessFileName
| sort by Timestamp desc
Persistence
HQ-KQL-005: Scheduled Tasks Created from Suspicious Paths
// T1053.005 — Scheduled task persistence from writable directories
DeviceProcessEvents
| where Timestamp > ago(14d)
| where FileName =~ "schtasks.exe"
| where ProcessCommandLine has "/create"
| where ProcessCommandLine has_any ("\\AppData\\", "\\Temp\\", "\\Public\\", "\\ProgramData\\", "\\Downloads\\")
| project Timestamp, DeviceName, AccountName, ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine
HQ-KQL-006: Registry Run Key Persistence
// T1547.001 — Run/RunOnce key modifications for persistence
DeviceRegistryEvents
| where Timestamp > ago(7d)
| where ActionType == "RegistryValueSet"
| where RegistryKey has_any (@"CurrentVersion\Run", @"CurrentVersion\RunOnce")
| where RegistryValueData has_any (".exe", ".dll", ".bat", ".ps1", ".vbs", ".js", "cmd", "powershell")
| where InitiatingProcessFileName !in~ ("msiexec.exe", "setup.exe", "explorer.exe")
| project Timestamp, DeviceName, RegistryKey, RegistryValueName, RegistryValueData, InitiatingProcessFileName, InitiatingProcessCommandLine
HQ-KQL-007: New Windows Service Creation (Non-Standard)
// T1543.003 — Service persistence from non-system paths
DeviceRegistryEvents
| where Timestamp > ago(14d)
| where RegistryKey has @"SYSTEM\CurrentControlSet\Services"
| where RegistryValueName == "ImagePath"
| where RegistryValueData !startswith "C:\\Windows\\"
| where RegistryValueData !startswith '"C:\\Windows\\'
| where RegistryValueData !has "svchost.exe"
| project Timestamp, DeviceName, RegistryKey, RegistryValueData, InitiatingProcessFileName
| summarize count() by RegistryValueData
| sort by count_ asc
HQ-KQL-008: WMI Event Subscription Persistence
// T1546.003 — WMI event subscription for persistence
DeviceProcessEvents
| where Timestamp > ago(14d)
| where InitiatingProcessFileName =~ "WmiPrvSE.exe"
| where FileName !in~ ("WerFault.exe", "WmiApSrv.exe", "scrcons.exe")
| project Timestamp, DeviceName, FileName, ProcessCommandLine, AccountName
Defense Evasion
HQ-KQL-009: Defender Exclusion Tampering
// T1562.001 — Adding Defender exclusions to hide malicious files/processes
// Source: Bert-JanP/Hunting-Queries-Detection-Rules
let ExclusionOptions = dynamic(['ExclusionPath', 'ExclusionExtension', 'ExclusionProcess', 'ExclusionIpAddress']);
let Modules = dynamic(['Add-MpPreference','Set-MpPreference']);
let CommandLineExecutions = DeviceProcessEvents
| where ProcessCommandLine has_any (Modules) and ProcessCommandLine has_any (ExclusionOptions);
let PowerShellExecutions = DeviceEvents
| where ActionType == 'PowerShellCommand'
| where AdditionalFields has_any (Modules) and AdditionalFields has_any (ExclusionOptions);
union PowerShellExecutions, CommandLineExecutions
HQ-KQL-010: Disable Defender via PowerShell
// T1562.001 — PowerShell commands to disable Defender components
// Source: Bert-JanP/Hunting-Queries-Detection-Rules
DeviceProcessEvents
| where FileName =~ "powershell.exe"
| where ProcessCommandLine has_any ("Add-MpPreference","Set-MpPreference")
| where ProcessCommandLine has_any ("ExclusionProcess","ExclusionPath")
| project-reorder Timestamp, DeviceName, ProcessCommandLine, InitiatingProcessCommandLine, AccountUpn
HQ-KQL-011: Security Event Log Clearing
// T1070.001 — Clearing Windows event logs to cover tracks
DeviceProcessEvents
| where Timestamp > ago(7d)
| where (FileName =~ "wevtutil.exe" and ProcessCommandLine has_any ("cl", "clear-log"))
or (FileName =~ "powershell.exe" and ProcessCommandLine has "Clear-EventLog")
| project Timestamp, DeviceName, AccountName, ProcessCommandLine, InitiatingProcessFileName
HQ-KQL-012: Process Masquerading — Renamed System Binaries
// T1036.003 — Executables renamed to bypass filename-based detection
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName != ProcessVersionInfoOriginalFileName
| where ProcessVersionInfoOriginalFileName in~ ("powershell.exe", "cmd.exe", "rundll32.exe",
"regsvr32.exe", "mshta.exe", "wscript.exe", "cscript.exe", "certutil.exe")
| project Timestamp, DeviceName, FileName, ProcessVersionInfoOriginalFileName, ProcessCommandLine,
FolderPath, InitiatingProcessFileName
HQ-KQL-013: Timestomping Detection via MFT Anomalies
// T1070.006 — File timestamp manipulation
DeviceFileEvents
| where Timestamp > ago(7d)
| where ActionType == "FileTimestampModified"
| where InitiatingProcessFileName !in~ ("robocopy.exe", "explorer.exe", "msiexec.exe")
| project Timestamp, DeviceName, FileName, FolderPath, InitiatingProcessFileName,
InitiatingProcessCommandLine
| summarize count() by InitiatingProcessFileName
| sort by count_ desc
Credential Access
HQ-KQL-014: LSASS Process Access by Non-Standard Processes
// T1003.001 — Direct LSASS memory access for credential dumping
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName =~ "lsass.exe" or ProcessCommandLine has "lsass"
| join kind=inner (
DeviceEvents
| where ActionType == "ProcessAccess"
| where AdditionalFields has "lsass"
) on DeviceId
| project Timestamp, DeviceName, InitiatingProcessFileName, InitiatingProcessCommandLine
HQ-KQL-015: NTDS.dit File Access/Modification
// T1003.003 — Active Directory database extraction
// Source: Bert-JanP/Hunting-Queries-Detection-Rules
search in(DeviceFileEvents) "ntds" and "dit" and ActionType:"FileModified"
| where Timestamp > ago(90d)
| summarize Device_Count=dcount(DeviceId), Device_Sample=take_any(DeviceName),
File_Count=dcount(FolderPath), File_Sample=take_any(FolderPath),
Last_Seen=max(Timestamp)
by InitiatingProcessParentFileName, InitiatingProcessFolderPath, InitiatingProcessAccountName
| sort by Device_Count desc, File_Count desc
HQ-KQL-016: Kerberos Attack Tool Detection
// T1558 — Kerberoasting, AS-REP roasting, Golden/Silver ticket tools
// Source: Bert-JanP/Hunting-Queries-Detection-Rules
DeviceProcessEvents
| where ProcessCommandLine has_any ('sekurlsa::tickets /export', 'kerberos::ptt',
'ptt /ticket', ' monitor /interval', ' asktgt', ' asktgs', ' golden',
' silver', ' kerberoast', ' asreproast', ' renew', ' brute')
| project Timestamp, AccountName, DeviceName, InitiatingProcessFileName,
InitiatingProcessCommandLine, FileName, ProcessCommandLine
HQ-KQL-017: DCSync Detection
// T1003.006 — DCSync replication requests from non-DC sources
IdentityDirectoryEvents
| where ActionType == "Potential lateral movement path identified"
| project Timestamp, ActionType, Application, AccountName, AccountDomain,
AccountSid, AccountDisplayName, DeviceName, AdditionalFields
HQ-KQL-018: Credential Dumping via comsvcs.dll
// T1003.001 — LSASS dump via rundll32 + comsvcs.dll MiniDump
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName =~ "rundll32.exe"
| where ProcessCommandLine has "comsvcs" and ProcessCommandLine has_any ("MiniDump", "#24", "full")
| project Timestamp, DeviceName, AccountName, ProcessCommandLine, InitiatingProcessFileName
HQ-KQL-019: Cleartext Password in Command Line
// T1552 — Unsecured credentials exposed in process command lines
// Source: Bert-JanP/Hunting-Queries-Detection-Rules
DeviceProcessEvents
| where ProcessCommandLine has_all ("-password", "*")
| extend UserName = tostring(extract(@'user(?:name)?[=\s](\w+)', 1, ProcessCommandLine))
| summarize TotalExecutions = count(), UniqueCommands = dcount(ProcessCommandLine),
CommandLines = make_set(ProcessCommandLine, 1000), UniqueUsers = dcount(UserName),
UserNames = make_set(UserName) by DeviceName
| sort by UniqueUsers, UniqueCommands, TotalExecutions
Discovery
HQ-KQL-020: BloodHound/SharpHound Execution
// T1087/T1069 — AD enumeration tools
DeviceProcessEvents
| where Timestamp > ago(14d)
| where ProcessCommandLine has_any ("sharphound", "bloodhound", "azurehound",
"Invoke-BloodHound", "Get-BloodHoundData")
or FileName in~ ("SharpHound.exe", "AzureHound.exe")
| project Timestamp, DeviceName, AccountName, FileName, ProcessCommandLine,
InitiatingProcessFileName
HQ-KQL-021: Net/Nltest Discovery Commands
// T1018/T1082 — Network/system discovery via built-in tools
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName in~ ("net.exe", "net1.exe", "nltest.exe")
| where ProcessCommandLine has_any ("domain", "trust", "dclist", "group",
"localgroup", "user", "view", "/all")
| summarize Commands = make_set(ProcessCommandLine), CommandCount = count()
by DeviceName, AccountName, bin(Timestamp, 1h)
| where CommandCount >= 3 // multiple discovery commands = enumeration
| sort by CommandCount desc
HQ-KQL-022: LDAP Reconnaissance via Search Filters
// T1087.002 — LDAP queries for AD enumeration (FalconFriday 0xFF-0003)
IdentityQueryEvents
| where Timestamp > ago(7d)
| where ActionType == "LDAP query"
| where QueryTarget has_any ("admincount", "userAccountControl", "servicePrincipalName",
"msDS-AllowedToDelegateTo", "msDS-GroupManagedServiceAccount")
| project Timestamp, DeviceName, AccountName, QueryTarget, Query
| summarize QueryCount = count(), Queries = make_set(Query) by DeviceName, AccountName
| where QueryCount >= 5
Lateral Movement
HQ-KQL-023: PsExec Lateral Movement
// T1021.002/T1570 — PsExec remote execution tracking
// Source: Bert-JanP/Hunting-Queries-Detection-Rules
DeviceProcessEvents
| where ProcessCommandLine contains "psexec.exe"
| extend RemoteDevice = extract(@'\\\\(.*)c:', 1, ProcessCommandLine)
| summarize TotalRemoteDevices = dcount(RemoteDevice),
RemoteDeviceList = make_set(RemoteDevice),
ExecutedCommands = make_set(ProcessCommandLine) by DeviceName
| sort by TotalRemoteDevices
HQ-KQL-024: Anomalous SMB Session Volume
// T1021.002 — Lateral movement via mass SMB connections
// Source: Bert-JanP/Hunting-Queries-Detection-Rules
let Threshold = 50;
DeviceNetworkEvents
| where ingestion_time() > ago(1h)
| where RemotePort == 445
| summarize
TotalIpsAccessed = dcount(RemoteIP),
RemoteIPs = make_set(RemoteIP),
arg_max(Timestamp, *)
by DeviceName, bin(Timestamp, 15m)
| where TotalIpsAccessed >= Threshold
| project-reorder Timestamp, DeviceName, InitiatingProcessCommandLine,
InitiatingProcessAccountName, InitiatingProcessFolderPath
HQ-KQL-025: Remote Desktop Protocol — New Connections
// T1021.001 — RDP connections from non-standard sources
DeviceNetworkEvents
| where Timestamp > ago(14d)
| where RemotePort == 3389 and ActionType == "ConnectionSuccess"
| summarize FirstSeen = min(Timestamp), ConnectionCount = count()
by DeviceName, RemoteIP, InitiatingProcessFileName
| join kind=leftanti (
DeviceNetworkEvents
| where Timestamp between (ago(60d) .. ago(14d))
| where RemotePort == 3389
| distinct DeviceName, RemoteIP
) on DeviceName, RemoteIP
| sort by ConnectionCount desc
HQ-KQL-026: WMI Remote Process Creation
// T1047 — WMI used for remote execution
DeviceProcessEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName =~ "WmiPrvSE.exe"
| where FileName !in~ ("WerFault.exe", "WmiApSrv.exe")
| project Timestamp, DeviceName, FileName, ProcessCommandLine, AccountName,
InitiatingProcessCommandLine
| summarize count() by FileName, DeviceName
| sort by count_ desc
Command and Control
HQ-KQL-027: C2 Beaconing via Connection Pattern Analysis
// T1071.001 — Detect periodic outbound connections (beaconing)
// Source: Bert-JanP/Hunting-Queries-Detection-Rules
let DeviceThreshold = 5;
let ConnectionThreshold = 25;
let GlobalPrevalanceThreshold = 250;
DeviceNetworkEvents
| where Timestamp > ago(7d)
| where not(ipv4_is_private(RemoteIP))
| where ActionType == 'ConnectionSuccessAggregatedReport'
| extend Connections = toint(parse_json(AdditionalFields).uniqueEventsAggregated)
| summarize Total = count(), Devices = dcount(DeviceId),
Domains = make_set(RemoteUrl), AvgConnections = avg(Connections)
by RemoteIP, bin(Timestamp, 1d)
| where AvgConnections >= ConnectionThreshold and Devices <= DeviceThreshold
| join kind=inner (
DeviceNetworkEvents
| where ActionType == 'ConnectionSuccess'
| distinct RemoteIP, InitiatingProcessSHA256
) on RemoteIP
| invoke FileProfile(InitiatingProcessSHA256)
| where GlobalPrevalence <= GlobalPrevalanceThreshold
HQ-KQL-028: Rare Outgoing Non-Web Connections
// T1571 — Non-standard port C2 communication
// Source: Bert-JanP/Hunting-Queries-Detection-Rules
DeviceNetworkEvents
| where Timestamp > ago(30d)
| where isempty(RemoteUrl)
| where not(InitiatingProcessFileName matches regex @'(?i)^(msedge|chrome|firefox)\.exe$')
| where Protocol == "Tcp" and ActionType == "ConnectionSuccess"
and RemoteIPType == "Public"
| where InitiatingProcessFileName endswith ".exe"
| where not(RemotePort in (80, 443))
| extend InitiatingProcessFileName = tolower(InitiatingProcessFileName)
| summarize
Hashes = make_set(InitiatingProcessMD5),
DeviceCount = count_distinct(DeviceId),
SampleProcess = any(InitiatingProcessCommandLine),
SampleRemoteIP = any(RemoteIP),
Ports = make_set(RemotePort) by InitiatingProcessFileName
| where DeviceCount < 4
| extend RemoteIP_country = tostring(parse_json(geo_info_from_ip_address(SampleRemoteIP)).country)
| sort by DeviceCount asc
HQ-KQL-029: Sliver C2 Beacon Detection (Behavioral Chain)
// T1071 — Multi-step Sliver C2 detection via connection + pipe + DLL chain
// Source: Bert-JanP/Hunting-Queries-Detection-Rules
let ImageLoads = DeviceImageLoadEvents
| where ActionType == 'ImageLoaded'
| where FileName =~ "samlib.dll"
| where isnotempty(InitiatingProcessSHA256)
| invoke FileProfile(InitiatingProcessSHA256, 1000)
| where GlobalPrevalence <= 50 or isempty(GlobalPrevalence)
| project Timestamp, DeviceId, DeviceName, ActionType, FileName,
InitiatingProcessFileName, InitiatingProcessSHA256,
InitiatingProcessAccountSid, ReportId;
let UniqueHashes = toscalar(ImageLoads | summarize make_set(InitiatingProcessSHA256));
let NamedPipes = DeviceEvents
| where ActionType == 'NamedPipeEvent'
| where InitiatingProcessSHA256 in (UniqueHashes)
| join kind=inner (ImageLoads | distinct InitiatingProcessSHA256) on InitiatingProcessSHA256
| where parse_json(AdditionalFields).PipeName == @"\Device\NamedPipe\wkssvc"
| project Timestamp, DeviceId, DeviceName, ActionType, FileName,
InitiatingProcessFileName, InitiatingProcessSHA256,
InitiatingProcessAccountSid,
PipeName = parse_json(AdditionalFields).PipeName, ReportId;
let Connection = DeviceNetworkEvents
| where ActionType == "ConnectionSuccess"
| where InitiatingProcessSHA256 in (UniqueHashes)
| join kind=inner (ImageLoads | distinct InitiatingProcessSHA256) on InitiatingProcessSHA256
| project Timestamp, DeviceId, DeviceName, ActionType, RemoteIP, RemoteUrl,
InitiatingProcessFileName, InitiatingProcessSHA256,
InitiatingProcessAccountSid, ReportId;
union NamedPipes, ImageLoads, Connection
| sort by DeviceId, Timestamp asc, InitiatingProcessSHA256
| scan with_match_id=Id declare (Step:string, Delta:timespan) with (
step InitialConnection: ActionType == "ConnectionSuccess" => Step = "s1";
step NamedPipe: ActionType == 'NamedPipeEvent'
and DeviceId == InitialConnection.DeviceId
and InitiatingProcessSHA256 == InitialConnection.InitiatingProcessSHA256
and Timestamp between (Timestamp .. datetime_add('second', 1, InitialConnection.Timestamp))
=> Step = "s2", Delta = Timestamp - InitialConnection.Timestamp;
step ImageLoad: ActionType == 'ImageLoaded'
and DeviceId == NamedPipe.DeviceId
and InitiatingProcessSHA256 == NamedPipe.InitiatingProcessSHA256
and Timestamp between (Timestamp .. datetime_add('second', 1, NamedPipe.Timestamp))
=> Step = "s3", Delta = Timestamp - NamedPipe.Timestamp;
)
| where Step == 's3'
HQ-KQL-030: RAT/RMM Tool Detection
// T1219 — Remote access tool usage (TeamViewer, AnyDesk, RustDesk, etc.)
// Source: Bert-JanP/Hunting-Queries-Detection-Rules (Alex Teixeira)
DeviceProcessEvents
| where Timestamp > ago(60d)
| where FolderPath matches regex @'(?i)^[a-z]:\\\S+\.exe'
| where not(FolderPath contains "c:\\windows" and FolderPath matches regex
@'(?i)microsoft\.net|softwaredistribution|system32|syswow64|ccm|servicing|winsxs')
| extend RAT = case(
FolderPath contains "teamviewer", "TeamViewer",
FolderPath contains "anydesk", "AnyDesk",
FolderPath contains "rustdesk", "RustDesk",
FolderPath contains "vnc", "VNC",
FolderPath contains "logmein", "LogMeIn",
FolderPath contains "splashtop", "Splashtop",
FolderPath contains "screenconnect", "ScreenConnect",
FolderPath contains "supremo", "Supremo",
FolderPath contains "zerotier", "ZeroTier",
"Other")
| where RAT != "Other"
| summarize count(), dcount(DeviceName), make_set(DeviceName), max(Timestamp) by RAT, FolderPath
Impact
HQ-KQL-031: Ransomware Precursor — Shadow Copy Deletion
// T1490 — Shadow copy deletion as ransomware precursor
// Source: Bert-JanP/Hunting-Queries-Detection-Rules
let CommonRansomwareExecutionCommands = dynamic([
@'vssadmin.exe delete shadows /all /quiet',
@'wmic.exe shadowcopy delete',
@'wbadmin delete catalog -quiet',
@'Get-WmiObject Win32_Shadowcopy | ForEach-Object {$_.Delete();}',
@'wbadmin delete systemstatebackup -keepVersions:0',
@'schtasks.exe /Change /TN "\Microsoft\Windows\SystemRestore\SR" /disable'
]);
DeviceProcessEvents
| where ProcessCommandLine has_any (CommonRansomwareExecutionCommands)
| project-reorder Timestamp, ProcessCommandLine, DeviceName, AccountName
HQ-KQL-032: Mass File Encryption Detection
// T1486 — Data encrypted for impact (ransomware file modification)
DeviceFileEvents
| where Timestamp > ago(1h)
| where ActionType == "FileModified"
| summarize FileCount = count(), Extensions = make_set(FileName),
UniqueExtensions = dcount(tostring(extract(@'\.\w+$', 0, FileName)))
by DeviceName, InitiatingProcessFileName, bin(Timestamp, 5m)
| where FileCount > 100 and UniqueExtensions <= 2 // mass rename to single extension
| sort by FileCount desc
Webshell Detection
HQ-KQL-033: Webshell — Web Server Spawning Shell
// T1505.003 — Web server process spawning command interpreters
// Source: Bert-JanP/Hunting-Queries-Detection-Rules
let webservers = dynamic(["beasvc.exe", "coldfusion.exe", "httpd.exe", "owstimer.exe",
"visualsvnserver.exe", "w3wp.exe", "tomcat", "apache2", "nginx"]);
let linuxShells = dynamic(["/bin/bash", "/bin/sh", "python", "python3"]);
let windowsShells = dynamic(["powershell.exe", "powershell_ise.exe", "cmd.exe"]);
let exclusions = dynamic(["csc.exe", "php-cgi.exe", "vbc.exe", "conhost.exe"]);
DeviceProcessEvents
| where (InitiatingProcessParentFileName in~(webservers)
or InitiatingProcessCommandLine in~(webservers))
| where (InitiatingProcessFileName in~(windowsShells)
or InitiatingProcessCommandLine has_any(linuxShells))
| where FileName !in~ (exclusions)
| extend Reason = iff(InitiatingProcessParentFileName in~ (webservers),
"Suspicious web shell execution", "Suspicious webserver process")
| summarize by FileName, DeviceName, Reason, InitiatingProcessParentFileName,
InitiatingProcessCommandLine
Identity / Azure AD
HQ-KQL-034: Anomalous Azure AD Sign-In Patterns
// T1078.004 — Cloud account abuse via impossible travel or unusual location
SigninLogs
| where TimeGenerated > ago(14d)
| where ResultType == "0" // successful sign-ins only
| summarize Locations = make_set(Location), LocationCount = dcount(Location),
IPs = make_set(IPAddress), IPCount = dcount(IPAddress)
by UserPrincipalName, bin(TimeGenerated, 1d)
| where LocationCount > 3 or IPCount > 10
| sort by LocationCount desc
HQ-KQL-035: Suspicious OAuth Application Consent
// T1550.001 — Malicious OAuth app consent grants
AuditLogs
| where TimeGenerated > ago(30d)
| where OperationName == "Consent to application"
| extend AppName = tostring(TargetResources[0].displayName)
| extend Permissions = tostring(TargetResources[0].modifiedProperties)
| where Permissions has_any ("Mail.Read", "Files.ReadWrite", "Directory.ReadWrite",
"full_access_as_app")
| project TimeGenerated, InitiatedBy, AppName, Permissions
HQ-KQL-036: Password Spray Detection
// T1110.003 — Multiple failed logins across many accounts from single IP
SigninLogs
| where TimeGenerated > ago(1d)
| where ResultType != "0"
| summarize FailedAccounts = dcount(UserPrincipalName),
AccountList = make_set(UserPrincipalName),
FailureCount = count()
by IPAddress, bin(TimeGenerated, 15m)
| where FailedAccounts >= 10
| sort by FailedAccounts desc
HQ-KQL-037: MFA Fatigue / Push Bombing
// T1621 — Multiple MFA prompts in short succession
SigninLogs
| where TimeGenerated > ago(1d)
| where ResultType == "50074" // MFA required
| summarize MFAPrompts = count(), SuccessAfterSpam = countif(ResultType == "0")
by UserPrincipalName, IPAddress, bin(TimeGenerated, 10m)
| where MFAPrompts >= 5
| sort by MFAPrompts desc
Cloud (Azure/AWS)
HQ-KQL-038: Azure Resource Deployment from Unusual Location
// T1578 — Cloud infrastructure manipulation
AzureActivity
| where TimeGenerated > ago(7d)
| where OperationNameValue has_any ("Microsoft.Compute/virtualMachines/write",
"Microsoft.Network/networkSecurityGroups/write")
| where ActivityStatusValue == "Succeeded"
| summarize count() by Caller, CallerIpAddress, OperationNameValue
| join kind=leftanti (
AzureActivity
| where TimeGenerated between (ago(90d) .. ago(7d))
| distinct Caller, CallerIpAddress
) on Caller, CallerIpAddress
HQ-KQL-039: Azure Key Vault Secret Access Anomaly
// T1552.001 — Unusual secret/key retrieval from Azure Key Vault
AzureDiagnostics
| where ResourceType == "VAULTS"
| where OperationName has_any ("SecretGet", "KeyGet", "CertificateGet")
| summarize AccessCount = count(), UniqueSecrets = dcount(id_s)
by CallerIPAddress, identity_claim_upn_s, bin(TimeGenerated, 1h)
| where AccessCount > 20 or UniqueSecrets > 5
| sort by AccessCount desc
Linux Hunting
HQ-KQL-040: Suspicious Linux Process Execution
// T1059.004 — Unix shell command execution anomalies
DeviceProcessEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName in~ ("bash", "sh", "dash", "zsh")
| where ProcessCommandLine has_any ("curl", "wget", "nc", "ncat", "python -c",
"perl -e", "ruby -e", "base64 -d", "openssl enc")
| where ProcessCommandLine has_any ("http", "|", "bash", "sh", "/dev/tcp", "/dev/udp")
| project Timestamp, DeviceName, AccountName, ProcessCommandLine, InitiatingProcessCommandLine
HQ-KQL-041: Linux Cron Persistence
// T1053.003 — Cron job manipulation for persistence
DeviceFileEvents
| where Timestamp > ago(14d)
| where FolderPath has_any ("/etc/cron", "/var/spool/cron", "/etc/crontab")
| where ActionType in ("FileCreated", "FileModified")
| project Timestamp, DeviceName, FolderPath, FileName, InitiatingProcessFileName,
InitiatingProcessCommandLine, AccountName
HQ-KQL-042: Linux Reverse Shell Detection
// T1059.004 — Common reverse shell patterns
DeviceProcessEvents
| where Timestamp > ago(7d)
| where ProcessCommandLine has_any (
"/dev/tcp/", "/dev/udp/",
"mkfifo", "mknod",
"nc -e", "ncat -e",
"python -c 'import socket",
"perl -e 'use Socket",
"bash -i >& /dev/tcp",
"0<&196;exec 196<>/dev/tcp")
| project Timestamp, DeviceName, AccountName, ProcessCommandLine,
InitiatingProcessFileName
HQ-KQL-043: Linux Credential File Access
// T1003.008 — /etc/passwd, /etc/shadow access by unusual processes
DeviceFileEvents
| where Timestamp > ago(7d)
| where FileName in~ ("passwd", "shadow", "gshadow")
| where FolderPath startswith "/etc/"
| where InitiatingProcessFileName !in~ ("login", "sshd", "passwd", "su", "sudo",
"useradd", "userdel", "groupadd", "chpasswd", "pam")
| project Timestamp, DeviceName, FileName, InitiatingProcessFileName,
InitiatingProcessCommandLine, AccountName
Network Telemetry
HQ-KQL-044: DNS Tunneling Detection
// T1071.004 — DNS-based C2 or exfiltration
DnsEvents
| where TimeGenerated > ago(7d)
| extend SubdomainLength = strlen(tostring(split(Name, ".")[0]))
| extend DomainParts = countof(Name, ".")
| where SubdomainLength > 30 or DomainParts > 5
| summarize QueryCount = count(), AvgSubdomainLen = avg(SubdomainLength),
MaxSubdomainLen = max(SubdomainLength)
by Name, ClientIP
| where QueryCount > 50 and AvgSubdomainLen > 20
| sort by QueryCount desc
HQ-KQL-045: Ingress Tool Transfer via certutil
// T1105 — certutil used to download files (FalconFriday 0xFF-0001)
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName =~ "certutil.exe"
| where ProcessCommandLine has_any ("urlcache", "split", "http", "ftp", "verifyctl")
| where ProcessCommandLine has_any ("http://", "https://", "ftp://")
| project Timestamp, DeviceName, AccountName, ProcessCommandLine,
InitiatingProcessFileName
HQ-KQL-046: Bitsadmin Download
// T1105/T1197 — BITS job used for file download
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName =~ "bitsadmin.exe"
| where ProcessCommandLine has_any ("/transfer", "/addfile", "http://", "https://")
| project Timestamp, DeviceName, AccountName, ProcessCommandLine,
InitiatingProcessFileName
Privilege Escalation
HQ-KQL-047: Token Elevation to SeDebugPrivilege
// T1134 — Access token manipulation for privilege escalation
DeviceEvents
| where Timestamp > ago(7d)
| where ActionType == "ProcessPrimaryTokenModified"
| project Timestamp, DeviceName, InitiatingProcessFileName,
InitiatingProcessCommandLine, AccountName, AdditionalFields
HQ-KQL-048: UAC Bypass via fodhelper/eventvwr/sdclt
// T1548.002 — UAC bypass through auto-elevating binaries
DeviceProcessEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName in~ ("fodhelper.exe", "eventvwr.exe", "sdclt.exe",
"computerdefaults.exe", "slui.exe", "wsreset.exe")
| where FileName in~ ("cmd.exe", "powershell.exe", "pwsh.exe")
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName,
FileName, ProcessCommandLine
Collection / Exfiltration
HQ-KQL-049: Archive Creation for Exfiltration
// T1560.001 — Data staged via archive tools (7zip, rar, zip)
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName in~ ("7z.exe", "7za.exe", "rar.exe", "winrar.exe")
| where ProcessCommandLine has_any ("a ", "-p", "-hp") // archive creation with password
| project Timestamp, DeviceName, AccountName, ProcessCommandLine,
InitiatingProcessFileName
HQ-KQL-050: Large Data Upload to Cloud Storage
// T1567.002 — Exfiltration to cloud storage services
DeviceNetworkEvents
| where Timestamp > ago(7d)
| where RemoteUrl has_any ("mega.nz", "anonfiles.com", "transfer.sh", "gofile.io",
"file.io", "dropmefiles.com", "wetransfer.com", "sendspace.com")
| summarize TotalBytes = sum(SentBytes), ConnectionCount = count()
by DeviceName, RemoteUrl, InitiatingProcessFileName
| where TotalBytes > 10000000 // > 10MB
| sort by TotalBytes desc
Office/Email
HQ-KQL-051: Suspicious Office Child Process
// T1566.001 — Phishing attachment spawns suspicious process
DeviceProcessEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName in~ ("winword.exe", "excel.exe", "powerpnt.exe",
"outlook.exe", "onenote.exe", "msaccess.exe")
| where FileName in~ ("cmd.exe", "powershell.exe", "pwsh.exe", "mshta.exe",
"wscript.exe", "cscript.exe", "regsvr32.exe", "rundll32.exe",
"certutil.exe", "bitsadmin.exe")
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName,
FileName, ProcessCommandLine
HQ-KQL-052: Email Forwarding Rule Creation
// T1114.003 — Mailbox rule created for data collection
OfficeActivity
| where TimeGenerated > ago(7d)
| where Operation in ("New-InboxRule", "Set-InboxRule")
| where Parameters has_any ("ForwardTo", "ForwardAsAttachmentTo", "RedirectTo")
| project TimeGenerated, UserId, Operation, Parameters, ClientIP
Additional High-Value Hunts
HQ-KQL-053: DLL Side-Loading — Unsigned DLL in Signed Process Directory
// T1574.002 — DLL search order hijacking
DeviceImageLoadEvents
| where Timestamp > ago(7d)
| where not(IsSigned) or SignatureState != "SignedAndVerified"
| where FolderPath startswith "C:\\Program Files" or FolderPath startswith "C:\\Windows"
| where InitiatingProcessFileName !in~ ("devenv.exe", "code.exe") // exclude IDEs
| invoke FileProfile(SHA256, 1000)
| where GlobalPrevalence < 100 or isempty(GlobalPrevalence)
| project Timestamp, DeviceName, FileName, FolderPath, InitiatingProcessFileName,
GlobalPrevalence, SHA256
HQ-KQL-054: Process Injection via CreateRemoteThread
// T1055.003 — Remote thread injection detection
DeviceEvents
| where Timestamp > ago(7d)
| where ActionType == "CreateRemoteThreadApiCall"
| where InitiatingProcessFileName !in~ ("csrss.exe", "lsass.exe", "services.exe",
"svchost.exe", "MsMpEng.exe")
| project Timestamp, DeviceName, InitiatingProcessFileName,
InitiatingProcessCommandLine, FileName, AdditionalFields
HQ-KQL-055: Named Pipe Impersonation
// T1134.001 — Named pipe token impersonation for privilege escalation
DeviceEvents
| where Timestamp > ago(7d)
| where ActionType == "NamedPipeEvent"
| extend PipeName = tostring(parse_json(AdditionalFields).PipeName)
| where PipeName has_any ("\\pipe\\spoolss", "\\pipe\\epmapper",
"\\pipe\\samr", "\\pipe\\lsarpc")
| where InitiatingProcessFileName !in~ ("spoolsv.exe", "svchost.exe", "lsass.exe")
| project Timestamp, DeviceName, PipeName, InitiatingProcessFileName,
InitiatingProcessCommandLine
Hunting Queries — SPL
Splunk SPL Queries (Mapped to Splunk Security Content / ES)
HQ-SPL-001: Encoded PowerShell Execution
index=windows sourcetype="WinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=1
CommandLine="*powershell*" (CommandLine="*-enc*" OR CommandLine="*-encodedcommand*")
| rex field=CommandLine "(?i)-e[nc]*\s+(?<encoded_payload>[A-Za-z0-9+/=]{20,})"
| eval decoded=base64decode(encoded_payload)
| table _time, host, user, CommandLine, decoded, ParentCommandLine
| sort -_time
HQ-SPL-002: LSASS Memory Access via Sysmon
index=windows sourcetype="WinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=10
TargetImage="*\\lsass.exe"
NOT SourceImage IN ("*\\MsMpEng.exe", "*\\csrss.exe", "*\\svchost.exe",
"*\\WerFault.exe", "*\\taskmgr.exe", "*\\vmtoolsd.exe")
| eval AccessRights=if(match(GrantedAccess, "0x1010|0x1410|0x1438|0x143a|0x1fffff"),
"SUSPICIOUS", "NORMAL")
| where AccessRights="SUSPICIOUS"
| stats count by SourceImage, GrantedAccess, host, user
| sort -count
HQ-SPL-003: Shadow Copy Deletion
index=windows sourcetype="WinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=1
(CommandLine="*vssadmin*delete*shadows*" OR CommandLine="*wmic*shadowcopy*delete*"
OR CommandLine="*wbadmin*delete*catalog*"
OR CommandLine="*bcdedit*recoveryenabled*no*"
OR CommandLine="*bcdedit*bootstatuspolicy*ignoreallfailures*")
| table _time, host, user, CommandLine, ParentImage, ParentCommandLine
| sort -_time
HQ-SPL-004: Certutil Download Detection
index=windows sourcetype="WinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=1
Image="*\\certutil.exe"
(CommandLine="*urlcache*" OR CommandLine="*split*" OR CommandLine="*-decode*")
(CommandLine="*http*" OR CommandLine="*ftp*")
| table _time, host, user, CommandLine, ParentImage
| sort -_time
HQ-SPL-005: Suspicious Service Installation
index=windows sourcetype="WinEventLog:System" EventCode=7045
NOT ServiceFileName IN ("*\\Windows\\*", "*\\Program Files*", "*svchost.exe*")
| eval suspicious=case(
match(ServiceFileName, "(?i)(cmd|powershell|mshta|wscript|cscript)"), "HIGH",
match(ServiceFileName, "(?i)(temp|tmp|appdata|public|downloads)"), "MEDIUM",
1=1, "LOW")
| where suspicious IN ("HIGH", "MEDIUM")
| table _time, host, ServiceName, ServiceFileName, ServiceStartType, suspicious
| sort -_time
HQ-SPL-006: Kerberoasting — SPN Request Anomaly
index=windows sourcetype="WinEventLog:Security" EventCode=4769
ServiceName!="krbtgt" TicketEncryptionType=0x17
| stats count dc(ServiceName) as UniqueServices values(ServiceName) as Services
by TargetUserName, IpAddress
| where count > 5 AND UniqueServices > 3
| sort -UniqueServices
HQ-SPL-007: Pass-the-Hash Detection
index=windows sourcetype="WinEventLog:Security" EventCode=4624 LogonType=9
| eval suspicious=if(AuthenticationPackageName="Negotiate" AND
LogonProcessName="seclogo", "PtH_Candidate", "Normal")
| where suspicious="PtH_Candidate"
| stats count by TargetUserName, WorkstationName, IpAddress
| sort -count
HQ-SPL-008: DCSync Replication Attack
index=windows sourcetype="WinEventLog:Security" EventCode=4662
Properties="*Replicating Directory Changes*"
NOT SubjectUserName="*$"
| stats count by SubjectUserName, SubjectDomainName, ObjectServer
| where count > 1
| sort -count
HQ-SPL-009: PsExec Named Pipe Detection
index=windows sourcetype="WinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=17
PipeName IN ("\\PSEXESVC*", "\\RemCom*", "\\csexec*")
| table _time, host, Image, PipeName, user
| sort -_time
HQ-SPL-010: Rare Process Network Connections (Stacking)
index=windows sourcetype="WinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=3
Initiated=true NOT DestinationPort IN (80, 443, 53)
NOT DestinationIp IN ("10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16")
| stats count dc(host) as host_count values(DestinationIp) as dst_ips
values(DestinationPort) as dst_ports by Image
| where host_count < 3
| sort host_count
HQ-SPL-011: WMI Persistence Event Consumer
index=windows sourcetype="WinEventLog:Microsoft-Windows-Sysmon/Operational"
(EventCode=19 OR EventCode=20 OR EventCode=21)
| table _time, host, EventCode, EventType, Operation, User, Consumer, Destination
| sort -_time
HQ-SPL-012: Registry Run Key Modification
index=windows sourcetype="WinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=13
TargetObject="*\\CurrentVersion\\Run*"
NOT Image IN ("*\\explorer.exe", "*\\msiexec.exe", "*\\setup.exe")
| table _time, host, user, Image, TargetObject, Details
| sort -_time
Hunting Queries — EQL
Elastic EQL Queries
HQ-EQL-001: Encoded PowerShell Execution
process where event.type == "start" and
process.name : "powershell.exe" and
process.args : ("-enc", "-encodedcommand", "-e") and
process.args : regex("^[A-Za-z0-9+/]{20,}")
HQ-EQL-002: Suspicious Office Child Process
process where event.type == "start" and
process.parent.name : ("winword.exe", "excel.exe", "powerpnt.exe", "outlook.exe") and
process.name : ("cmd.exe", "powershell.exe", "mshta.exe", "wscript.exe",
"cscript.exe", "regsvr32.exe", "rundll32.exe", "certutil.exe")
HQ-EQL-003: LSASS Credential Dump via Process Access
process where event.type == "start" and
event.action == "process_access" and
process.name == "lsass.exe" and
not process.parent.name : ("MsMpEng.exe", "csrss.exe", "svchost.exe")
HQ-EQL-004: UAC Bypass via Auto-Elevating Binary
process where event.type == "start" and
process.parent.name : ("fodhelper.exe", "eventvwr.exe", "sdclt.exe", "wsreset.exe") and
process.name : ("cmd.exe", "powershell.exe", "pwsh.exe")
HQ-EQL-005: Rundll32 Suspicious Execution
process where event.type == "start" and
process.name == "rundll32.exe" and
(process.args : "javascript:*" or
process.args : "http*" or
process.args : "\\AppData\\*" or
process.args : "\\Temp\\*")
HQ-EQL-006: Service Creation for Persistence
registry where event.type == "change" and
registry.path : "HKLM\\SYSTEM\\*\\Services\\*\\ImagePath" and
not registry.data.strings : ("C:\\Windows\\*", "\\SystemRoot\\*")
HQ-EQL-007: Webshell Process Chain
process where event.type == "start" and
process.parent.name : ("w3wp.exe", "httpd.exe", "nginx.exe", "tomcat*.exe") and
process.name : ("cmd.exe", "powershell.exe", "bash", "sh")
HQ-EQL-008: Scheduled Task Persistence
process where event.type == "start" and
process.name == "schtasks.exe" and
process.args : "/create" and
process.args : ("\\AppData\\*", "\\Temp\\*", "\\Public\\*", "\\ProgramData\\*")
HQ-EQL-009: Lateral Movement via Remote Service
sequence by host.name with maxspan=1m
[process where event.type == "start" and process.name == "services.exe"]
[network where destination.port == 445 and source.port >= 49152]
HQ-EQL-010: Archive Creation Before Exfiltration
sequence by host.name with maxspan=5m
[process where event.type == "start" and
process.name : ("7z.exe", "rar.exe", "winrar.exe") and
process.args : ("-p*", "a")]
[network where destination.port in (443, 80) and
not destination.address : ("10.*", "172.16.*", "192.168.*")]
Hunting Queries — Sigma (Cross-Platform)
Sigma Rules for Detection-as-Code
HQ-SIG-001: Mimikatz Command Line Detection
# Source: SigmaHQ/sigma - proc_creation_win_hktl_mimikatz_command_line.yml
title: HackTool - Mimikatz Execution
id: a642964e-bead-4bed-8910-1bb4d63e3b4d
status: test
description: Detection of well-known mimikatz command line arguments
tags:
- attack.credential-access
- attack.t1003.001
- attack.t1003.002
- attack.t1003.004
- attack.t1003.005
- attack.t1003.006
logsource:
category: process_creation
product: windows
detection:
selection_tools_name:
CommandLine|contains:
- 'DumpCreds'
- 'mimikatz'
selection_function_names:
CommandLine|contains:
- '::aadcookie'
- '::detours'
- '::memssp'
- '::mflt'
- '::skeleton'
- '::printnightmare'
selection_module_names:
CommandLine|contains:
- 'rpc::'
- 'token::'
- 'crypto::'
- 'dpapi::'
- 'sekurlsa::'
- 'kerberos::'
- 'lsadump::'
- 'privilege::'
- 'process::'
- 'vault::'
condition: 1 of selection_*
falsepositives:
- Unlikely
level: high
HQ-SIG-002: Ingress Tool Transfer via Certutil
title: Certutil File Download
id: 19b08b1c-861d-4e75-a1ef-ea0c1baf202b
status: stable
description: Detects certutil.exe being used to download files from the internet
tags:
- attack.command-and-control
- attack.t1105
logsource:
category: process_creation
product: windows
detection:
selection:
Image|endswith: '\certutil.exe'
CommandLine|contains:
- 'urlcache'
- 'split'
filter:
CommandLine|contains: '-addstore'
condition: selection and not filter
falsepositives:
- Legitimate certificate operations (rare with urlcache flag)
level: high
HQ-SIG-003: Cobalt Strike Process Pattern
title: Cobalt Strike Process Injection Patterns
id: f35c5d71-b489-4e22-a115-e82a402c5e85
status: experimental
description: Detects process patterns commonly associated with Cobalt Strike beacon
tags:
- attack.execution
- attack.defense-evasion
- attack.t1055
logsource:
category: process_creation
product: windows
detection:
selection:
ParentImage|endswith:
- '\rundll32.exe'
- '\regsvr32.exe'
- '\dllhost.exe'
Image|endswith:
- '\cmd.exe'
- '\powershell.exe'
condition: selection
falsepositives:
- Legitimate software using COM
level: medium
HQ-SIG-004: Shadow Copy Deletion
title: Shadow Copy Deletion via System Tools
id: c947b146-0571-4c04-85fb-5ea1e4c8d149
status: stable
description: Detects shadow copy deletion commonly used by ransomware
tags:
- attack.impact
- attack.t1490
logsource:
category: process_creation
product: windows
detection:
selection_vssadmin:
Image|endswith: '\vssadmin.exe'
CommandLine|contains|all:
- 'delete'
- 'shadows'
selection_wmic:
Image|endswith: '\wmic.exe'
CommandLine|contains|all:
- 'shadowcopy'
- 'delete'
selection_wbadmin:
Image|endswith: '\wbadmin.exe'
CommandLine|contains:
- 'delete catalog'
- 'delete systemstatebackup'
condition: 1 of selection_*
falsepositives:
- Legitimate backup management by IT (verify with change management)
level: critical
Sigma Conversion Commands:
# Convert to Splunk SPL
sigma convert -t splunk -p sysmon rule.yml
# Convert to Elastic EQL
sigma convert -t elasticsearch -p ecs_windows rule.yml
# Convert to Microsoft Sentinel KQL
sigma convert -t microsoft365defender rule.yml
# Convert to QRadar AQL
sigma convert -t qradar rule.yml
Technique-Specific Playbooks (Top 20 ATT&CK)
Playbook Template
PLAYBOOK ID : PB-TXXX
TECHNIQUE : MITRE ID — Name
PRIORITY : Critical | High | Medium
DATA SOURCES : [Required telemetry]
HUNT QUERIES : [Query IDs from above]
BASELINE : [What normal looks like]
INDICATORS : [What adversary activity looks like]
FALSE POSITIVES : [Known benign triggers]
VALIDATION : [Confirmation steps]
ESCALATION : [Response actions]
DETECTION RULE : [Automated rule if hunt validates]
PB-T1059: Command and Scripting Interpreter
TECHNIQUE : T1059.001 (PowerShell), T1059.003 (Windows Command Shell)
PRIORITY : Critical
DATA SOURCES : Process creation (Sysmon 1), Script Block Logging (4104),
Module Logging (4103), PowerShell Transcription
HUNT QUERIES : HQ-KQL-001, HQ-KQL-002, HQ-SPL-001, HQ-EQL-001
BASELINE : Typical PowerShell usage patterns per device role (workstation
vs server), known automation scripts, SCCM/Intune deployments
INDICATORS :
- Encoded/obfuscated commands (-enc, -e, base64)
- Download cradles (IEX, Invoke-WebRequest, Net.WebClient)
- AMSI bypass attempts (amsiInitFailed, amsiContext)
- Unusual parent processes spawning powershell (explorer -> powershell with -enc)
- PowerShell running without powershell.exe (System.Management.Automation.dll
loaded by non-PowerShell process)
FALSE POSITIVES : SCCM scripts, Intune remediation, admin automation
VALIDATION : Decode encoded content, check script reputation, verify admin
ESCALATION : Isolate host, collect script block logs, check for persistence
DETECTION RULE : Alert on encoded PowerShell from non-admin context on workstations
PB-T1003: OS Credential Dumping
TECHNIQUE : T1003.001 (LSASS), T1003.002 (SAM), T1003.003 (NTDS),
T1003.006 (DCSync)
PRIORITY : Critical
DATA SOURCES : Sysmon 10 (ProcessAccess), Sysmon 1, Windows 4662/4663,
Directory Service Access (4662), Network (DCE/RPC)
HUNT QUERIES : HQ-KQL-014, HQ-KQL-015, HQ-KQL-016, HQ-KQL-018,
HQ-SPL-002, HQ-SPL-008
BASELINE : Only EDR/AV and WerFault should access LSASS; only DCs
should request directory replication; ntds.dit should only
be modified by ntdsai.dll
INDICATORS :
- Non-standard process accessing lsass.exe memory (GrantedAccess 0x1010/0x1fffff)
- comsvcs.dll MiniDump via rundll32
- Shadow copy creation followed by ntds.dit extraction
- Directory replication (GetNCChanges) from non-DC IP
- Mimikatz module names in command line (sekurlsa::, lsadump::)
- procdump.exe targeting lsass
FALSE POSITIVES : AV/EDR legitimate scans, WerFault crash dumps, scheduled AD backup
VALIDATION : Check if source is legitimate security tool, verify DC list,
inspect process chain
ESCALATION : Assume credential compromise, force password reset for affected
accounts, hunt for lateral movement with stolen creds
PB-T1021: Remote Services (Lateral Movement)
TECHNIQUE : T1021.001 (RDP), T1021.002 (SMB), T1021.006 (WinRM)
PRIORITY : High
DATA SOURCES : DeviceNetworkEvents, Windows 4624/4625 (LogonType 3/10),
Sysmon 3, Firewall/proxy logs
HUNT QUERIES : HQ-KQL-023, HQ-KQL-024, HQ-KQL-025, HQ-KQL-026
BASELINE : Normal RDP/SMB patterns per user role, known jump servers,
PAW-to-server connections, backup/monitoring systems
INDICATORS :
- New RDP connections from previously unseen source IPs
- Single device creating SMB sessions to 50+ hosts in 15 minutes
- PsExec named pipe creation (PSEXESVC, RemCom, csexec)
- WinRM connections from non-admin workstations
- Lateral movement chains (device A -> B -> C in short succession)
FALSE POSITIVES : Vulnerability scanners, backup software, SCCM, admin jump servers
VALIDATION : Correlate with authentication logs, verify source user/device,
check for prior credential theft indicators
ESCALATION : Isolate source device, reset source credentials, map full
lateral movement path, check each hop for persistence
PB-T1053: Scheduled Task/Job
TECHNIQUE : T1053.005 (Scheduled Task), T1053.003 (Cron)
PRIORITY : High
DATA SOURCES : Windows 4698/4702, Sysmon 1, DeviceProcessEvents,
cron file monitoring (Linux)
HUNT QUERIES : HQ-KQL-005, HQ-KQL-041, HQ-EQL-008, HQ-SPL-011
BASELINE : Known scheduled tasks per device role, Group Policy-deployed
tasks, software update tasks
INDICATORS :
- schtasks /create from cmd/powershell (not Group Policy)
- Task actions pointing to user-writable directories
- Task created outside business hours
- XML task definition referencing encoded commands or URLs
- Linux: new crontab entries referencing /tmp or download URLs
FALSE POSITIVES : Software installations, IT automation, patch management
VALIDATION : Verify task action binary, check creator context, review task XML
ESCALATION : Remove task, investigate binary, check if task has already executed
PB-T1547: Boot or Logon Autostart Execution
TECHNIQUE : T1547.001 (Registry Run Keys), T1547.009 (Shortcut Modification)
PRIORITY : High
DATA SOURCES : Sysmon 13, DeviceRegistryEvents, DeviceFileEvents
HUNT QUERIES : HQ-KQL-006, HQ-SPL-012
BASELINE : Known Run key entries per standard build, software-deployed entries
INDICATORS :
- New Run/RunOnce key pointing to non-Program Files paths
- Registry value set by unusual process (not msiexec, setup, explorer)
- .lnk files created in Startup folder by non-explorer processes
- Registry values containing encoded commands or download cradles
FALSE POSITIVES : Software installations, user-pinned applications
VALIDATION : Check referenced binary reputation and path, verify installer source
ESCALATION : Remove persistence entry, quarantine binary, investigate source
PB-T1071: Application Layer Protocol (C2)
TECHNIQUE : T1071.001 (Web Protocols), T1071.004 (DNS)
PRIORITY : Critical
DATA SOURCES : DeviceNetworkEvents, proxy logs, DNS logs, Sysmon 3/22
HUNT QUERIES : HQ-KQL-027, HQ-KQL-028, HQ-KQL-044, HQ-SPL-010
BASELINE : Normal outbound connection patterns per process, known
update/telemetry endpoints, CDN domains
INDICATORS :
- Periodic connections with low jitter (beaconing coefficient of variation < 0.1)
- Connections to IPs with low global prevalence (< 250)
- Non-browser processes making HTTP/HTTPS connections
- DNS queries with high subdomain entropy or length (> 30 chars)
- High TXT record query volumes to single domain
FALSE POSITIVES : Update services, health monitors, telemetry endpoints
VALIDATION : Jitter analysis, destination IP/domain reputation, process binary
reputation, pcap inspection if available
ESCALATION : Block C2 domain/IP, isolate host, begin full IR
PB-T1078: Valid Accounts
TECHNIQUE : T1078.001 (Default), T1078.002 (Domain), T1078.004 (Cloud)
PRIORITY : High
DATA SOURCES : Windows 4624/4625/4648, SigninLogs, AuditLogs, CloudTrail
HUNT QUERIES : HQ-KQL-034, HQ-KQL-036, HQ-KQL-037
BASELINE : Normal logon patterns per user (time, location, device, app)
INDICATORS :
- Logons from impossible travel locations
- Password spray patterns (many accounts, single IP, short window)
- MFA fatigue (5+ prompts in 10 minutes)
- Logon from TOR exit nodes or known VPN services
- Service account logons from unexpected sources
FALSE POSITIVES : Traveling users, VPN users, shared accounts
VALIDATION : Contact user, check VPN logs, review concurrent sessions
ESCALATION : Disable account, force password reset, revoke all sessions
PB-T1055: Process Injection
TECHNIQUE : T1055.001 (DLL Injection), T1055.003 (Thread Execution Hijacking),
T1055.012 (Process Hollowing)
PRIORITY : High
DATA SOURCES : Sysmon 8 (CreateRemoteThread), Sysmon 25 (ProcessTampering),
DeviceEvents, ETW
HUNT QUERIES : HQ-KQL-054
BASELINE : Very few legitimate processes use CreateRemoteThread; exceptions
include AV/EDR, input method editors, accessibility tools
INDICATORS :
- CreateRemoteThread from non-system process to system process
- Process hollowing (Sysmon Event 25)
- Unsigned DLL loaded into signed process
- Memory anomalies (RWX regions in unexpected processes)
FALSE POSITIVES : AV/EDR hooking, game anti-cheat, accessibility software
VALIDATION : Check source process reputation, analyze injected code if possible
ESCALATION : Collect memory dump, isolate host, investigate source binary
PB-T1218: System Binary Proxy Execution
TECHNIQUE : T1218.005 (Mshta), T1218.010 (Regsvr32), T1218.011 (Rundll32)
PRIORITY : High
DATA SOURCES : Process creation, network connections, Sysmon 1/3
HUNT QUERIES : HQ-KQL-003, HQ-KQL-004, HQ-EQL-005
BASELINE : Legitimate use of mshta (rare), rundll32 (common for control panel),
regsvr32 (software installation)
INDICATORS :
- Mshta with URLs or script content
- Rundll32 loading DLLs from user-writable paths
- Regsvr32 with /s /n /u /i:http patterns (Squiblydoo)
- Any of these making outbound network connections
FALSE POSITIVES : Legitimate COM registration, control panel applets
VALIDATION : Check DLL/HTA reputation, inspect network destinations
ESCALATION : Block URL/DLL, investigate payload, check for persistence
PB-T1562: Impair Defenses
TECHNIQUE : T1562.001 (Disable or Modify Tools)
PRIORITY : Critical
DATA SOURCES : DeviceProcessEvents, DeviceRegistryEvents, DeviceEvents
HUNT QUERIES : HQ-KQL-009, HQ-KQL-010, HQ-KQL-011
BASELINE : Defender configuration should only change via GPO/Intune;
event logs should never be cleared outside maintenance windows
INDICATORS :
- PowerShell Add-MpPreference/Set-MpPreference with exclusion parameters
- Registry modifications to DisableAntiSpyware, DisableRealtimeMonitoring
- wevtutil cl or Clear-EventLog commands
- Tampering with ETW providers
- Stopping/disabling security services
FALSE POSITIVES : IT deploying AV exclusions via SCCM (should be GPO-managed)
VALIDATION : Verify with IT/change management, check GPO vs local change
ESCALATION : Re-enable defenses, investigate why defenses were disabled,
assume compromise and hunt for concurrent malicious activity
PB-T1486: Data Encrypted for Impact
TECHNIQUE : T1486 (Ransomware Encryption)
PRIORITY : Critical
DATA SOURCES : DeviceFileEvents, DeviceProcessEvents, file system monitoring
HUNT QUERIES : HQ-KQL-031, HQ-KQL-032
BASELINE : Normal file modification rates per device, known backup
operations, known archive tools
INDICATORS :
- Mass file rename/modification (> 100 files in 5 minutes)
- Shadow copy deletion (always precedes encryption)
- New file extensions appearing across many files
- Ransom note file creation (readme.txt, DECRYPT*.txt, HOW_TO_RECOVER*)
- BCDEdit recovery disable commands
FALSE POSITIVES : Large file copy/move operations, archive extraction, batch rename
VALIDATION : Check file extension pattern, look for ransom note, verify
shadow copy status
ESCALATION : IMMEDIATELY isolate host, invoke IR plan, assess blast radius,
check for data exfiltration (double extortion)
PB-T1505: Server Software Component (Webshell)
TECHNIQUE : T1505.003 (Web Shell)
PRIORITY : Critical
DATA SOURCES : DeviceProcessEvents, web server logs, DeviceFileEvents
HUNT QUERIES : HQ-KQL-033, HQ-EQL-007
BASELINE : Web server processes should not spawn command interpreters;
web root directories should not have new executable content
INDICATORS :
- w3wp.exe/httpd/nginx/tomcat spawning cmd.exe, powershell.exe, bash
- New .aspx/.jsp/.php files in web root directories
- Web server process making unusual outbound connections
- File creation in web directories by non-deployment processes
FALSE POSITIVES : CGI scripts, legitimate PHP execution, CI/CD deployment
VALIDATION : Inspect web shell content, check deployment logs, verify
file hash against known good
ESCALATION : Remove webshell, patch entry vector, review web server logs
for all access to webshell URL, check for persistence
PB-T1036: Masquerading
TECHNIQUE : T1036.003 (Rename System Utilities), T1036.005 (Match Legitimate Name)
PRIORITY : High
DATA SOURCES : DeviceProcessEvents (OriginalFileName vs FileName), Sysmon 1
HUNT QUERIES : HQ-KQL-012
BASELINE : System binaries should match their OriginalFileName PE metadata
INDICATORS :
- FileName differs from ProcessVersionInfoOriginalFileName
- System binary names running from non-System32 paths
- Executables with system binary names but wrong hashes
FALSE POSITIVES : Renamed copies for testing (rare), some legitimate portable tools
VALIDATION : Compare hash to known good, check digital signature
ESCALATION : Quarantine binary, investigate how it arrived on system
PB-T1566: Phishing
TECHNIQUE : T1566.001 (Spearphishing Attachment), T1566.002 (Link)
PRIORITY : High
DATA SOURCES : Email logs, DeviceProcessEvents, DeviceFileEvents
HUNT QUERIES : HQ-KQL-051, HQ-EQL-002
BASELINE : Office applications should rarely spawn scripting engines;
macro execution should be limited by policy
INDICATORS :
- Office app spawning cmd/powershell/mshta/wscript/certutil
- Office app creating executable files
- Email with attachment from new/rare sender domain
- URL clicks leading to file downloads within minutes of email receipt
FALSE POSITIVES : Legitimate macros (should be signed and whitelisted)
VALIDATION : Check email headers, analyze attachment in sandbox, verify sender
ESCALATION : Block sender domain, quarantine email, check all recipients
PB-T1105: Ingress Tool Transfer
TECHNIQUE : T1105 (Remote File Copy)
PRIORITY : High
DATA SOURCES : DeviceProcessEvents, DeviceNetworkEvents, proxy logs
HUNT QUERIES : HQ-KQL-045, HQ-KQL-046, HQ-SPL-004
BASELINE : Legitimate software distribution channels, SCCM/Intune,
known download tools
INDICATORS :
- certutil -urlcache -split -f http://
- bitsadmin /transfer or /addfile with external URLs
- PowerShell Invoke-WebRequest/wget/curl to suspicious domains
- Process downloading then executing from same directory
FALSE POSITIVES : Admin scripts using certutil for cert operations, BITS for updates
VALIDATION : Check downloaded file hash/reputation, inspect URL
ESCALATION : Block URL, quarantine downloaded file, investigate execution chain
PB-T1543: Create or Modify System Process
TECHNIQUE : T1543.003 (Windows Service)
PRIORITY : High
DATA SOURCES : Windows 7045, DeviceRegistryEvents, Sysmon 13
HUNT QUERIES : HQ-KQL-007, HQ-SPL-005
BASELINE : Known services per device role, GPO-deployed services
INDICATORS :
- New service with ImagePath outside Windows/Program Files
- Service binary in temp/user directories
- Service command line containing cmd/powershell
- Service installed by non-installer process
FALSE POSITIVES : Software installations, driver installations
VALIDATION : Verify service binary, check installer chain, compare to baseline
ESCALATION : Stop/remove service, quarantine binary, investigate installer
PB-T1070: Indicator Removal
TECHNIQUE : T1070.001 (Clear Windows Event Logs), T1070.004 (File Deletion),
T1070.006 (Timestomp)
PRIORITY : High
DATA SOURCES : Windows 1102, DeviceProcessEvents, DeviceFileEvents
HUNT QUERIES : HQ-KQL-011, HQ-KQL-013
BASELINE : Event logs should never be cleared outside planned maintenance;
timestomping should not occur in normal operations
INDICATORS :
- wevtutil cl Security / Clear-EventLog
- Event ID 1102 (audit log cleared)
- Timestamp modification on recently created files
- Bulk file deletion in staging/exfil directories
FALSE POSITIVES : Planned log rotation (should be automated, not manual)
VALIDATION : Check who cleared logs, correlate timeline with other events
ESCALATION : Assume attacker covering tracks, escalate to full IR,
recover logs from SIEM (already forwarded)
PB-T1190: Exploit Public-Facing Application
TECHNIQUE : T1190
PRIORITY : Critical
DATA SOURCES : WAF logs, web server access logs, DeviceProcessEvents,
vulnerability scanner data
HUNT QUERIES : HQ-KQL-033 (webshell as post-exploitation indicator)
BASELINE : Known web application behavior, expected HTTP methods,
normal response code distribution
INDICATORS :
- Spike in 500 errors from single source IP
- Known exploit path patterns in URL (Log4Shell, ProxyShell, Confluence CVEs)
- Web server spawning unexpected processes post-request
- New files created in web-accessible directories
FALSE POSITIVES : Vulnerability scanners (should be whitelisted by source IP)
VALIDATION : Cross-reference with CVE databases, check if patch is applied,
inspect web server process tree
ESCALATION : Emergency patch, WAF rule deployment, check for post-exploitation
PB-T1219: Remote Access Software
TECHNIQUE : T1219
PRIORITY : High
DATA SOURCES : DeviceProcessEvents, DeviceNetworkEvents, software inventory
HUNT QUERIES : HQ-KQL-030
BASELINE : Approved remote access tools per organization policy
INDICATORS :
- Unapproved RMM tools (AnyDesk, TeamViewer, RustDesk, ScreenConnect,
Splashtop, NetSupport, ConnectWise) on endpoints
- RMM tools on servers (unusual)
- Multiple different RMM tools on single endpoint
- RMM tools appearing for first time in environment
FALSE POSITIVES : IT-approved remote support tools (should be in allowlist)
VALIDATION : Check if tool is approved, verify who installed it
ESCALATION : Remove unauthorized tool, investigate installation source,
check if tool was used for data access
PB-T1048: Exfiltration Over Alternative Protocol
TECHNIQUE : T1048.001 (Encrypted), T1048.003 (Unencrypted)
PRIORITY : High
DATA SOURCES : DNS logs, network flow data, proxy logs, DeviceNetworkEvents
HUNT QUERIES : HQ-KQL-044, HQ-KQL-050
BASELINE : Normal DNS query patterns, normal outbound data volumes per
device role, approved file sharing services
INDICATORS :
- DNS queries with unusually long subdomains (> 30 chars)
- High volume of DNS TXT queries to single domain
- Large outbound transfers to cloud storage (mega.nz, anonfiles, etc.)
- Non-standard protocol usage on standard ports
FALSE POSITIVES : CDN traffic, legitimate cloud storage usage, DKIM queries
VALIDATION : Decode DNS payload, check destination reputation, correlate
with data access events
ESCALATION : Block exfil channel, assess data loss scope, invoke breach
notification process if PII involved
Hunting Maturity Model
HMM Levels (Sqrrl Framework)
| Level | Name | Description | Capabilities |
|---|---|---|---|
| HM0 | Initial | Relies primarily on automated alerting | SIEM with vendor rules, no custom hunting |
| HM1 | Minimal | Can use threat intel IOCs to search | IOC searches in SIEM, basic log analysis |
| HM2 | Procedural | Follows documented hunting procedures | Uses published hunting playbooks, understands data sources |
| HM3 | Innovative | Creates new hunting procedures | Develops original hypotheses, creates custom analytics |
| HM4 | Leading | Automates successful hunts, advances the field | Full hypothesis-driven program, detection-as-code pipeline |
Maturity Progression Checklist
[ ] HM0 -> HM1
- Deploy Sysmon with SwiftOnSecurity or Olaf Hartong config
- Enable PowerShell Script Block Logging (4104)
- Forward Windows Security + Sysmon to SIEM
- Create IOC search capability in SIEM
[ ] HM1 -> HM2
- Adopt published hunting playbooks (ThreatHunter-Playbook, Sigma)
- Establish weekly hunting cadence
- Document hunts with hypothesis template
- Build data source inventory and gap analysis
[ ] HM2 -> HM3
- Develop original hunting hypotheses from threat intel
- Create custom analytics based on environmental baselines
- Integrate purple team exercises into hunting program
- Establish metrics (hunts/month, findings/hunt, time-to-detection)
[ ] HM3 -> HM4
- Automate validated hunts into production detection rules
- Implement detection-as-code pipeline (Sigma -> SIEM)
- Contribute back to community (publish rules, share TTPs)
- Continuous ATT&CK coverage mapping and gap remediation
- ML/statistical anomaly detection augmenting rule-based hunting
Source Attribution
Repositories Referenced
| Source | Content Used | License |
|---|---|---|
| ThreatHunter-Playbook | Hunting methodology framework, hypothesis-driven approach | MIT |
| FalconFriday | KQL detections (0xFF series), MDE hunting queries | BSD-3 |
| Bert-JanP/Hunting-Queries-Detection-Rules | 85+ KQL queries for MDE/Sentinel, beaconing, RAT/RMM, credential, SMB, webshell | MIT |
| reprise99/Sentinel-Queries | Azure AD/Sentinel KQL categories and patterns | MIT |
| SigmaHQ/sigma | Sigma detection rules (process creation YAML), cross-platform rule format | LGPL-2.1 |
| Splunk Security Content | SPL analytic stories (credential dumping, defense evasion), 25+ detection rules | Apache-2.0 |
| Elastic Detection Rules | EQL rule structure, detection-as-code pipeline | Elastic-2.0 |
| Azure-Sentinel Hunting Queries | 29 hunting query categories by data source | MIT |
| Microsoft-365-Defender-Hunting-Queries | M365 Defender KQL categories (archived -> Azure-Sentinel) | MIT |
| A3sal0n/CyberThreatHunting | Hunting tools (Velociraptor, osquery, GRR, Chainsaw), data source inventory | — |
| The DFIR Report | Real-world intrusion TTPs, ransomware playbooks (LockBit, Akira, RansomHub) | — |
Key Tool References
| Tool | Hunting Use |
|---|---|
| Sysmon | Foundation telemetry (process, network, file, registry, DNS) |
| Velociraptor | Endpoint artifact collection and live hunting |
| osquery | SQL-based endpoint state queries |
| Chainsaw | Rapid EVTX artifact search and Sigma rule matching |
| KAPE | Artifact collection for DFIR |
| Sigma CLI | Rule conversion across SIEM platforms |
| ATT&CK Navigator | Coverage visualization and gap analysis |
Training module compiled from 13 open-source repositories and community resources. Queries tested against MDE/Sentinel schema conventions. All Sigma rules follow SigmaHQ specification v2.