Microsoft Defender KQL Queries that detect common privilege-escalation behaviors

1 — High-fidelity: explorer.exe spawning suspicious children (KQL)

// Explorer -> suspicious child process (high fidelity)
DeviceProcessEvents
| where Timestamp >= ago(30d)
| where InitiatingProcessFileName == “explorer.exe”
| where FileName in (“cmd.exe”,”powershell.exe”,”pwsh.exe”,”cscript.exe”,”wscript.exe”,”mshta.exe”,”rundll32.exe”,”regsvr32.exe”)
| project Timestamp, DeviceName, DeviceId, InitiatingProcessFileName, InitiatingProcessCommandLine,
FileName, ProcessCommandLine, ProcessTokenElevation, InitiatingProcessTokenElevation,
InitiatingProcessAccountName, AccountDomain, ReportId
| sort by Timestamp desc

2 — Detect suspicious elevation events (parent not elevated → child elevated)

Why: A process becomes elevated while its parent was not — possible UAC bypass, token manipulation, or exploit attempt.

// Parent not elevated but created an elevated child (possible UAC bypass / token abuse)
DeviceProcessEvents
| where Timestamp >= ago(30d)
| where ProcessTokenElevation == “TokenElevationTypeFull” // child is elevated
| where InitiatingProcessTokenElevation != “TokenElevationTypeFull” // parent not elevated
| where InitiatingProcessFileName !in (“services.exe”,”winlogon.exe”,”lsass.exe”) // short whitelist
| project Timestamp, DeviceName, InitiatingProcessFileName, InitiatingProcessCommandLine,
FileName, ProcessCommandLine, InitiatingProcessTokenElevation, ProcessTokenElevation,
InitiatingProcessAccountName, AccountDomain, ReportId
| sort by Timestamp desc

3 — Service creation / installation events (typical ESCALATION persistence)

Why: Installing or modifying services is a common privilege-escalation/persistence technique.

// New or modified Windows service creation (DeviceEvents table)
DeviceEvents
| where Timestamp >= ago(30d)
| where ActionType in (“ServiceInstalled”, “ServiceCreated”, “ServiceModified”)
| project Timestamp, DeviceName, ActionType, InitiatingProcessFileName, InitiatingProcessCommandLine,
AdditionalFields, InitiatingProcessAccountName, ReportId
| sort by Timestamp desc

4 — Scheduled Task creation (another persistence / escalation vector)

// Detect Scheduled Task creation/modification
DeviceEvents
| where Timestamp >= ago(30d)
| where ActionType in (“ScheduledTaskCreated”, “ScheduledTaskUpdated”, “ScheduledTaskRegistered”)
| project Timestamp, DeviceName, ActionType, InitiatingProcessFileName, InitiatingProcessCommandLine,
AdditionalFields, InitiatingProcessAccountName, ReportId
| sort by Timestamp desc

5 — Local admin or privileged account creation (explicit escalation)

Why: Attackers sometimes create local accounts or add users to privileged groups.

// Local user created OR user added to privileged group (DeviceEvents)
DeviceEvents
| where Timestamp >= ago(30d)
| where ActionType in (“UserAccountCreated”,”UserAddedToLocalGroup”,”LocalGroupMemberAdded”)
| project Timestamp, DeviceName, ActionType, InitiatingProcessFileName, InitiatingProcessCommandLine,
AccountName = tostring(parse_json(AdditionalFields).TargetAccountName),
GroupName = tostring(parse_json(AdditionalFields).GroupName),
InitiatingProcessAccountName, ReportId
| sort by Timestamp desc

6 — Cross-table enrichment: process creation to privileged logon events

Combine process creation with privileged logons (DeviceLogonEvents) to raise confidence.

// Join process creation with privileged logon events within 1 minute
let procs = DeviceProcessEvents
| where Timestamp >= ago(30d)
| where FileName in (“cmd.exe”,”powershell.exe”,”rundll32.exe”,”regsvr32.exe”)
| project pTime = Timestamp, DeviceId, DeviceName, FileName, ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessAccountName, ProcessTokenElevation, ReportId;
DeviceLogonEvents
| where Timestamp >= ago(30d)
| where ActionType == “LogonWithElevatedPrivileges” or LogonType == “Interactive” // adjust based on your schema
| project lTime = Timestamp, DeviceId, AccountName = AccountName, LogonType, LogonResult
| join kind=inner (procs) on DeviceId
| where datetime_diff(‘second’, pTime, lTime) between (-60 .. 60)
| project pTime, lTime, DeviceName, InitiatingProcessFileName, FileName, ProcessCommandLine, InitiatingProcessAccountName, AccountName, ProcessTokenElevation, ReportId
| sort by pTime desc
  1. In Microsoft 365 Defender portal → Advanced hunting → paste and verify query.
  2. Click Create detection rule → choose severity.
  3. Add automatic response actions (isolate device, collect investigation package) only if your runbook and testing support it. Start with alerting + manual triage for high-noise queries.
  4. Add suppression / whitelists (device names, known admin tools, backup windows) to reduce noise.