Incident Response and Threat Hunting
Incident response is structured investigation: from an alert or tip, reconstruct what happened, determine scope, and drive remediation. Threat hunting is proactive: given a hypothesis about attacker behavior, search logs for evidence of that behavior without a triggering alert. Both skills require fluency in the same data sources — process creation, network, registry, file, and authentication events — and the same analytical tool: KQL or SPL queries that trace a behavior backward and forward in time from a pivot point.
Alert fires: MDE detected a suspicious PowerShell encoded command on WORKSTATION-42 at 14:32. The user claims they did nothing. You have 30 minutes to determine: was this a true positive, what was the full attack chain, are other hosts compromised, and does the attacker still have access?
Incident Response Phases
Initial Triage Queries
// MDE KQL: 30-minute triage on WORKSTATION-42 after PowerShell alert
let targetHost = "WORKSTATION-42";
let alertTime = datetime(2026-09-18 14:32:00);
let window = 2h;
// 1. What ran around the alert time?
DeviceProcessEvents
| where DeviceName == targetHost
| where Timestamp between ((alertTime - window) .. (alertTime + window))
| project Timestamp, AccountName, FileName, ProcessCommandLine, InitiatingProcessFileName
| order by Timestamp asc
// 2. Network connections around alert time
DeviceNetworkEvents
| where DeviceName == targetHost
| where Timestamp between ((alertTime - 30m) .. (alertTime + 1h))
| where RemotePort !in (80, 443, 53, 137, 138, 139, 445)
| project Timestamp, RemoteIP, RemotePort, RemoteUrl, InitiatingProcessFileName
// 3. Files created (payload drops)
DeviceFileEvents
| where DeviceName == targetHost
| where Timestamp between ((alertTime - 30m) .. (alertTime + 2h))
| where ActionType == "FileCreated"
| where FolderPath !startswith @"C:\Windows\Prefetch"
| project Timestamp, FileName, FolderPath, InitiatingProcessFileName, SHA256
// 4. Registry modifications (persistence)
DeviceRegistryEvents
| where DeviceName == targetHost
| where Timestamp between ((alertTime - 30m) .. (alertTime + 2h))
| where RegistryKey contains_any ("Run", "Services", "Startup", "Winlogon")
| project Timestamp, RegistryKey, RegistryValueName, RegistryValueData
// 5. Logon events (credential use / lateral movement)
DeviceLogonEvents
| where DeviceName == targetHost
| where Timestamp between ((alertTime - 1h) .. (alertTime + 2h))
| where LogonType in (3, 10) // network + remote interactive
| project Timestamp, AccountName, LogonType, RemoteIP, AuthenticationPackage
Threat Hunting Methodology
// HYPOTHESIS-DRIVEN HUNTING:
// Hypothesis: An attacker used WMI for lateral movement and established persistence
// via a WMI subscription, evading scheduled-task-based detection.
// Data needed: WMI activity logs (EID 5861), process trees from WmiPrvSE.exe
// Query: hunt for all hosts with WmiPrvSE spawning suspicious children
// Hunt query 1: WMI-spawned commands in last 7 days
DeviceProcessEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName =~ "WmiPrvSE.exe"
| where FileName in~ ("cmd.exe","powershell.exe","wscript.exe","mshta.exe","cscript.exe","regsvr32.exe")
| summarize count(), commands=makeset(ProcessCommandLine, 5) by DeviceName, FileName
| order by count_ desc
// Hunt query 2: Kerberoasting hunt — all RC4 TGS-REPs for service accounts
IdentityLogonEvents
| where Timestamp > ago(30d)
| where Protocol == "Kerberos" and EncryptionType == "RC4-HMAC"
| where not(AccountName endswith "$") // exclude computer accounts
| summarize count(), first_seen=min(Timestamp), source_hosts=dcount(IPAddress)
by AccountName, TargetDeviceName
| where count_ > 2
| order by count_ desc
// Hunt query 3: Beaconing detection — regular outbound connection intervals
DeviceNetworkEvents
| where Timestamp > ago(24h)
| where InitiatingProcessFileName !in~ ("svchost.exe","MsMpEng.exe","chrome.exe","msedge.exe")
| summarize intervals=make_list(Timestamp, 1000), count_=count()
by DeviceName, RemoteIP, InitiatingProcessFileName
| where count_ between (10 .. 500)
// Add jitter analysis: compute standard deviation of intervals; low StdDev = beaconing
Timeline Reconstruction
// Unified timeline: merge process, file, network, registry, logon events by timestamp
let Host = "WORKSTATION-42";
let Start = datetime(2026-09-18 13:00:00);
let End = datetime(2026-09-18 17:00:00);
union
(DeviceProcessEvents
| where DeviceName == Host and Timestamp between (Start .. End)
| project Timestamp, Type="Process", Detail=strcat(FileName, " | ", ProcessCommandLine)),
(DeviceNetworkEvents
| where DeviceName == Host and Timestamp between (Start .. End)
| project Timestamp, Type="Network", Detail=strcat(RemoteIP, ":", tostring(RemotePort), " | ", InitiatingProcessFileName)),
(DeviceFileEvents
| where DeviceName == Host and Timestamp between (Start .. End)
| where ActionType == "FileCreated"
| project Timestamp, Type="File", Detail=strcat(FolderPath, "\\", FileName)),
(DeviceRegistryEvents
| where DeviceName == Host and Timestamp between (Start .. End)
| project Timestamp, Type="Registry", Detail=strcat(RegistryKey, " = ", RegistryValueData)),
(DeviceLogonEvents
| where DeviceName == Host and Timestamp between (Start .. End)
| project Timestamp, Type="Logon", Detail=strcat(AccountName, " type=", tostring(LogonType), " from=", RemoteIP))
| order by Timestamp asc
IOC Pivoting
| Starting IOC | Pivot query | What it finds |
|---|---|---|
| IP address 1.2.3.4 | DeviceNetworkEvents | where RemoteIP == "1.2.3.4" | All hosts that connected to C2 |
| File SHA256 | DeviceFileEvents | where SHA256 == "..." | All hosts with the same binary |
| Username | DeviceLogonEvents | where AccountName == "..." | All hosts the user authenticated to |
| Parent process name | DeviceProcessEvents | where InitiatingProcessFileName == "..." | All children of the suspicious parent |
| Registry key | DeviceRegistryEvents | where RegistryKey has "..." | All hosts with that persistence key |
| Domain in DNS query | DeviceNetworkEvents | where RemoteUrl has "c2domain" | Full network scope of C2 usage |
Q&A
During threat hunting, you find beaconing behavior in DNS — a workstation making a query to the same domain every 60 seconds for 8 hours. The domain resolves to a legitimate CDN IP. How do you determine whether this is malicious C2 or legitimate software telemetry, and what additional evidence would drive a containment decision?
Regular high-frequency DNS queries to a legitimate CDN IP is a classic C2 evasion pattern: the attacker fronts their C2 through a CDN provider (Cloudflare, Azure Front Door, Fastly) so the resolved IP is shared across thousands of legitimate domains. The IP by itself is not indicative. The determination requires investigation along three axes.
First, identify the domain behind the CDN query. Use passive DNS or perform the resolution in a sandbox to get the domain. Then query VirusTotal, Shodan, or WHOIS for registration age, registrar, and community detections. A domain registered within the last 60 days with a privacy-protected registrar and no historical DNS resolutions is suspicious regardless of what IP it resolves to today. A domain that is three years old with hundreds of DNS resolvers reporting legitimate categories is likely legitimate software telemetry.
Second, identify the process making the queries. DeviceNetworkEvents | where RemoteUrl has "domain.example" | project InitiatingProcessFileName, ProcessCommandLine reveals whether it is a known application (Chrome, Windows Update, Defender) or an unknown binary. For an unknown process, check its file hash against VirusTotal and examine its parent process chain — where did it come from, who created it? A binary that is unsigned, located in %APPDATA%, and spawned by powershell.exe -enc is high confidence C2 regardless of CDN fronting.
The containment decision is driven by the combination: (1) unknown or recently-dropped binary + (2) newly-registered or low-reputation domain + (3) regular interval (low jitter) consistent with beacon sleep = isolate and collect. If process is a known vendor binary with digital signature and the domain is old and reputable, the behavior is likely telemetry and should be added to a hunting exclusion list. The key data point that drives containment over exclusion is the process identity — CDN fronting can deceive network-layer analysis, but the endpoint process chain cannot be spoofed without a separate endpoint compromise.