Advanced Hunting in Defender XDR
Turn your KQL skills into real threat hunting. Learn how to write Advanced Hunting queries that detect threats across endpoints, email, identity, and cloud apps in the Defender XDR unified hunting experience.
What is Advanced Hunting?
Advanced Hunting is your search engine for security data in Defender XDR. You write KQL queries and get answers across endpoints, emails, identities, and cloud apps β all from one place.
Unlike analytics rules (which detect known patterns automatically), hunting is proactive. You are the one asking the questions: βHas anyone in the org been contacted by this phishing domain?β or βAre there any devices running processes from temp folders?β
When your hunting query finds something valuable, you can save it as a custom detection rule (Module 9) so it runs automatically from now on.
Hunting patterns: real-world queries
Pattern 1: Living off the land (LOLBins)
Attackers use legitimate Windows tools for malicious purposes. Hunt for unusual parent-child process relationships:
DeviceProcessEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName in ("winword.exe", "excel.exe", "powerpnt.exe")
| where FileName in ("powershell.exe", "cmd.exe", "mshta.exe", "wscript.exe", "cscript.exe")
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName, FileName, ProcessCommandLine
| sort by Timestamp desc
What this finds: Office applications spawning command interpreters β a strong indicator of macro-based malware.
Pattern 2: Credential theft indicators
DeviceProcessEvents
| where Timestamp > ago(24h)
| where FileName in ("mimikatz.exe", "procdump.exe", "sekurlsa.exe")
or ProcessCommandLine has_any ("sekurlsa", "lsadump", "kerberos::list", "privilege::debug")
| project Timestamp, DeviceName, AccountName, FileName, ProcessCommandLine
What this finds: Known credential dumping tools and command-line indicators.
Pattern 3: Phishing campaign scope
EmailEvents
| where Timestamp > ago(48h)
| where SenderFromAddress =~ "hr-updates@pacificmeridian-careers.com"
| summarize
TotalEmails = count(),
Recipients = make_set(RecipientEmailAddress),
Delivered = countif(DeliveryAction == "Delivered"),
Blocked = countif(DeliveryAction == "Blocked")
| extend RecipientCount = array_length(Recipients)
What this finds: The full scope of a phishing campaign β how many emails, to whom, and how many got through.
Pattern 4: Lateral movement via RDP
DeviceLogonEvents
| where Timestamp > ago(7d)
| where LogonType == "RemoteInteractive"
| where IsLocalAdmin == true
| summarize
RDPSessions = count(),
SourceDevices = make_set(RemoteDeviceName)
by DeviceName, AccountName
| where RDPSessions > 5
| sort by RDPSessions desc
What this finds: Devices with unusually high admin RDP sessions β a lateral movement indicator.
Pattern 5: Cross-domain hunting (email to endpoint)
let PhishingUrls =
EmailUrlInfo
| where Timestamp > ago(48h)
| where UrlDomain == "evil-login.com"
| distinct Url;
DeviceNetworkEvents
| where Timestamp > ago(48h)
| where RemoteUrl in (PhishingUrls)
| project Timestamp, DeviceName, AccountName, RemoteUrl
What this finds: Devices that visited a phishing URL found in emails β connecting the email attack vector to endpoint compromise.
Exam tip: cross-table joins
Cross-domain hunting (combining email + endpoint, or identity + endpoint data) is a key exam topic. The let statement creates a variable holding results from one table, which you then use to filter another table.
This is the power of Defender XDRβs unified hunting β you can trace an attack from the phishing email through the endpoint compromise in a single query.
The hunting workflow
| Step | What You Do | Example |
|---|---|---|
| 1. Hypothesis | Form a question based on threat intel, incident learning, or MITRE technique | βAre there signs of Kerberoasting in our environment?β |
| 2. Query | Write KQL to search for evidence | Query IdentityQueryEvents for abnormal TGS requests |
| 3. Analyse | Review results β separate signal from noise | Filter out service accounts that normally make TGS requests |
| 4. Refine | Narrow the query to reduce false positives | Add exclusions for known legitimate behaviour |
| 5. Detect | Save as custom detection rule if the hunt finds a repeatable pattern | Create hourly detection for Kerberoasting indicators |
Scenario: Tyler hunts for data exfiltration at CipherStack
Tyler hypothesises that an attacker may be exfiltrating code via DNS tunnelling (encoding data in DNS queries to bypass firewalls).
Hunting query:
DeviceNetworkEvents
| where Timestamp > ago(7d)
| where RemotePort == 53
| extend DomainLength = strlen(RemoteUrl)
| where DomainLength > 50 // DNS tunnelling uses very long domain names
| summarize
LongDnsQueries = count(),
AvgLength = avg(DomainLength),
SampleDomains = make_set(RemoteUrl, 5)
by DeviceName
| where LongDnsQueries > 100
| sort by LongDnsQueries descResults: One developer workstation made 2,300 DNS queries with domain names averaging 85 characters β classic DNS tunnelling. Tyler saves the query as a custom detection rule running every 3 hours.
Tyler wants to find all devices in CipherStack's environment that made DNS queries with unusually long domain names (potential DNS tunnelling). Which table and filter should he use?
Anika wants to trace which devices visited phishing URLs that arrived via email. She needs to combine EmailUrlInfo and DeviceNetworkEvents. What KQL technique should she use?
Tyler discovers suspicious DNS activity on a developer workstation. His initial KQL query shows 2,300 DNS queries with domain names averaging 85 characters. He suspects DNS tunnelling but needs to confirm. The legitimate CDN the company uses also generates long subdomains. What is the BEST next step?
π¬ Video coming soon
Next up: Advanced Hunting queries are written. Now letβs build Sentinel-specific hunting queries and learn how to monitor hunts over time.