Building an IOC Hunt in Microsoft Defender XDR.
One hash appeared on one device.
Then the same domain appeared in network telemetry.
One clue became an enterprise-wide hunt.
Agent Foskett followed the indicators.
Lesson overview
Learn how defenders build an IOC hunt by searching for malicious hashes, file names, IP addresses, domains, URLs, senders and accounts across Microsoft Defender XDR telemetry.
Why IOC hunting matters
The IOC hunt workflow
Step 1 — Hunt for a known file hash
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
let IocHash = "REPLACE_WITH_SHA256";
DeviceFileEvents
| where Timestamp > ago(30d)
| where SHA256 == IocHash or SHA1 == IocHash
| project Timestamp,
DeviceName,
InitiatingProcessAccountUpn,
FileName,
FolderPath,
SHA1,
SHA256,
InitiatingProcessFileName
| order by Timestamp desc
Step 2 — Hunt for suspicious file names and process execution
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
let SuspiciousFileNames = dynamic(["invoice.exe", "update.js", "payload.dll"]);
DeviceProcessEvents
| where Timestamp > ago(30d)
| where FileName in~ (SuspiciousFileNames)
or ProcessCommandLine has_any (SuspiciousFileNames)
| project Timestamp,
DeviceName,
AccountUpn,
FileName,
ProcessCommandLine,
InitiatingProcessFileName
| order by Timestamp desc
Step 3 — Hunt for suspicious domains and URLs
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
let IocDomains = dynamic(["example-bad-domain.com", "login-update.example"]);
DeviceNetworkEvents
| where Timestamp > ago(30d)
| where RemoteUrl has_any (IocDomains)
| project Timestamp,
DeviceName,
InitiatingProcessAccountUpn,
InitiatingProcessFileName,
RemoteUrl,
RemoteIP
| order by Timestamp desc
Step 4 — Hunt for suspicious IP addresses
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
let IocIPs = dynamic(["203.0.113.10", "198.51.100.25"]);
DeviceNetworkEvents
| where Timestamp > ago(30d)
| where RemoteIP in (IocIPs)
| project Timestamp,
DeviceName,
InitiatingProcessAccountUpn,
InitiatingProcessFileName,
RemoteIP,
RemotePort,
ActionType
| order by Timestamp desc
Step 5 — Hunt through URL click evidence
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
let IocUrls = dynamic(["https://example-bad-domain.com/login"]);
UrlClickEvents
| where Timestamp > ago(30d)
| where Url has_any (IocUrls) or UrlChain has_any (IocUrls)
| project Timestamp,
AccountUpn,
Url,
UrlChain,
ActionType,
IsClickedThrough,
NetworkMessageId
| order by Timestamp desc
Step 6 — Summarise IOC hunt results
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
let IocDomain = "example-bad-domain.com";
DeviceNetworkEvents
| where Timestamp > ago(30d)
| where RemoteUrl contains IocDomain
| summarize FirstSeen=min(Timestamp),
LastSeen=max(Timestamp),
Devices=dcount(DeviceName),
DeviceList=make_set(DeviceName),
Accounts=make_set(InitiatingProcessAccountUpn)
by RemoteUrl
| order by Devices desc
How to read IOC hunt evidence
Real-world investigation
Investigation checklist
Related Agent Foskett Academy lessons
Coming next
Final thought
Building an IOC Hunt in Microsoft Defender XDR
Agent Foskett Academy Lesson 88 teaches defenders how to build an IOC hunt in Microsoft Defender XDR.
IOC hunt investigation workflow
This lesson explains how DeviceFileEvents, DeviceProcessEvents, DeviceNetworkEvents, EmailEvents, UrlClickEvents and IdentityLogonEvents help defenders hunt for malicious hashes, file names, IP addresses, domains, URLs, senders and accounts across the environment.
