Intermediate ⏱ 75 min πŸ“‹ 8 Steps

Advanced Cross-Product Threat Hunting

Write advanced hunting queries that join DeviceEvents, EmailEvents, and IdentityLogonEvents to trace a multi-stage attack across your enterprise. Correlate telemetry from endpoints, email, identity, and cloud apps using KQL in the Microsoft Defender XDR unified hunting console.

πŸ“‹ Overview

About This Lab

In this hands-on lab you will master cross-product threat hunting in Microsoft Defender XDR by writing KQL queries that span endpoints, email, identity, and cloud app telemetry. You will begin by exploring the unified advanced hunting schema, then progressively build queries against individual data sources before joining them into powerful multi-table correlation queries that reconstruct a complete attack chain. By the end of this lab, you will have created reusable hunting queries, built a chronological attack timeline, saved queries to the shared library with MITRE ATT&CK tags, and promoted a hunting query into a custom detection rule with automated response actions.

🏒 Enterprise Use Case

A financial services firm with 8,000 employees has detected unusual activity across multiple systems but cannot determine whether the events are related. The SOC team received a phishing alert from Defender for Office 365, a suspicious logon alert from Defender for Identity, and an encoded PowerShell execution alert from Defender for Endpoint. all within a 90-minute window. Each alert was triaged independently by different analysts, and none realized they were looking at a coordinated attack. The CISO has mandated that the threat hunting team develop cross-product hunting queries that can trace attack chains spanning email delivery, credential compromise, lateral movement, and data exfiltration in a single investigation. These queries must be reusable, mapped to MITRE ATT&CK, and convertible into automated detection rules for continuous protection.

🎯 What You Will Learn

  1. Navigate the unified advanced hunting schema and understand all available tables across Defender products
  2. Write KQL queries to detect suspicious process execution, encoded PowerShell, and LOLBins abuse on endpoints
  3. Hunt for phishing indicators by querying EmailEvents, EmailAttachmentInfo, and EmailUrlInfo tables
  4. Detect credential attacks including brute-force, pass-the-hash, and suspicious logon patterns via IdentityLogonEvents
  5. Join queries across products using inner join, let statements, and union to correlate multi-stage attacks
  6. Build a chronological attack timeline that reconstructs the full kill chain across all data sources
  7. Save and organize shared hunting queries with MITRE ATT&CK technique tags
  8. Promote a hunting query to a custom detection rule with automated response actions

πŸ”‘ Why This Matters

Sophisticated adversaries deliberately operate across security boundaries. moving from email to identity to endpoint to cloud. because they know most organizations investigate each domain in isolation. Cross-product threat hunting eliminates these blind spots by enabling analysts to trace an attacker's complete path through the environment in a single query. Organizations that adopt cross-product hunting in Defender XDR reduce their mean time to detect (MTTD) multi-stage attacks by up to 80%, because the analyst sees the full kill chain rather than isolated fragments. This skill transforms reactive alert triage into proactive threat discovery and is the cornerstone of a mature security operations practice.

βš™οΈ Prerequisites

  • Completed XDR Lab 01 . Unified Incident Management . You should understand the Defender portal layout, incident correlation, and have verified telemetry from all products
  • Microsoft 365 E5 or E5 Security add-on . Required for access to the unified advanced hunting console across MDE, MDO, MDI, and MDA data
  • Security Reader or Security Operator role (minimum) . Needed to run advanced hunting queries. Security Administrator required to save shared queries and create detection rules
  • Active telemetry from at least 2 Defender products . Endpoint (DeviceEvents) and Identity (IdentityLogonEvents) data must be flowing. Email (EmailEvents) and Cloud Apps (CloudAppEvents) are recommended
  • Basic KQL proficiency . You should be comfortable with where, project, summarize, order by, and take operators. See KQL reference
  • Familiarity with MITRE ATT&CK framework . Understanding of tactics (Initial Access, Execution, Lateral Movement, etc.) helps map hunting queries to adversary behaviors
πŸ’‘ Pro Tip: If you don't have live production data, activate the Microsoft Defender XDR evaluation lab which includes sample data and simulated attacks across all products. perfect for practicing cross-product hunting queries.

Step 1 Β· Understand the Advanced Hunting Schema

The Defender XDR advanced hunting console provides a unified schema that spans all integrated security products. Before writing cross-product queries, you need to understand which tables are available, what data each contains, and how entity columns (like AccountUpn, DeviceName, AccountObjectId) serve as join keys across tables. The schema is organized by product domain but shares common entity identifiers that enable seamless correlation.

Portal Instructions

  • Open security.microsoft.com and navigate to Hunting β†’ Advanced hunting
  • In the left panel, expand the Schema tab to browse all available tables
  • Explore the table groups: Device (MDE), Email (MDO), Identity (MDI), Cloud app (MDA), and Alert (cross-product)
  • Click on any table name (e.g., DeviceEvents) to see its columns, data types, and descriptions
  • Note the common entity columns: AccountUpn, AccountObjectId, DeviceId, DeviceName, SHA256 . these are your join keys
  • Click the Functions tab to see built-in functions like AssignedIPAddresses() and DeviceFromIP()

Key Tables by Product

  • Endpoint (MDE): DeviceEvents, DeviceProcessEvents, DeviceNetworkEvents, DeviceFileEvents, DeviceLogonEvents, DeviceRegistryEvents, DeviceImageLoadEvents
  • Email (MDO): EmailEvents, EmailAttachmentInfo, EmailUrlInfo, EmailPostDeliveryEvents
  • Identity (MDI): IdentityLogonEvents, IdentityQueryEvents, IdentityDirectoryEvents
  • Cloud Apps (MDA): CloudAppEvents
  • Alerts (cross-product): AlertInfo, AlertEvidence

KQL . Explore Available Tables and Row Counts

// ============================================================
// TELEMETRY HEALTH CHECK – verify data is flowing from each product
// Run each line individually in Advanced Hunting at security.microsoft.com
// Purpose: Before cross-product hunting, confirm every data source
//   has recent events. Stale or missing data = blind spots.
// Output columns:
//   Events      – number of events in last 24h (0 = problem)
//   LatestEvent – timestamp of most recent event (stale = config issue)
// ============================================================

// ENDPOINT (MDE): Device-level security events
// Covers: process execution, file changes, logons, registry mods
// If Events=0 β†’ no devices onboarded to MDE or agent not reporting
DeviceEvents | where Timestamp > ago(24h) | summarize Events=count(), LatestEvent=max(Timestamp)
// ENDPOINT (MDE): Process creation telemetry specifically
// This is the richest table for detecting malicious execution
DeviceProcessEvents | where Timestamp > ago(24h) | summarize Events=count(), LatestEvent=max(Timestamp)

// EMAIL (MDO): Mail flow events for all processed emails
// Covers: inbound/outbound delivery, phishing verdicts, spam filtering
// If Events=0 β†’ MDO not licensed or no mailboxes connected
EmailEvents | where Timestamp > ago(24h) | summarize Events=count(), LatestEvent=max(Timestamp)
// EMAIL (MDO): Attachment metadata for files attached to emails
// Includes: file name, type, SHA256 hash, detonation results
EmailAttachmentInfo | where Timestamp > ago(24h) | summarize Events=count(), LatestEvent=max(Timestamp)

// IDENTITY (MDI): Authentication events from AD domain controllers
// Covers: Kerberos, NTLM, interactive/remote logons, failures
// If Events=0 β†’ MDI sensors not installed on domain controllers
IdentityLogonEvents | where Timestamp > ago(24h) | summarize Events=count(), LatestEvent=max(Timestamp)
// IDENTITY (MDI): LDAP/AD query events (reconnaissance detection)
// Covers: user/group enumeration, service account queries
IdentityQueryEvents | where Timestamp > ago(24h) | summarize Events=count(), LatestEvent=max(Timestamp)

// CLOUD APPS (MDA): SaaS application activity
// Covers: OAuth grants, file downloads, admin changes, app access
// If Events=0 β†’ MDA not configured or no app connectors enabled
CloudAppEvents | where Timestamp > ago(24h) | summarize Events=count(), LatestEvent=max(Timestamp)

// ALERTS (cross-product): All alerts from all Defender products
// Using 7d window since alerts are generated less frequently than raw events
// Output: total alert count + list of detection sources sending alerts
// Sources should include: MicrosoftDefenderForEndpoint, MicrosoftDefenderForOffice365, etc.
AlertInfo | where Timestamp > ago(7d) | summarize Alerts=count(), Sources=make_set(DetectionSource)
πŸ’‘ Pro Tip: The advanced hunting console retains 30 days of raw data for most tables. For longer-term hunting, consider streaming data to Microsoft Sentinel via the Defender XDR data connector, which supports configurable retention up to 12 years. Always check the LatestEvent timestamp. if a table shows stale data, the corresponding product may have a configuration issue.

Step 2 Β· Query Device Events for Suspicious Process Execution

Endpoint telemetry is often the richest data source for detecting post-compromise activity. Attackers frequently abuse built-in Windows tools (Living-off-the-Land Binaries, or LOLBins) and encoded PowerShell commands to evade detection. In this step, you will write KQL queries against DeviceProcessEvents and DeviceEvents to identify suspicious process execution patterns that indicate hands-on-keyboard attacker activity.

Portal Instructions

  • In the Advanced Hunting console, ensure you are on the Query tab
  • Paste each KQL query below into the editor and click Run query
  • Review the results table. sort by Timestamp to see chronological order
  • Click on any row to see full event details in the side panel
  • Use the Export button to save results as CSV for offline analysis

KQL . Detect Encoded PowerShell Commands

// DETECT ENCODED POWERSHELL EXECUTION
// MITRE ATT&CK: T1059.001 (Command and Scripting Interpreter: PowerShell)
// Why: Attackers encode PowerShell commands in Base64 to evade static signature
//   detection and hide malicious payloads. Legitimate encoded commands exist
//   (e.g., some Azure scripts) but are typically short; malicious ones are long.
//
// Detection logic:
//   1. Filters to powershell.exe or pwsh.exe (PowerShell 7+) processes
//   2. Checks ProcessCommandLine for encoding indicators:
//      -EncodedCommand / -enc / -e / -ec  = direct Base64 flag
//      FromBase64String / Convert]::FromBase64 = inline decoding in script
//      -WindowStyle Hidden / -w hidden   = hidden execution (no visible window)
//      -nop -sta = no profile + single-threaded (common attack combo)
//   3. Filters by CommandLength > 200 chars (encoded payloads are long strings)
//
// Output columns:
//   InitiatingProcessFileName – what launched PowerShell (e.g., explorer.exe,
//     cmd.exe, or an Office app like WINWORD.EXE = macro-based attack)
//   CommandLength – > 500 chars is highly suspicious
//   SHA256 – hash of the PowerShell binary (verify it’s not renamed)
// False positives: SCCM, Azure Automation, DSC scripts may trigger.
//   Exclude known parent processes via InitiatingProcessFileName if needed.
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName in~ ("powershell.exe", "pwsh.exe")
| where ProcessCommandLine has_any (
    "-EncodedCommand", "-enc ", "-e ", "-ec ",
    "FromBase64String", "Convert]::FromBase64",
    "-WindowStyle Hidden", "-w hidden", "-nop -sta"
)
| extend CommandLength = strlen(ProcessCommandLine)
| where CommandLength > 200  // Encoded commands are typically long
| project Timestamp, DeviceName, AccountUpn,
          FileName, ProcessCommandLine, CommandLength,
          InitiatingProcessFileName, InitiatingProcessCommandLine,
          FolderPath, SHA256
| order by Timestamp desc
| take 100

KQL . Detect LOLBins Abuse (Living-off-the-Land)

// DETECT LOLBins ABUSE (Living-off-the-Land Binaries)
// MITRE ATT&CK: T1218 (System Binary Proxy Execution)
// Why: Attackers use legitimate Windows binaries to bypass application
//   whitelisting and evade detection. These tools are signed by Microsoft
//   and present on every Windows machine, making them ideal for:
//   - Downloading malware from remote URLs (certutil, bitsadmin)
//   - Executing scripts without PowerShell (mshta, wscript, cscript)
//   - Loading malicious DLLs (rundll32, regsvr32)
//   - Compiling/running code inline (msbuild, installutil)
//
// LOLBin-specific indicators in command line:
//   http/https/ftp     – remote payload download
//   /i: + scrobj.dll   – regsvr32 loading a COM scriptlet (Squiblydoo)
//   javascript:        – mshta executing inline JavaScript
//   -decode/-urlcache  – certutil downloading & decoding Base64 files
//   process call create – wmic spawning a new process remotely
//   /transfer          – bitsadmin downloading files in background
//
// Output: Each row = a LOLBin execution with suspicious arguments.
//   Check InitiatingProcessFileName to see what spawned the LOLBin
//   (e.g., cmd.exe from a macro β†’ Word launched the attack)
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName in~ (
    "mshta.exe", "certutil.exe", "regsvr32.exe",
    "rundll32.exe", "msbuild.exe", "installutil.exe",
    "cmstp.exe", "wmic.exe", "bitsadmin.exe"
)
| where ProcessCommandLine has_any (
    "http://", "https://", "ftp://",       // Remote downloads
    "/i:", "scrobj.dll", "javascript:",     // Script execution
    "-decode", "-urlcache", "-split",       // certutil abuse
    "process call create",                  // wmic process creation
    "/transfer"                             // bitsadmin transfers
)
| project Timestamp, DeviceName, AccountUpn,
          FileName, ProcessCommandLine,
          InitiatingProcessFileName,
          InitiatingProcessCommandLine
| order by Timestamp desc
| take 50

KQL . Detect Suspicious Process Injection Patterns

// DETECT PROCESS INJECTION via Windows API abuse
// MITRE ATT&CK: T1055 (Process Injection)
// Why: Attackers inject malicious code into legitimate processes to:
//   - Run code inside trusted processes (evade EDR detections)
//   - Steal credentials from LSASS memory
//   - Establish persistence without writing files to disk
//
// Windows API calls that indicate injection:
//   CreateRemoteThreadApiCall           – creates a thread in another process (classic injection)
//   QueueUserApcRemoteApiCall           – APC injection (queues code in target’s thread)
//   NtAllocateVirtualMemoryRemoteApiCall – allocates memory in another process
//   WriteProcessMemoryApiCall           – writes shellcode into target process memory
//   SetThreadContextRemoteApiCall       – hijacks an existing thread’s execution context
//
// Aggregation logic:
//   Groups by InitiatingProcessFileName (what’s doing the injecting) + ActionType
//   per 1-hour time bin. The InjectionCount > 3 threshold filters single-event noise.
//   make_set() shows WHICH processes were injected into (targets like svchost.exe,
//   explorer.exe are suspicious; security software targets may be legitimate).
//
// False positives: AV/EDR agents, accessibility tools, legitimate hooking.
//   Check InitiatingProcessFileName against your software inventory.
DeviceEvents
| where Timestamp > ago(7d)
| where ActionType in (
    "CreateRemoteThreadApiCall",
    "QueueUserApcRemoteApiCall",
    "NtAllocateVirtualMemoryRemoteApiCall",
    "WriteProcessMemoryApiCall",
    "SetThreadContextRemoteApiCall"
)
| project Timestamp, DeviceName, AccountUpn,
          ActionType, FileName,
          InitiatingProcessFileName,
          InitiatingProcessCommandLine,
          AdditionalFields
| summarize InjectionCount = count(),
            TargetProcesses = make_set(FileName),
            Devices = make_set(DeviceName)
    by InitiatingProcessFileName, ActionType, bin(Timestamp, 1h)
| where InjectionCount > 3
| order by InjectionCount desc
⚠️ Important: Some legitimate software (antivirus, monitoring agents, accessibility tools) triggers process injection events. Always cross-reference hits with your organization's software inventory. The InjectionCount > 3 threshold helps filter noise, but adjust based on your environment's baseline. Document known false positives in a shared query comment.

Step 3 Β· Query Email Events for Phishing Indicators

Email is the most common initial access vector for enterprise attacks. Defender for Office 365 captures detailed telemetry about every email processed, including sender reputation, attachment detonation results, URL analysis, and delivery actions. In this step, you will query EmailEvents, EmailAttachmentInfo, and EmailUrlInfo to find phishing emails that reached user mailboxes, identify suspicious attachments, and trace click-through on malicious URLs.

Portal Instructions

  • In the Advanced Hunting console, query the EmailEvents table to find delivered threats
  • Join with EmailAttachmentInfo using NetworkMessageId to correlate attachment details
  • Join with EmailUrlInfo to see embedded URL verdicts and click data
  • Note the RecipientEmailAddress column. this is the key entity for joining with identity tables later

KQL . Find Delivered Phishing Emails

// FIND DELIVERED PHISHING EMAILS that bypassed or partially bypassed filtering
// MITRE ATT&CK: T1566.001 (Phishing: Spearphishing Attachment)
// Why: Emails that reach user mailboxes are the starting point of most
//   enterprise attacks. This query finds threats that evaded protection.
//
// Filter logic:
//   ThreatTypes has "Phish" or "Malware" – MDO’s threat classification
//   DetectionMethods – HOW MDO detected the threat:
//     "URL detonation"   = Safe Links sandbox analysis found malicious URL
//     "File detonation"  = Safe Attachments sandbox detonated a malicious file
//     "Impersonation domain" = sender domain spoofing a trusted brand
//     "Mailbox intelligence" = AI detected impersonation based on mail patterns
//   DeliveryAction:
//     "Delivered" = reached inbox (highest risk – user can interact)
//     "Junked"    = went to Junk folder (lower risk but user can still open)
//
// Key output columns:
//   NetworkMessageId      – unique email ID for joining with attachment/URL tables
//   SenderFromAddress      – display "From" (can be spoofed)
//   SenderMailFromAddress  – envelope sender (harder to spoof, check for mismatches)
//   AuthenticationDetails  – SPF/DKIM/DMARC results (failures = likely spoofed)
//   RecipientEmailAddress  – the targeted user (use this to join with identity events)
EmailEvents
| where Timestamp > ago(7d)
| where ThreatTypes has_any ("Phish", "Malware")
    or DetectionMethods has_any ("URL detonation", "File detonation",
        "Impersonation domain", "Mailbox intelligence impersonation")
| where DeliveryAction == "Delivered"
    or DeliveryAction == "Junked"
| project Timestamp, NetworkMessageId, SenderFromAddress,
          SenderMailFromAddress, RecipientEmailAddress,
          Subject, ThreatTypes, DetectionMethods,
          DeliveryAction, DeliveryLocation,
          AuthenticationDetails
| order by Timestamp desc
| take 50

KQL . Identify Suspicious Attachments

// IDENTIFY WEAPONIZED EMAIL ATTACHMENTS
// MITRE ATT&CK: T1566.001 (Phishing: Spearphishing Attachment)
// Why: Malicious attachments are the #1 payload delivery method.
//   This query correlates attachment metadata with email delivery status.
//
// High-risk file types explained:
//   exe/dll/scr  – direct executables (rarely legitimate in email)
//   js/vbs/hta   – script files that run via Windows Script Host
//   ps1          – PowerShell scripts
//   bat/cmd      – batch/command scripts
//   iso/img/vhd  – disk images that auto-mount and bypass Mark-of-the-Web
//   lnk          – shortcuts that can launch arbitrary commands
//   .html.htm    – double-extension trick to disguise HTML credential harvesters
//
// Join logic: inner join on NetworkMessageId links each attachment
//   to its parent email, filtering to only delivered/junked emails.
// Output: SHA256 hash can be searched in VirusTotal for known malware.
//   FileType mismatches (e.g., FileType="exe" but FileName="invoice.pdf.exe")
//   are strong indicators of social engineering.
EmailAttachmentInfo
| where Timestamp > ago(7d)
| where FileType in~ (
    "exe", "dll", "scr", "js", "vbs", "hta", "ps1",
    "bat", "cmd", "iso", "img", "vhd", "lnk"
)
    or FileName endswith ".html.htm"    // Double extensions
    or FileName matches regex @"\.\w+\.\w+$"  // Any double extension
| join kind=inner (
    EmailEvents
    | where Timestamp > ago(7d)
    | where DeliveryAction in ("Delivered", "Junked")
) on NetworkMessageId
| project Timestamp, SenderFromAddress, RecipientEmailAddress,
          Subject, FileName, FileType, SHA256,
          ThreatTypes, DeliveryAction
| order by Timestamp desc

KQL . Trace Malicious URL Clicks

// TRACE MALICIOUS URLS IN PHISHING CAMPAIGNS
// MITRE ATT&CK: T1566.002 (Phishing: Spearphishing Link)
// Why: URL-based phishing is increasingly common as organizations
//   improve attachment filtering. This query identifies phishing
//   domains and reveals campaign scope (how many users were targeted).
//
// How it works:
//   1. Starts from EmailUrlInfo (all URLs extracted from emails)
//   2. Excludes known Microsoft domains to reduce noise
//   3. Inner joins with EmailEvents filtered to delivered phishing emails
//      using NetworkMessageId (unique email identifier)
//   4. Aggregates by UrlDomain to reveal campaign infrastructure
//
// Output columns:
//   UrlDomain       – the phishing domain (check in VirusTotal/URLhaus)
//   PhishEmailCount – how many phishing emails used this domain
//   TargetedUsers   – list of users who received emails with this URL
//   UrlList         – full URLs (look for credential harvesting paths
//                     like /login, /signin, /verify commonly used in BEC)
// High PhishEmailCount with many TargetedUsers = organized phishing campaign
EmailUrlInfo
| where Timestamp > ago(7d)
| where UrlDomain !in~ ("microsoft.com", "office.com", "windows.net",
    "microsoftonline.com", "sharepoint.com")
| join kind=inner (
    EmailEvents
    | where Timestamp > ago(7d)
    | where ThreatTypes has "Phish"
    | where DeliveryAction == "Delivered"
) on NetworkMessageId
| project Timestamp, RecipientEmailAddress, SenderFromAddress,
          Subject, Url, UrlDomain, UrlLocation
| summarize PhishEmailCount = count(),
            TargetedUsers = make_set(RecipientEmailAddress),
            UrlList = make_set(Url)
    by UrlDomain
| order by PhishEmailCount desc
πŸ’‘ Pro Tip: Pay special attention to emails where DeliveryAction == "Delivered" and ThreatTypes has "Phish" . these are threats that bypassed filtering. Cross-reference the RecipientEmailAddress with IdentityLogonEvents in the next step to check if the targeted user subsequently had a suspicious logon, which would indicate a successful credential harvest.

Step 4 Β· Query Identity Events for Credential Attacks

After phishing emails reach user mailboxes, the next stage of a multi-stage attack typically involves credential compromise. Defender for Identity captures authentication events from Active Directory domain controllers and Entra ID, giving you visibility into failed sign-ins, pass-the-hash attacks, Kerberos abuse, and lateral movement. The IdentityLogonEvents table is your primary source for detecting credential-based attacks.

Portal Instructions

  • In the Advanced Hunting console, query IdentityLogonEvents for all authentication telemetry
  • Focus on high-risk logon types: Interactive from unusual locations, RemoteInteractive (RDP), and Network logons from unexpected sources
  • Use the FailureReason column to distinguish brute-force (many failures) from pass-the-hash (specific failure codes)
  • Cross-reference AccountUpn values with the phishing targets from Step 3

KQL . Detect Brute-Force and Password Spray Attacks

// DETECT BRUTE-FORCE PASSWORD ATTACKS with successful compromise
// MITRE ATT&CK: T1110.001 (Brute Force: Password Guessing)
// Why: Brute-force attacks try many passwords against one account.
//   The dangerous pattern is many failures FOLLOWED by a success,
//   meaning the attacker guessed the correct password.
//
// Tunable thresholds:
//   failureThreshold = 10 – minimum failed attempts to trigger detection
//     (lower = more sensitive but more false positives from typos)
//   timeWindow = 1h – aggregation window for counting failures
//     (password spray attacks may spread failures over longer periods)
//
// Detection logic:
//   Groups all logon events per user per 1-hour window, then checks:
//   - FailedAttempts >= 10 (brute-force pattern)
//   - SuccessfulAttempts >= 1 (attacker got in – HIGH PRIORITY)
//
// Output: each row = a likely compromised account
//   FailureReasons – "BadPassword" is typical; "AccountLocked" means
//     lockout policy kicked in (but attacker may have succeeded before lock)
//   SourceIPs – multiple IPs suggest distributed/botnet attack
//   TargetDevices – which systems the attacker targeted
let failureThreshold = 10;
let timeWindow = 1h;
IdentityLogonEvents
| where Timestamp > ago(7d)
| summarize
    FailedAttempts = countif(ActionType == "LogonFailed"),
    SuccessfulAttempts = countif(ActionType == "LogonSuccess"),
    FailureReasons = make_set(FailureReason),
    SourceIPs = make_set(IPAddress),
    TargetDevices = make_set(DeviceName)
    by AccountUpn, bin(Timestamp, timeWindow)
| where FailedAttempts >= failureThreshold
    and SuccessfulAttempts >= 1  // Compromise indicator
| extend RiskIndicator = "BruteForceSuccess"
| project Timestamp, AccountUpn, FailedAttempts,
          SuccessfulAttempts, FailureReasons,
          SourceIPs, TargetDevices, RiskIndicator
| order by FailedAttempts desc

KQL . Detect Pass-the-Hash and Lateral Movement

// DETECT PASS-THE-HASH AND NTLM LATERAL MOVEMENT
// MITRE ATT&CK: T1550.002 (Use Alternate Authentication Material: Pass the Hash)
// Why: After stealing NTLM hashes (e.g., from LSASS memory), attackers
//   use them to authenticate to other machines without knowing the password.
//   NTLM Network logons to MULTIPLE unique devices in a short window
//   is the strongest indicator of lateral movement.
//
// Detection logic:
//   1. Filters to NTLM protocol (not Kerberos) – PtH uses NTLM
//   2. Only successful Network logons (remote authentication)
//   3. Groups by user per 1-hour window
//   4. Checks: NTLMLogonCount > 5 AND UniqueTargets > 3
//      Normal users rarely authenticate to 3+ different servers in 1 hour
//      via NTLM. Admins may, so tune threshold for admin accounts.
//
// Output:
//   UniqueTargets  – number of distinct devices accessed (high = lateral movement)
//   TargetDevices  – list of device names (look for DCs, file servers, tier-0 assets)
//   SourceIPs      – originating IP addresses
// False positives: Domain admins, SCCM, backup agents. Exclude known service accounts.
IdentityLogonEvents
| where Timestamp > ago(7d)
| where Protocol == "NTLM"
| where ActionType == "LogonSuccess"
| where LogonType == "Network"
| summarize
    NTLMLogonCount = count(),
    UniqueTargets = dcount(DeviceName),
    TargetDevices = make_set(DeviceName),
    SourceIPs = make_set(IPAddress)
    by AccountUpn, bin(Timestamp, 1h)
| where NTLMLogonCount > 5
    and UniqueTargets > 3   // Multiple targets = lateral movement
| extend RiskIndicator = "PotentialPtH_LateralMovement"
| order by UniqueTargets desc

KQL . Suspicious Logons After Phishing (Proactive Correlation)

// PROACTIVE CORRELATION: Phishing recipients who later logged in
// MITRE ATT&CK: T1566 β†’ T1078 (Phishing β†’ Valid Accounts)
// Why: This is a lightweight pre-join that finds users who:
//   1. Received a delivered phishing email (from Step 3)
//   2. Subsequently had a successful logon event
//   This does NOT mean they’re compromised, but they ARE high-priority
//   for investigation. Any unusual IPAddress, Location, or Application
//   in the logon event suggests credential harvesting was successful.
//
// How it works:
//   - 'let phishedUsers' creates a list of email recipients from EmailEvents
//   - The main query filters IdentityLogonEvents to only those users
//   - Sorted by time (asc) to see logons AFTER the phishing delivery
//
// Key columns to examine:
//   IPAddress   – is this from a known/expected location?
//   Location    – does this match the user’s normal geography?
//   Application – did the attacker access a sensitive app (e.g., Exchange, SharePoint)?
//   LogonType   – Interactive from a new location is high-risk
let phishedUsers =
    EmailEvents
    | where Timestamp > ago(7d)
    | where ThreatTypes has "Phish"
    | where DeliveryAction == "Delivered"
    | distinct RecipientEmailAddress;
IdentityLogonEvents
| where Timestamp > ago(7d)
| where AccountUpn in (phishedUsers)
| where ActionType == "LogonSuccess"
| project Timestamp, AccountUpn, IPAddress, DeviceName,
          Location, Application, LogonType, Protocol
| order by Timestamp asc
⚠️ Important: NTLM logons are often legitimate in hybrid environments with legacy applications. However, a high volume of NTLM Network logons from a single account to multiple unique devices within a short time window is a strong indicator of lateral movement using pass-the-hash. Tune the UniqueTargets > 3 threshold based on your environment. a domain admin may legitimately touch many servers.

Step 5 Β· Join Queries Across Products

This is the core of cross-product threat hunting. By joining data from EmailEvents, IdentityLogonEvents, and DeviceProcessEvents, you can trace an attacker's path from initial phishing email through credential compromise to endpoint exploitation. all in a single query. KQL supports join, let statements, and union operators to correlate data across tables. The key is identifying shared entity columns that link events across products.

Portal Instructions

  • In the Advanced Hunting console, paste each multi-table query below
  • Note the let statements that create intermediate result sets. these act as sub-queries
  • The join kind=inner operator returns only rows with matches in both tables
  • Review the results carefully. each row represents a correlated event chain across products
  • Use these queries as templates for your own cross-product investigations

KQL . Phishing β†’ Credential Compromise Correlation

// CROSS-PRODUCT JOIN: Phishing email β†’ Credential compromise
// MITRE ATT&CK: T1566 β†’ T1078 (Phishing β†’ Valid Accounts)
// Purpose: Directly correlate a delivered phishing email with a
//   subsequent suspicious logon by the SAME user within 4 hours.
//   This is evidence of a successful credential harvesting attack.
//
// How the join works:
//   1. 'let phishingEmails' captures all delivered phishing emails
//   2. 'let suspiciousLogons' captures all successful logon events
//   3. Inner join on RecipientEmailAddress == AccountUpn links them
//   4. 'where LogonTime between (PhishTime .. PhishTime + 4h)' ensures
//      the logon happened AFTER the phishing email and within the window
//
// Output columns:
//   PhishTime     – when the phishing email was delivered
//   LogonTime     – when the user’s credentials were used
//   TimeDelta     – time between phish and logon (shorter = more suspicious)
//   IPAddress     – logon source IP (different from user’s normal IP = compromise)
//   Application   – what the attacker accessed first (OWA, SharePoint, Teams, etc.)
//   LogonType     – Interactive = direct sign-in with stolen credentials
//
// The 4-hour window is typical for credential harvesting. Adjust:
//   - Narrow to 1h for automated attack campaigns
//   - Widen to 24h for targeted spearphishing with delayed exploitation
let phishingEmails =
    EmailEvents
    | where Timestamp > ago(7d)
    | where ThreatTypes has "Phish"
    | where DeliveryAction == "Delivered"
    | project PhishTime = Timestamp, RecipientEmailAddress,
              SenderFromAddress, Subject, NetworkMessageId;
let suspiciousLogons =
    IdentityLogonEvents
    | where Timestamp > ago(7d)
    | where ActionType == "LogonSuccess"
    | project LogonTime = Timestamp, AccountUpn,
              IPAddress, DeviceName, Application, LogonType;
phishingEmails
| join kind=inner (suspiciousLogons)
    on $left.RecipientEmailAddress == $right.AccountUpn
| where LogonTime between (PhishTime .. (PhishTime + 4h))
| project PhishTime, LogonTime,
          TimeDelta = LogonTime. PhishTime,
          AccountUpn, SenderFromAddress, Subject,
          IPAddress, DeviceName, Application, LogonType
| order by PhishTime asc

KQL . Full Kill Chain: Email β†’ Identity β†’ Endpoint

// ============================================================
// FULL KILL CHAIN CORRELATION: Email β†’ Identity β†’ Endpoint
// MITRE ATT&CK: T1566 β†’ T1078 β†’ T1059 (Phishing β†’ Valid Accounts β†’ Execution)
// Purpose: Traces a complete 3-stage attack across all three products:
//   Stage 1 (MDO): Phishing email delivered to user
//   Stage 2 (MDI): Stolen credentials used to sign in
//   Stage 3 (MDE): Attacker runs malicious commands on endpoint
// This is the most powerful cross-product query in this lab.
//
// Join strategy:
//   - Stage 1 β†’ Stage 2: joined on TargetUser == AccountUpn
//     with 4h time window (cred harvesting window)
//   - Stage 2 β†’ Stage 3: joined on AccountUpn
//     with 8h time window (post-compromise execution window)
//
// Stage 3 detection criteria:
//   Suspicious processes: powershell, cmd, wscript, cscript, mshta, certutil
//   Suspicious arguments: encoded commands, download strings, bypass flags
//   These indicate hands-on-keyboard attacker activity post-compromise
//
// Output: Each row = a confirmed 3-stage attack chain
//   AttackDuration – total time from email to execution (assess urgency)
//   LogonIP – attacker’s IP address (geo-locate and block)
//   ProcessCommandLine – what the attacker actually ran (decode if encoded)
// ============================================================
let lookback = 7d;
// Stage 1: Phishing emails delivered
let stage1_phish =
    EmailEvents
    | where Timestamp > ago(lookback)
    | where ThreatTypes has "Phish" and DeliveryAction == "Delivered"
    | project PhishTime = Timestamp, TargetUser = RecipientEmailAddress,
              SenderFromAddress, Subject, NetworkMessageId;
// Stage 2: Successful logons by phished users
let stage2_logon =
    IdentityLogonEvents
    | where Timestamp > ago(lookback)
    | where ActionType == "LogonSuccess"
    | project LogonTime = Timestamp, AccountUpn,
              LogonIP = IPAddress, LogonDevice = DeviceName,
              Application, Protocol;
// Stage 3: Suspicious process execution by compromised users
let stage3_execution =
    DeviceProcessEvents
    | where Timestamp > ago(lookback)
    | where FileName in~ ("powershell.exe", "cmd.exe", "wscript.exe",
                           "cscript.exe", "mshta.exe", "certutil.exe")
    | where ProcessCommandLine has_any (
        "-enc", "FromBase64", "bypass", "http://", "https://",
        "Invoke-", "IEX", "downloadstring", "-nop"
    )
    | project ExecTime = Timestamp, AccountUpn,
              ExecDevice = DeviceName, FileName,
              ProcessCommandLine, SHA256;
// Correlate all three stages using time-windowed joins
stage1_phish
| join kind=inner (stage2_logon)
    on $left.TargetUser == $right.AccountUpn
| where LogonTime between (PhishTime .. (PhishTime + 4h))
| join kind=inner (stage3_execution)
    on AccountUpn
| where ExecTime between (LogonTime .. (LogonTime + 8h))
| project PhishTime, LogonTime, ExecTime,
          AccountUpn, SenderFromAddress, Subject,
          LogonIP, LogonDevice, Application,
          ExecDevice, FileName, ProcessCommandLine
| extend AttackDuration = ExecTime. PhishTime
| order by PhishTime asc
πŸ’‘ Pro Tip: The time windows in between clauses are critical for accuracy. A 4-hour window between phishing and logon is typical for credential harvesting, but adjust based on your threat model. For automated attacks, reduce to 1 hour. For targeted spearphishing with delayed exploitation, expand to 24 hours. Always start narrow and widen if you get zero results.

Step 6 Β· Build a Multi-Stage Attack Timeline

A chronological attack timeline is the most powerful artifact a threat hunter can produce. It shows the complete sequence of adversary actions across every data source in a single, time-ordered view. In this step, you will use the KQL union operator to merge events from EmailEvents, IdentityLogonEvents, DeviceProcessEvents, and CloudAppEvents into a unified timeline for a specific user or incident.

Portal Instructions

  • Identify a target user from your Step 5 results (or use a known compromised account from your environment)
  • Replace targetUser in the query below with the actual UPN
  • Run the query and review the chronological output. each row is a single event with its source product labeled
  • Look for the attack narrative: what happened first, what came next, and how the attacker progressed

KQL . Comprehensive Cross-Product Attack Timeline

// ============================================================
// COMPREHENSIVE CROSS-PRODUCT ATTACK TIMELINE
// Purpose: Merge ALL telemetry sources for a single user into one
//   chronological view. This reconstructs the entire attack narrative.
//
// How it works:
//   - 'union' combines rows from 7 different tables into one result
//   - Each sub-query targets the same user and labels its Source
//   - Results sorted by Timestamp (ascending) = attack progression
//
// Data sources included:
//   1. Email (MDO)      – phishing delivery to the user’s mailbox
//   2. Attachment (MDO)  – details of attached files (type, hash)
//   3. Identity (MDI)    – authentication events (logon success/failure)
//   4. AD Query (MDI)    – LDAP/directory queries (reconnaissance)
//   5. Process (MDE)     – process execution on endpoints
//   6. Network (MDE)     – outbound connections (C2, exfiltration)
//   7. Cloud App (MDA)   – SaaS app activity (data access)
//
// Reading the timeline: Each row shows WHEN, WHERE (source), and WHAT.
//   Look for the progression pattern typical of multi-stage attacks:
//   MDO β†’ MDI β†’ MDE Process β†’ MDE Network β†’ MDA
// ============================================================
// Replace the targetUser value with the actual compromised account UPN
let targetUser = "jsmith@contoso.com";
let timeRange = 24h;
union
    // Email events: phishing email delivery to target user
    (EmailEvents
     | where Timestamp > ago(timeRange)
     | where RecipientEmailAddress =~ targetUser
     | extend Source = "Email (MDO)",
              Detail = strcat("From: ", SenderFromAddress,
                              " | Subject: ", Subject,
                              " | Action: ", DeliveryAction,
                              " | Threat: ", ThreatTypes)
     | project Timestamp, Source, Detail),
    // Email attachment info: files attached to emails received by target
    (EmailAttachmentInfo
     | where Timestamp > ago(timeRange)
     | join kind=inner (
         EmailEvents | where RecipientEmailAddress =~ targetUser
     ) on NetworkMessageId
     | extend Source = "Attachment (MDO)",
              Detail = strcat("File: ", FileName,
                              " | Type: ", FileType,
                              " | SHA256: ", SHA256)
     | project Timestamp, Source, Detail),
    // Identity logon events: authentication attempts by target user
    // ActionType shows LogonSuccess vs LogonFailed; IP/Location reveal attacker origin
    (IdentityLogonEvents
     | where Timestamp > ago(timeRange)
     | where AccountUpn =~ targetUser
     | extend Source = "Identity (MDI)",
              Detail = strcat(ActionType, " | Device: ", DeviceName,
                              " | IP: ", IPAddress,
                              " | App: ", Application,
                              " | Protocol: ", Protocol,
                              " | Type: ", LogonType)
     | project Timestamp, Source, Detail),
    // AD directory queries: reconnaissance activity (LDAP enumeration)
    // Attackers query AD for Domain Admins, service accounts, group membership
    (IdentityQueryEvents
     | where Timestamp > ago(timeRange)
     | where AccountUpn =~ targetUser
     | extend Source = "AD Query (MDI)",
              Detail = strcat(ActionType, " | Query: ", QueryType,
                              " | Target: ", QueryTarget)
     | project Timestamp, Source, Detail),
    // Device process events: commands executed on endpoints by the user
    // Look for: PowerShell, cmd, suspicious LOLBins, encoded commands
    (DeviceProcessEvents
     | where Timestamp > ago(timeRange)
     | where AccountUpn =~ targetUser
         or InitiatingProcessAccountUpn =~ targetUser
     | extend Source = "Process (MDE)",
              Detail = strcat(FileName, " | Cmd: ",
                              substring(ProcessCommandLine, 0, 200),
                              " | Device: ", DeviceName)
     | project Timestamp, Source, Detail),
    // Device network events: outbound connections (C2 beaconing, data exfiltration)
    // RemoteUrl/RemoteIP show where data is going; RemotePort 443/80 = HTTPS/HTTP
    (DeviceNetworkEvents
     | where Timestamp > ago(timeRange)
     | where InitiatingProcessAccountUpn =~ targetUser
     | extend Source = "Network (MDE)",
              Detail = strcat(ActionType, " | Remote: ",
                              RemoteUrl, " (", RemoteIP, ":",
                              tostring(RemotePort), ")",
                              " | Process: ", InitiatingProcessFileName)
     | project Timestamp, Source, Detail),
    // Cloud app events: SaaS application usage (file access, downloads, sharing)
    // Large file downloads or sharing to external users indicates data exfiltration
    (CloudAppEvents
     | where Timestamp > ago(timeRange)
     | where AccountObjectId == targetUser
         or AccountDisplayName =~ targetUser
     | extend Source = "Cloud App (MDA)",
              Detail = strcat(ActionType, " | App: ", Application,
                              " | Object: ", ObjectName)
     | project Timestamp, Source, Detail)
| order by Timestamp asc

Reading the Timeline

A typical multi-stage attack timeline reads like this:

  • T+0 min . Email (MDO): Phishing email delivered with malicious attachment
  • T+12 min . Attachment (MDO): User opens HTML credential harvester
  • T+15 min . Identity (MDI): Successful logon from new IP address (attacker using stolen creds)
  • T+18 min . AD Query (MDI): LDAP query for Domain Admins group membership
  • T+25 min . Process (MDE): PowerShell encoded command execution on endpoint
  • T+30 min . Network (MDE): Outbound connection to suspicious C2 domain
  • T+45 min . Identity (MDI): NTLM logon to file server (lateral movement)
  • T+60 min . Cloud App (MDA): Mass file download from SharePoint (data exfiltration)
πŸ’‘ Pro Tip: Save your timeline query as a function in Advanced Hunting so you can quickly run it for any user. Go to Query tab β†’ Create function, name it InvestigateUserTimeline, and parameterize the targetUser and timeRange variables. Then call it with: InvestigateUserTimeline("jsmith@contoso.com", 48h).

Step 7 Β· Create Shared Hunting Queries

Effective threat hunting is a team activity. The shared query library in Defender XDR allows you to save, organize, and share your best hunting queries with the entire SOC. In this step, you will save the queries you built in previous steps to the shared library, tag them with MITRE ATT&CK technique IDs, and organize them into logical folders for easy retrieval during incident investigations.

Portal Instructions. Save a Query to Shared Library

  • In the Advanced Hunting console, paste one of your queries from Steps 2Β·6
  • Click Save β†’ Save as
  • In the save dialog, configure:
    • Name: XH-001: PhishToEndpoint Kill Chain
    • Description: Traces phishing email delivery β†’ credential compromise β†’ suspicious endpoint execution. Maps to MITRE T1566?T1078?T1059.
    • Folder: Shared queries / Cross-Product Hunting (create the folder if needed)
  • Click Save
  • Repeat for each query, using a consistent naming convention

Recommended Naming Convention

  • XH-001 . PhishToEndpoint Kill Chain (T1566, T1078, T1059)
  • XH-002 . BruteForce Success Detection (T1110.001)
  • XH-003 . NTLM Lateral Movement (T1550.002)
  • XH-004 . LOLBins Download and Execute (T1218)
  • XH-005 . Encoded PowerShell Execution (T1059.001)
  • XH-006 . Process Injection Patterns (T1055)
  • XH-007 . Suspicious Attachment Delivery (T1566.001)
  • XH-008 . User Investigation Timeline (Multi-technique)

Portal Instructions. Organize with MITRE ATT&CK Tags

  • Navigate to Hunting β†’ Advanced hunting β†’ Shared queries tab
  • For each saved query, click the three-dot menu (?) β†’ Edit details
  • In the MITRE ATT&CK techniques field, add the relevant technique IDs (e.g., T1566, T1078, T1059)
  • Use the Tags field to add custom tags: cross-product, kill-chain, phishing, lateral-movement
  • Organize queries into folders: Cross-Product Hunting, Endpoint Hunting, Email Hunting, Identity Hunting
πŸ’‘ Pro Tip: Include a comment block at the top of every saved query documenting the MITRE technique, data sources required, expected false positive rate, and tuning guidance. This makes queries self-documenting for SOC analysts who find them later. Example: // Author: SOC Team | MITRE: T1566?T1078 | FP Rate: Low | Tune: Adjust time window based on phishing sophistication

Step 8 Β· Export Results and Create Detection Rules

The final step in the threat hunting lifecycle is to convert your best hunting queries into automated custom detection rules. This means the query runs continuously on a schedule, and when it finds matching events, it automatically creates alerts and can trigger response actions like isolating a device or disabling a user account. This transforms one-time hunting into persistent, automated protection.

Portal Instructions. Create a Custom Detection Rule

  • In the Advanced Hunting console, paste the kill-chain query from Step 5
  • Click Create detection rule in the toolbar
  • Configure the detection rule:
    • Rule name: Cross-Product: Phishing to Endpoint Compromise
    • Frequency: Every hour (for near-real-time detection)
    • Severity: High
    • Category: InitialAccess
    • Description: Detects scenarios where a delivered phishing email is followed by a suspicious logon and endpoint execution within the defined time windows.
    • MITRE techniques: T1566, T1078, T1059
  • Map result columns to entities:
    • Map AccountUpn β†’ User entity
    • Map ExecDevice β†’ Device entity
    • Map LogonIP β†’ IP address entity
  • Click Next to configure response actions

Portal Instructions. Configure Automated Response Actions

  • On the Actions page, configure automated responses:
    • Device actions: Select Isolate device to network-isolate the compromised endpoint (allows Defender communication only)
    • User actions: Select Force password reset or Disable user to contain the compromised identity
    • Email actions: Select Move to deleted items or Soft delete to remove the phishing email from additional mailboxes
  • Review the full rule configuration and click Create
  • The rule will appear under Hunting β†’ Custom detection rules

KQL . Detection Rule Query (Production-Ready)

// ============================================================
// PRODUCTION-READY CUSTOM DETECTION RULE
// Purpose: Automated detection of phishing-to-endpoint compromise
//   This query is designed to run as a scheduled detection rule
//   (every hour) and automatically create alerts with entity mapping.
//
// MITRE ATT&CK: T1566 β†’ T1078 β†’ T1059
//   (Phishing β†’ Valid Accounts β†’ Command and Scripting Interpreter)
//
// Time windows explained:
//   lookback = 4h          – matches the rule frequency + buffer to avoid
//                            missing events between runs
//   phishToLogonWindow = 4h – max time between phishing delivery and logon
//   logonToExecWindow = 8h  – max time between logon and suspicious execution
//
// Entity mapping (configure in the portal when creating the rule):
//   AccountUpn  β†’ User entity (enables automatic user investigation)
//   ExecDevice  β†’ Device entity (enables one-click device isolation)
//   LogonIP     β†’ IP entity (enables IP blocking and geo-lookup)
//
// Response actions to configure:
//   - Isolate device (ExecDevice) – network-isolates the compromised endpoint
//   - Force password reset (AccountUpn) – invalidates stolen credentials
//   - Soft delete email (NetworkMessageId) – removes phishing email from mailboxes
//
// IMPORTANT: Start with alert-only mode for 2 weeks to validate accuracy.
//   Only enable automated response after confirming low false positive rate.
// ============================================================
let lookback = 4h;  // Match the rule frequency + buffer
let phishToLogonWindow = 4h;
let logonToExecWindow = 8h;
let stage1 =
    EmailEvents
    | where Timestamp > ago(lookback)
    | where ThreatTypes has "Phish"
    | where DeliveryAction == "Delivered"
    | project PhishTime = Timestamp,
              TargetUser = RecipientEmailAddress,
              SenderFromAddress, Subject, NetworkMessageId;
let stage2 =
    IdentityLogonEvents
    | where Timestamp > ago(lookback)
    | where ActionType == "LogonSuccess"
    | project LogonTime = Timestamp, AccountUpn,
              LogonIP = IPAddress, LogonDevice = DeviceName,
              Application;
let stage3 =
    DeviceProcessEvents
    | where Timestamp > ago(lookback)
    | where FileName in~ ("powershell.exe", "cmd.exe",
        "wscript.exe", "cscript.exe", "mshta.exe")
    | where ProcessCommandLine has_any (
        "-enc", "FromBase64", "bypass", "Invoke-",
        "downloadstring", "http://", "https://")
    | project ExecTime = Timestamp, AccountUpn,
              ExecDevice = DeviceName, FileName,
              ProcessCommandLine;
stage1
| join kind=inner (stage2) on $left.TargetUser == $right.AccountUpn
| where LogonTime between (PhishTime .. (PhishTime + phishToLogonWindow))
| join kind=inner (stage3) on AccountUpn
| where ExecTime between (LogonTime .. (LogonTime + logonToExecWindow))
| project PhishTime, LogonTime, ExecTime, AccountUpn,
          SenderFromAddress, Subject, LogonIP, LogonDevice,
          ExecDevice, FileName, ProcessCommandLine,
          NetworkMessageId
⚠️ Important: Automated response actions like Isolate device and Disable user have significant business impact. Start with alert-only mode for the first 2 weeks to validate the detection rule's accuracy and false positive rate. Only enable automated response actions after confirming the rule produces reliable results. Always exclude service accounts and break-glass admin accounts from user disable actions.
πŸ’‘ Pro Tip: After the detection rule is active, monitor its performance under Hunting β†’ Custom detection rules. Check the Last run, Alerts generated, and Actions taken columns. If the rule generates too many false positives, refine the KQL query. add exclusions for known-safe senders, trusted IP ranges, or legitimate LOLBin usage in your environment.

Summary

What You Accomplished

  • Explored the unified advanced hunting schema and verified telemetry health across all Defender products
  • Wrote KQL queries to detect encoded PowerShell, LOLBins abuse, and process injection on endpoints
  • Hunted for phishing indicators across EmailEvents, EmailAttachmentInfo, and EmailUrlInfo
  • Detected brute-force, pass-the-hash, and lateral movement patterns in IdentityLogonEvents
  • Built cross-product join queries that correlate phishing β†’ credential compromise β†’ endpoint execution
  • Created a comprehensive attack timeline using union across all data sources for a single user
  • Saved queries to the shared library with MITRE ATT&CK tags and folder organization
  • Promoted a hunting query into a custom detection rule with automated response actions

πŸ’° Cost Considerations

Advanced hunting queries in Defender XDR are included with your Microsoft 365 E5 or E5 Security license at no additional per-query cost. Custom detection rules that run on a schedule also have no extra cost. However, be mindful that queries with very broad time ranges (>30 days) or that scan massive tables without filters may time out. Optimize queries with early where filters and limit take clauses during development.

🧹 Clean Up Resources

  • If you created test detection rules with automated response actions, disable or delete them under Hunting β†’ Custom detection rules to prevent unintended device isolation or account lockouts
  • Shared hunting queries can remain in the library. they do not consume resources when not actively running
  • If you used the Defender XDR evaluation lab, it will automatically expire after 90 days

πŸš€ Next Steps

πŸ’‘ Pro Tip: The best threat hunting programs run on a cadence: weekly hypothesis-driven hunts using your saved queries, monthly review of detection rule performance, and quarterly updates to your query library based on emerging threats and MITRE ATT&CK updates. Track your hunting metrics. hunts conducted, true positives found, and queries promoted to detection rules. to demonstrate value to leadership.

πŸ“š Documentation Resources

ResourceDescription
Advanced hunting overviewCross-product threat hunting with KQL in Defender XDR
Advanced hunting schema referenceComplete table and column reference for all data sources
KQL in advanced huntingLanguage reference and best practices for hunting queries
Custom detection rulesCreate and manage automated detection rules from hunting queries
Shared hunting queriesSave, organize, and share queries with your SOC team
Advanced hunting best practicesQuery optimization, performance tips, and methodology
MITRE ATT&CK Enterprise MatrixFramework for mapping hunting queries to adversary techniques
KQL language referenceComplete Kusto Query Language documentation
← Previous Lab All Labs Next Lab β†’