Playbooks
TA0043Threat Hunting
What threat hunting is, how it differs from alert triage, the hypothesis-driven hunting loop that analysts follow, specific KQL/SPL hunting queries, and how to turn hunting findings into automated detections.
View on Graph
What Threat Hunting Is and How It Differs From Alert Triage
- Threat hunting is the proactive, analyst-driven search for threats that have evaded existing security controls and detection rules.
- Alert triage is reactive: an alert fires, an analyst investigates, the alert dictates the starting point.
- Threat hunting is proactive - the hunter forms a hypothesis about what an adversary might be doing in the network and searches for supporting evidence across logs, endpoints, and network telemetry without any alert to guide them.
- The hunting loop: Hypothesis → Research → Query → Analyze → Document → Automate
The Hunting Loop
Step 1: Form a Hypothesis
A hypothesis should be specific, testable, and based on real threat intelligence or observed gaps.
| Good Hypotheses | Bad Hypotheses |
|---|---|
| ”Attackers might be using PowerShell encoded commands to bypass AppLocker" | "Let me check if we are compromised" |
| "Ransomware groups targeting our sector use Cobalt Strike over HTTPS to port 443" | "Let me look at all the logs" |
| "We have no detection for service binary hijacking - let me search for services pointing to user-writable paths" | "I’m going to find the bad stuff” |
Step 2: Gather Data
For each hypothesis, identify the data sources needed:
| Hypothesis | Data Sources Needed | Key Events |
|---|---|---|
| PowerShell encoded commands | Windows Event 4103/4104 (PowerShell), Sysmon Event 1 | -EncodedCommand, -ExecutionPolicy Bypass, $env:APPDATA |
| Cobalt Strike beaconing | Network logs (proxy, firewall), DNS logs, Sysmon Event 22 | HTTPS to unknown IPs, JA3 signature patterns, DNS queries at regular intervals — correlate with KQL hunting queries |
| Service binary hijacking | Sysmon Event 1, Windows Event 4697/7045 | Service binary from %TEMP%, %APPDATA%, user-writable paths |
| LSASS credential dumping | Sysmon Event 10 (Process Access), Event 4663 | Non-LSASS process with PROCESS_ALL_ACCESS to lsass.exe |
Step 3: Execute the Hunt
Now run specific queries. Below are production-ready hunting queries for common hypotheses.
Hunting Hypothesis 1: PowerShell Encoded Command Execution
Hypothesis: Attackers are using PowerShell with -EncodedCommand to execute payloads without writing files to disk.
SPL query:
index=windows sourcetype=WinEventLog:Sysmon EventCode=1
| search Image="*powershell.exe" CommandLine="*-EncodedCommand*"
| eval decoded_cmd_len = len(split(CommandLine, "-EncodedCommand")[1])
| where decoded_cmd_len > 50
| stats count, values(Computer) as Systems, values(User) as Users by CommandLine, ParentImage
| eval alert = "POWERSHELL ENCODED COMMAND - base64 payload of " . decoded_cmd_len . " chars from " . mvjoin(Users, ", ") . " on " . mvjoin(Systems, ", ")
| table _time, Systems, Users, CommandLine, ParentImage, decoded_cmd_len, alert
| sort - count
SPL query - hunt for PowerShell downloading payloads:
index=windows sourcetype=WinEventLog:Sysmon EventCode=3
| search Image="*powershell.exe" DestinationPort IN (80, 443)
| stats count by Image, CommandLine, DestinationIp, DestinationPort
| eval alert = "PowerShell making outbound connections - possible download cradle"
| table _time, Image, CommandLine, DestinationIp, DestinationPort, count, alert
KQL query - PowerShell hunting:
DeviceProcessEvents
| where FileName startswith "powershell"
| where ProcessCommandLine contains "-EncodedCommand" or ProcessCommandLine contains "IEX" or ProcessCommandLine contains "DownloadString"
| where ProcessCommandLine contains "http"
| project Timestamp, DeviceName, AccountName, ProcessCommandLine
Hunting Hypothesis 2: Lateral Movement via WMI or PSExec
Hypothesis: Attackers are moving laterally using WMI (wmic.exe, Invoke-WmiMethod) or PSExec (psexec.exe), which does not write files to disk on the target.
SPL query - WMI process creation from remote:
index=windows sourcetype=WinEventLog:Sysmon EventCode=1
| search Image="*wmiprvse.exe"
| stats count, values(CommandLine) as Commands, values(ParentImage) as Parents by Computer
| where count > 1 AND mvcount(Commands) > 1
| eval alert = "LATERAL MOVEMENT - WMI process creation (wmiPrvSE.exe) spawning shell commands from " . Computer
| table _time, Computer, Commands, Parents, count, alert
SPL query - detect PSExec service installation:
index=windows sourcetype=WinEventLog:Security EventCode=4697
| search ServiceName="*PSEXESVC*"
| eval alert = "LATERAL MOVEMENT - PSExec service installed - remote command execution"
| table _time, Computer, SubjectUserName, ServiceName, ServiceFileName, alert
Hunting Hypothesis 3: Unusual Scheduled Task Patterns
Hypothesis: Attackers are creating scheduled tasks for persistence or lateral movement.
SPL query - scheduled task creation from non-admin tools:
index=windows sourcetype=WinEventLog:Security EventCode=4698
| search SubjectUserName!="*$" AND TaskContent="*cmd*" OR TaskContent="*powershell*" OR TaskContent="*wscript*"
| stats count by Computer, SubjectUserName, TaskName, TaskContent
| eval alert = "Scheduled task with shell command created by " . SubjectUserName . " on " . Computer
| table _time, Computer, SubjectUserName, TaskName, TaskContent, alert
SPL query - high-frequency scheduled tasks (potential C2 beacon disguised as task):
index=windows sourcetype=WinEventLog:Security EventCode=106 (Task Trigger Registered)
| search TaskName="*\\*" TaskTrigger="*Repetition*"
| eval alert = "Repetitive scheduled task - possible persistence mechanism"
| table _time, Computer, TaskName, TaskTrigger, alert
Hunting Hypothesis 4: Unusual Service Binary Paths
Hypothesis: Attackers have installed services pointing to user-writable directories for persistence or privilege escalation.
SPL query - hunt for services from user-writable paths:
index=windows sourcetype=WinEventLog:Security EventCode=4697
| search ServiceFileName="*\\Users\\*" OR ServiceFileName="*\\Temp\\*" OR ServiceFileName="*\\AppData\\*" OR ServiceFileName="*\\Desktop\\*"
| eval alert = "SERVICE HIJACK - service binary in user-writable path: " . ServiceFileName
| table _time, Computer, SubjectUserName, ServiceName, ServiceFileName, alert
Hunting Hypothesis 5: DNS Tunneling Indicators
Hypothesis: Data is being exfiltrated via DNS tunneling (TX T record queries with long subdomains).
SPL query - hunt for DNS tunneling:
index=dns sourcetype=dns_logs
| eval subdomain_len = len(split(query, ".")[0])
| where subdomain_len > 30
| stats count, values(query_type) as QueryTypes by src_ip, query
| where mvcount(QueryTypes) > 2 OR count > 50
| eval alert = "DNS TUNNELING - host " . src_ip . " made " . count . " queries with subdomains > 30 chars"
| table _time, src_ip, query, QueryTypes, count, alert
| sort - count
Hunting Hypothesis 6: Unusual Outbound Traffic Patterns
Hypothesis: Compromised hosts are beaconing to C2 infrastructure with consistent intervals and payload sizes.
SPL query - hunt for beaconing patterns:
index=proxy sourcetype=access_combined
| search dest_port=443
| stats earliest(_time) as first_seen, latest(_time) as last_seen, count by src_ip, dest_ip
| eval duration = last_seen - first_seen
| eval connections_per_hour = if(duration > 0, (count / (duration / 3600)), 0)
| where connections_per_hour > 10 AND connections_per_hour < 100 (beaconing: 10+ per hour but not constant streaming)
| eval alert = "BEACONING - host " . src_ip . " made " . count . " connections to " . dest_ip . " in " . tostring(duration/3600, "0.0") . " hours (" . tostring(connections_per_hour, "0.0") . "/hour)"
| table _time, src_ip, dest_ip, count, connections_per_hour, alert
Hunting Hypothesis 7: Unusual Logon Patterns
Hypothesis: An attacker is using compromised credentials to log in at unusual times or from unusual workstations.
SPL query - hunt for after-hours logins:
index=windows sourcetype=WinEventLog:Security EventCode=4624 LogonType=2
| eval login_hour = strftime(_time, "%H")
| where login_hour < 6 OR login_hour > 18 (after 6 PM or before 6 AM)
| stats count by AccountName, Computer, login_hour
| where count > 3
| eval alert = "After-hours logon by " . AccountName . " - " . count . " logins between hour " . login_hour
| table _time, AccountName, Computer, login_hour, count, alert
SPL query - hunt for workstation-to-workstation logins (lateral movement):
index=windows sourcetype=WinEventLog:Security EventCode=4624 LogonType=3
| search WorkstationName=Computer (same machine)
| stats count by AccountName, Computer, WorkstationName, SourceNetworkAddress
| where count > 1 AND SourceNetworkAddress != "-" AND SourceNetworkAddress != Computer
| eval alert = "LATERAL MOVEMENT - " . AccountName . " logged into " . Computer . " from " . SourceNetworkAddress
| table _time, AccountName, Computer, SourceNetworkAddress, count, alert
Automating Hunting Findings
When you find a pattern during hunting, the final step is turning it into an automated detection:
| Hunting Finding | Missing Detection | New Rule Type |
|---|---|---|
| Found PowerShell encoded commands executing from Office macros | No rule for PowerShell from winword.exe or excel.exe parent | Sysmon rule: Parent=Office + Child=powershell.exe + CommandLine=-EncodedCommand |
| Found scheduled tasks created by standard users | No alert on Task Creation Event 4698 from non-admin users | SIEM correlation: Event 4698 with user not in Admin group |
| Found service binary hijack on three servers | No baseline for expected service binaries | SIEM correlation: Event 4697 with ServiceFile in user-writable path |
Found DNS queries to .xyz TLD from development machines | No block/alert for anomalous TLD queries | DNS sinkhole + SIEM alert for .xyz TLD from non-browser processes |
Related
- Threat Intelligence Fundamentals — detection and response for T1598 techniques
- Insider Threat — detection and response for T1078 techniques
- Active Directory Compromise Response — detection and response for T1558 techniques
- Business Email Compromise Response — detection and response for T1566, T1114, T1098, T1586 techniques
