Query Details
# *Multi-Stage Browser Exploitation & Post-Compromise Detection*
## Query Information
#### MITRE ATT&CK Technique(s)
| Technique ID | Title | Link |
| --- | --- | --- |
| T1055 | Process Injection | https://attack.mitre.org/techniques/T1055 |
| T1203 | Exploit for Client Execution | https://attack.mitre.org/techniques/T1203/ |
#### Description
This query identifies high-confidence browser-based attacks by correlating three distinct suspicious behaviors: Remote Code Injection (memory writes), Anomalous Process Spawning (LOLBins and shell commands), and the loading of Unsigned Modules from sensitive user directories.
To minimize false positives, it utilizes a robust verification logic that cross-references known benign injectors and system paths. The results are aggregated per process session and categorized into a severity-based scoring system, allowing security analysts to prioritize incidents where multiple attack vectors converge on a single browser instance.
#### Author <Optional>
- **Name: Benjamin Zulliger**
- **Github: https://github.com/benscha/KQLAdvancedHunting**
- **LinkedIn: https://www.linkedin.com/in/benjamin-zulliger/**
#### References
-
## Defender XDR
```KQL
// =============================================================================
// Browser Attack Detection – Optimized
// Detects: Remote Injection, Shell-Spawning, Unsigned Module Loads in Browsers
// =============================================================================
// ── Configuration ─────────────────────────────────────────────────────────────
let LookbackPeriod = 24h;
let Browsers = dynamic([
"msedge.exe",
"chrome.exe",
"brave.exe",
"firefox.exe"
]);
// High-risk LOLBins → flag directly
// cmd.exe is handled separately with a CommandLine pattern check
let HighRiskBinaries = dynamic([
"powershell.exe",
"pwsh.exe",
"wscript.exe",
"cscript.exe",
"mshta.exe",
"bitsadmin.exe",
"rundll32.exe",
"regsvr32.exe",
"certutil.exe"
]);
// Suspicious cmd.exe patterns: only flag if cmd.exe itself
let SuspiciousCmdPatterns = dynamic([
"powershell",
"encoded",
"bypass",
"hidden",
"invoke",
"iex",
"downloadstring",
"downloadfile",
"webclient",
"curl ",
"wget ",
"certutil",
"bitsadmin",
"regsvr32",
"mshta",
"wscript",
"cscript",
".ps1",
".vbs",
".hta",
".bat",
"/c reg add",
"/c sc ",
"/c net ",
"base64"
]);
// Known legitimate injectors (process names)
// Checked in combination with KnownBenignPaths (Name + Path)
let KnownBenignInjectors = dynamic([
"msedge.exe",
"chrome.exe",
"firefox.exe",
"brave.exe",
"svchost.exe",
"memcompression.exe",
"msmpeng.exe",
"senseir.exe",
"csfalconservice.exe"
]);
// Unified path exclusion list – used in BOTH subqueries:
// BrowserInjection → checked against InitiatingProcessFolderPath
// BrowserSpawnedHighRisk → checked against ProcessCommandLine (SpawnedCmdLine)
let KnownBenignPaths = dynamic([
@"C:\Windows\System32",
@"C:\Windows\SysWOW64",
@"C:\Program Files\Windows Defender",
@"C:\Program Files\Microsoft Security Client",
@"system32\spool\DRIVERS", // Printer drivers (e.g., rundll32 + HP-DLL)
@"Windows Security\BrowserCore", // Edge BrowserCore (legitimate SSO broker)
@"Windows\BrowserCore",
@"Acrobat DC\Acrobat\Browser"
]);
// ── Remote Thread Injection / Memory Write in Browser ─────────────
let BrowserInjection =
DeviceEvents
| where Timestamp > ago(LookbackPeriod)
| where ActionType in ("CreateRemoteThreadApiCall", "WriteProcessMemoryApiCall")
| extend TargetProcessName = tostring(parse_json(AdditionalFields).TargetProcessName)
| where TargetProcessName in~ (Browsers)
| mv-apply _path = KnownBenignPaths to typeof(string) on (
summarize _benignPathCount = countif(InitiatingProcessFolderPath contains _path)
)
// Exclusion: known injector name AND from a known path
| where not (
InitiatingProcessFileName in~ (KnownBenignInjectors)
and _benignPathCount > 0
)
| project
Timestamp,
DeviceName,
InitiatingProcessId,
InitiatingProcessFileName,
InitiatingProcessFolderPath,
InitiatingProcessCommandLine,
InitiatingProcessAccountName,
TargetProcessName,
SpawnedCmdLine = "",
DetailFile = FileName,
DetailPath = FolderPath,
ActionType,
Activity = "Browser Injection";
// ── Browser spawns high-risk LOLBins ─────────────────────────
let BrowserSpawnedHighRisk =
DeviceProcessEvents
| where Timestamp > ago(LookbackPeriod)
| where InitiatingProcessFileName in~ (Browsers)
| where FileName in~ (HighRiskBinaries)
| mv-apply _path = KnownBenignPaths to typeof(string) on (
summarize _benignPathCount = countif(ProcessCommandLine contains _path)
)
| where _benignPathCount == 0
| project
Timestamp,
DeviceName,
InitiatingProcessId,
InitiatingProcessFileName,
InitiatingProcessFolderPath,
InitiatingProcessCommandLine,
InitiatingProcessAccountName,
TargetProcessName = FileName,
SpawnedCmdLine = ProcessCommandLine,
DetailFile = FileName,
DetailPath = FolderPath,
ActionType,
Activity = "Browser Spawned LOLBin/Shell";
// ── Browser spawns cmd.exe – only with suspicious arguments ───────
// Browser → cmd.exe is normal OS behavior (protocol handlers, opening links).
// Only flag if the cmd.exe CommandLine itself contains something suspicious.
let BrowserSpawnedSuspiciousCmd =
DeviceProcessEvents
| where Timestamp > ago(LookbackPeriod)
| where InitiatingProcessFileName in~ (Browsers)
| where FileName =~ "cmd.exe"
| where isnotempty(ProcessCommandLine)
| where ProcessCommandLine has_any (SuspiciousCmdPatterns)
| mv-apply _path = KnownBenignPaths to typeof(string) on (
summarize _benignPathCount = countif(ProcessCommandLine contains _path)
)
| where _benignPathCount == 0
| project
Timestamp,
DeviceName,
InitiatingProcessId,
InitiatingProcessFileName,
InitiatingProcessFolderPath,
InitiatingProcessCommandLine,
InitiatingProcessAccountName,
TargetProcessName = FileName,
SpawnedCmdLine = ProcessCommandLine,
DetailFile = FileName,
DetailPath = FolderPath,
ActionType,
Activity = "Browser Spawned LOLBin/Shell";
// ── Unsigned Module Load by Browser from suspicious paths ────
let SuspiciousModuleLoad =
DeviceImageLoadEvents
| where Timestamp > ago(LookbackPeriod)
| where InitiatingProcessFileName in~ (Browsers)
| where IsCertificateValidated != true
| where FolderPath has_any (
@"\Users\",
@"\ProgramData\",
@"\Temp\",
@"\AppData\Local\Temp\",
@"\AppData\Roaming\"
)
| where FileName !in~ (
"d3dcompiler_47.dll",
"libEGL.dll",
"libGLESv2.dll",
"vk_swiftshader.dll",
"vulkan-1.dll"
)
| project
Timestamp,
DeviceName,
InitiatingProcessId,
InitiatingProcessFileName,
InitiatingProcessFolderPath,
InitiatingProcessCommandLine,
InitiatingProcessAccountName,
TargetProcessName = "",
SpawnedCmdLine = "",
DetailFile = FileName,
DetailPath = FolderPath,
ActionType = "",
Activity = "Unsigned Module In Browser";
// ── Correlation & Scoring ─────────────────────────────────────────────────────
union isfuzzy=true
BrowserInjection,
BrowserSpawnedHighRisk,
BrowserSpawnedSuspiciousCmd,
SuspiciousModuleLoad
// Collect all activities per browser process + device
| summarize
Activities = make_set(Activity),
ActivityCount = dcount(Activity),
FirstSeen = min(Timestamp),
LastSeen = max(Timestamp),
InjectedInto = make_set_if(TargetProcessName, Activity == "Browser Injection"),
SpawnedBinaries = make_set_if(DetailFile, Activity == "Browser Spawned LOLBin/Shell"),
SpawnedCmdLines = make_set_if(SpawnedCmdLine, Activity == "Browser Spawned LOLBin/Shell"),
LoadedModules = make_set_if(DetailPath, Activity == "Unsigned Module In Browser"),
BrowserCmdLines = make_set(InitiatingProcessCommandLine),
AccountName = take_any(InitiatingProcessAccountName)
by
DeviceName,
InitiatingProcessFileName,
InitiatingProcessId
// ── Score-based Filtering ──────────────────────────────────────────────────
| extend Score =
iff(Activities has "Browser Injection", 3, 0) +
iff(Activities has "Browser Spawned LOLBin/Shell", 2, 0) +
iff(Activities has "Unsigned Module In Browser", 1, 0)
| where Score >= 2
// ── Severity Label for Triage ──────────────────────────────────────────────────
| extend Severity = case(
Score >= 5, "Critical",
Score >= 3, "High",
Score >= 2, "Medium",
"Low"
)
```
This KQL query is designed to detect potential browser-based attacks by looking for specific suspicious activities. It focuses on identifying three main behaviors that could indicate a security threat:
Remote Code Injection: This involves unauthorized memory writes or thread creation in browser processes, which could suggest an attempt to inject malicious code.
Anomalous Process Spawning: This checks if browsers are starting high-risk programs (like PowerShell or other command-line utilities) that could be used for malicious purposes.
Unsigned Module Loads: This looks for browsers loading modules from unusual or sensitive directories without proper digital signatures, which can be a sign of tampering.
The query uses a set of known safe processes and paths to reduce false positives, ensuring that only genuinely suspicious activities are flagged. It aggregates the results by process session and assigns a severity score based on the combination of detected activities. This scoring helps prioritize incidents, with higher scores indicating a greater potential threat. The query is part of a broader effort to enhance security monitoring by identifying complex, multi-stage attacks that target web browsers.

Benjamin Zulliger
Released: May 11, 2026
Tables
Keywords
Operators