In this section
ES9.2 DeviceProcessEvents Deep Dive
The previous section covered endpoint hunting philosophy. This section covers deviceprocessevents deep dive.
Figure ES9.2. Five process-based hunting queries covering the most common endpoint attack patterns. Each query tests a specific hypothesis about attacker behavior in DeviceProcessEvents.
HUNT-PROC-001: Encoded PowerShell from unusual parents
Hypothesis: An attacker is using Base64-encoded PowerShell to execute commands that evade command-line based detections. The encoding is launched by a parent process that does not normally spawn PowerShell.
Anti-Pattern
Configuring without validating
The deviceprocessevents deep dive configuration is deployed based on documentation or vendor guidance, but nobody verifies it works in your environment. Deploy, then validate with a test that confirms the expected behavior. Every configuration has a verification query or test procedure, if you cannot verify it, you cannot trust it.
// HUNT-PROC-001: Encoded PowerShell from unusual parent processes
// Hypothesis: attacker uses encoded PS to evade command-line detections
// Expected results: 0-5 per week on a clean fleet (IT automation, Intune)
// Escalation: any result where the parent is NOT a known management tool
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName =~ "powershell.exe" or FileName =~ "pwsh.exe"
// Filter for encoded command patterns
| where ProcessCommandLine has_any (
"-enc ", "-encodedcommand ", "-e ", "FromBase64String",
"-EncodedCommand", "-EC "
)
// Exclude known management tools that legitimately use encoding
| where InitiatingProcessFileName !in~ (
"Microsoft.Management.Services.IntuneWindowsAgent.exe", // Intune
"CcmExec.exe", // SCCM
"MonitoringHost.exe", // SCOM
"MsSense.exe", // MDE sensor
"svchost.exe" // Scheduled tasks (review individually)
)
// Exclude SYSTEM account (most automation runs as SYSTEM)
| where AccountName !in ("SYSTEM", "LOCAL SERVICE", "NETWORK SERVICE")
| project Timestamp, DeviceName, AccountName,
ParentProcess = InitiatingProcessFileName,
ParentCmdLine = InitiatingProcessCommandLine,
EncodedCmdLine = ProcessCommandLine
| sort by Timestamp desc
Line-by-line: The 7-day lookback balances thoroughness with query performance. The encoded command patterns cover all common PowerShell encoding switches (including abbreviated forms). The parent process exclusion removes the 3 most common legitimate sources of encoded PowerShell at NE. The SYSTEM account exclusion removes scheduled tasks and services that use encoding. What remains: user-context encoded PowerShell from unexpected parents: the attacker's fingerprint.
Escalation criteria: Any result where the parent process is a browser, an Office application, or an unknown binary. Decode the Base64 content (in a sandbox) to determine the command payload.
HUNT-PROC-002: Office applications spawning execution engines
Hypothesis: A phishing attachment (macro-enabled document) executed and spawned a command shell or scripting engine as a child process.
// HUNT-PROC-002: Office child process spawning
// Hypothesis: macro-enabled phishing doc executing payload
// Expected results: 0 on clean fleet with ASR enabled (ASR blocks this)
// but ASR may be in audit mode or have exclusions
DeviceProcessEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName in~ (
"winword.exe", "excel.exe", "powerpnt.exe",
"outlook.exe", "msaccess.exe", "mspub.exe"
)
| where FileName in~ (
"cmd.exe", "powershell.exe", "pwsh.exe", "wscript.exe",
"cscript.exe", "mshta.exe", "rundll32.exe", "regsvr32.exe",
"certutil.exe", "bitsadmin.exe"
)
| project Timestamp, DeviceName, AccountName,
OfficeApp = InitiatingProcessFileName,
ChildProcess = FileName,
ChildCmdLine = ProcessCommandLine
| sort by Timestamp desc
Note: ASR rule "Block Office applications from creating child processes" prevents this technique when in block mode. This hunting query is valuable when: ASR is in audit mode (you are still in the graduated deployment from ES4), ASR has exclusions that might miss specific Office-to-child patterns, or you want to verify that ASR is working by confirming zero results.
HUNT-PROC-003: Script host execution from temp directories
Hypothesis: An attacker dropped a VBS/JS script to a temporary directory and executed it through wscript.exe or cscript.exe.
// HUNT-PROC-003: Script host from temp directories
// Hypothesis: dropped script executing from staging location
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName in~ ("wscript.exe", "cscript.exe")
| where ProcessCommandLine has_any (
"\\Temp\\", "\\AppData\\Local\\Temp\\",
"\\Downloads\\", "\\ProgramData\\",
"\\Users\\Public\\", "\\Windows\\Temp\\"
)
| where ProcessCommandLine !has "Microsoft Office" // Office add-in installer exclusion
| project Timestamp, DeviceName, AccountName,
ScriptHost = FileName,
ScriptPath = ProcessCommandLine,
ParentProcess = InitiatingProcessFileName
| sort by Timestamp desc
HUNT-PROC-004: rundll32 with anomalous arguments
Hypothesis: An attacker is abusing rundll32.exe to execute malicious DLLs, load remote content via URLs, or call specific LOLBin export functions (comsvcs MiniDump, javascript protocol handler).
// HUNT-PROC-004: rundll32 anomalous usage
// Hypothesis: LOLBin abuse — rundll32 executing non-standard DLLs or remote content
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName =~ "rundll32.exe"
| where ProcessCommandLine has_any (
"http://", "https://", // Remote DLL loading
"javascript:", // Script execution via protocol handler
"comsvcs", "MiniDump", // Credential dumping (also in NE-CRED-002)
"\\Temp\\", "\\AppData\\", // DLL from temp directory
"\\Downloads\\", "\\ProgramData\\" // DLL from staging directory
)
| where ProcessCommandLine !has "shell32.dll" // Common legitimate rundll32 usage
| where ProcessCommandLine !has "dfshim.dll" // .NET ClickOnce (legitimate)
| project Timestamp, DeviceName, AccountName,
CmdLine = ProcessCommandLine,
ParentProcess = InitiatingProcessFileName
| sort by Timestamp desc
HUNT-PROC-005: Executables running from suspicious locations
Hypothesis: An attacker staged a binary in a temp directory, recycle bin, or user profile path and executed it.
// HUNT-PROC-005: Process execution from suspicious filesystem locations
// Hypothesis: staged malware executing from non-standard locations
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FolderPath has_any (
"\\Temp\\", "\\$Recycle.Bin\\",
"\\AppData\\Local\\Temp\\", "\\Users\\Public\\",
"\\ProgramData\\", "\\Windows\\Temp\\",
"\\perflogs\\"
)
| where FileName endswith ".exe"
// Exclude known legitimate processes in these paths
| where FileName !in~ (
"msiexec.exe", "setup.exe", "install.exe", "update.exe",
"DismHost.exe", "TiWorker.exe", "MpCmdRun.exe"
)
// Focus on unsigned or unknown binaries
| summarize
ExecutionCount = count(),
Devices = dcount(DeviceName),
Users = dcount(AccountName),
FirstSeen = min(Timestamp),
LastSeen = max(Timestamp)
by FileName, FolderPath
| where Devices <= 3 // Rare binaries — present on few devices
| sort by ExecutionCount desc
This query uses a rarity filter: Devices <= 3 means the binary is present on 3 or fewer endpoints. Legitimate software is typically deployed broadly. Attacker tooling is present on only the compromised endpoints. The rarity filter dramatically reduces noise while highlighting the unusual.
Execute each HUNT-PROC query against the last 7 days. For each:
- Record the result count
- Review the top 10 results, classify as baseline (known-good), noise (legitimate but unusual), or finding (suspicious/malicious)
- For findings: document the device, user, command, and escalation recommendation
- For baseline: add the pattern to the query's exclusion list for future hunts
- For noise: note the pattern, if it recurs weekly, it becomes baseline
After running all 5, you have a process-level snapshot of your fleet's behavior. Repeat weekly, changes in the result set between weeks indicate either new legitimate activity (update exclusions) or new suspicious activity (investigate).
Interpreting process event results
When a hunting query returns results, each result needs classification. The classification framework for DeviceProcessEvents results:
Clearly benign: the process is a known legitimate application, running from a standard path, with expected command-line parameters, initiated by an expected parent process. Close the finding. If this pattern appears frequently, add it as an exclusion to the hunting query.
Clearly malicious: the process matches a known attack pattern (Mimikatz command line, encoded PowerShell download cradle, LOLBAS download), running from a temp directory, initiated by an unexpected parent. Escalate immediately as an incident. Preserve evidence (collect investigation package).
Ambiguous: the process could be legitimate or malicious. Examples: PowerShell with long command lines (could be IT automation or attacker obfuscation), unsigned executables (could be a custom business application or dropped malware), or processes running from user directories (could be a portable app or staged payload). For ambiguous findings: investigate further, check the user (IT admin or standard user?), check the timing (business hours or 02:00 AM?), check the broader context (any related alerts on this device?).
Document the classification for each finding in the hunt report. The classifications train your judgment: after classifying 100 findings, you develop intuition for what is normal in NE's environment and what warrants investigation.
The process event hunting results require context before classification. A PowerShell command with encoded parameters appears suspicious in isolation but may be a legitimate IT automation script that has been running daily for months. The context check: has this exact command been seen before on this device or from this user? Check the historical frequency by querying DeviceProcessEvents for the same command-line pattern over thirty days. A command that appears daily for the last three months is established baseline. A command that appeared for the first time today is novel and warrants investigation.
Compliance Context
Process events show WHAT ran. They do not show: what the process connected to (DeviceNetworkEvents. ES9.3), what files the process created or modified (DeviceFileEvents. ES9.4), what registry keys the process changed (DeviceRegistryEvents. ES9.4), how the user authenticated (DeviceLogonEvents. ES9.5), or what DLLs the process loaded (DeviceImageLoadEvents. ES9.5). A comprehensive hunt correlates process events with network, file, registry, logon, and image load events: the joined queries in ES9.6 provide this cross-table hunting capability. Process hunting is the foundation. Cross-table hunting provides the complete picture.
Five production hunting queries
Hunt 1: Rare executables in temp directories.
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FolderPath has_any ("\\Temp\\", "\\tmp\\")
| where FileName endswith ".exe"
| summarize ExecCount = count(), Devices = dcount(DeviceName) by FileName, FolderPath, SHA256
| where ExecCount < 10
| sort by ExecCount asc
Hunt 2: Reconnaissance command clustering (3+ recon commands in 1 hour).
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName in ("whoami.exe", "ipconfig.exe", "systeminfo.exe", "net.exe", "nltest.exe")
| summarize Commands = make_set(FileName), Count = count() by DeviceName, AccountName, bin(Timestamp, 1h)
| where Count > 3
Hunt 3: PowerShell with download indicators.
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName == "powershell.exe"
| where ProcessCommandLine has_any ("downloadstring", "downloadfile", "iex", "-enc", "frombase64string")
| project Timestamp, DeviceName, ProcessCommandLine, AccountName
Each result needs investigation: who ran it, from what parent process, and was the activity authorized?
Troubleshooting
"HUNT-PROC-005 returns 200+ results. I cannot review them all." The query is correctly finding rare binaries in suspicious paths, but 200+ is too many to manually review. Tighten the rarity filter: change Devices <= 3 to Devices == 1 (present on exactly one device). This surfaces the rarest binaries, most likely attacker tooling or one-off IT testing. Also: add the | where ExecutionCount > 1 filter to focus on binaries that were executed multiple times (persistent activity, not one-off testing).