[New Rule] Unusual Azure VM Extension Installed; Suspicious Child Process via Azure VM CustomScript Extension#6277
Conversation
Rule: New - GuidelinesThese guidelines serve as a reminder set of considerations when proposing a new rule. Documentation and Context
Rule Metadata Checks
New BBR Rules
Testing and Validation
|
…ibling; adjusts the intent of unusual extension
|
⛔️ Test failed Results
|
|
⛔️ Test failed Results
|
There was a problem hiding this comment.
Pull request overview
This PR adds two new detection rules focused on Azure VM extension abuse: one control-plane rule that surfaces first-seen VM extension instance names per host from Azure Activity Logs, and one endpoint rule that detects suspicious process execution associated with the Azure CustomScript extension handler on Windows.
Changes:
- Adds an ES|QL rule to alert on first-seen
(VM, extension instance name)pairs inlogs-azure.activitylogs-*. - Adds an EQL rule to detect suspicious Windows child process execution tied to
CustomScriptHandler.exe. - Includes investigation guides and ATT&CK mappings for both rules.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 10 comments.
| File | Description |
|---|---|
| rules/windows/execution_azure_customscript_extension_suspicious_descendant.toml | New Windows endpoint EQL rule for suspicious process execution associated with Azure CustomScript extension activity. |
| rules/integrations/azure/execution_azure_vm_extension_unusual_for_host.toml | New Azure Activity Logs ES |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
⛔️ Test failed Results
|
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
⛔️ Test failed Results
|
|
⛔️ Test failed Results
|
| note = """## Triage and analysis | ||
|
|
||
| ### Investigating Unusual Azure VM Extension Detected | ||
|
|
||
| Identifies the first time a given VM extension name is created or updated on an Azure virtual machine or VM scale set | ||
| historically. VM extensions run with high privilege on the guest (SYSTEM on Windows, root on Linux) and are a | ||
| common code-execution and persistence primitive. The extension instance name is attacker-controlled and the Azure | ||
| activity log records only that name, not the publisher or type, so the control plane cannot reliably identify the | ||
| extension family (for example CustomScript). This rule therefore takes a type-agnostic ES|QL new-terms approach: it | ||
| derives the host and the extension instance name from `azure.resource.name` and alerts the first time a given | ||
| (host, extension name) pair is observed in the window, surfacing novel extension deployments while suppressing names a | ||
| host routinely uses. | ||
|
|
||
| ### Possible investigation steps | ||
|
|
||
| - Identify the host (`Esql.vm_name`) and the full extension resource (`azure.resource.name` / `azure.resource.id`). | ||
| - Identify the acting principal: `Esql.principal_id_values`, `Esql.principal_type_values` (User vs ServicePrincipal), | ||
| `Esql.appid_values`. Service principal or managed identity deployment is more suspicious than a known admin user. | ||
| - Review the source: `Esql.source_ip_values`, `Esql.source_as_number_values`, `Esql.source_country_values`. Cloud | ||
| hosting, VPS, or anonymizing networks are more suspicious than known corporate egress. | ||
| - Was this preceded by a Run Command invocation, role assignment, or other VM operations by the same principal? | ||
| - Correlate with endpoint telemetry on the host: process activity parented by the Azure guest agent | ||
| (`WaAppAgent.exe` / `walinuxagent`) within ~120 seconds of the deployment. | ||
| - Review the principal's Entra ID sign-in logs and RBAC role assignments on the subscription, resource group, and VM. | ||
| - Retrieve the extension settings/protected settings from the VM (the activity log does not contain the script/settings | ||
| body) to assess intent. | ||
| - Pivot on the VM for credential access, new local accounts, or outbound C2 connections following the deployment. | ||
|
|
||
| ### False positive analysis | ||
|
|
||
| - This is a broad first-seen net: the first deployment of any extension name to a host alerts, so benign monitoring, | ||
| antimalware (Defender/MDE), AKS, DSC, or configuration-management extensions deployed by routine automation will | ||
| trigger. Baseline expected automation principals (`Esql.appid_values`) and extension names, and exclude verified ones. | ||
| - Automation that generates a unique extension instance name per deployment produces a new (host, name) pair every time | ||
| and will recur; if benign, exclude by the deploying principal/appid or the known naming pattern rather than per host. | ||
| - Newly provisioned VMs receiving their initial extension set are expected. Corroborate the deploying principal and | ||
| source before escalating, and treat deployments from known corporate egress by approved automation as lower confidence. | ||
|
|
||
| ### Response and remediation | ||
|
|
||
| - If unauthorized, remove the extension, isolate the VM, rotate credentials reachable from it, and review RBAC on the | ||
| affected scope. | ||
| - Collect endpoint and activity log artifacts per incident procedures. |
There was a problem hiding this comment.
nit: Remove multiline for better formatting
| // new terms emulation: fire only when the (host, extension name) pair is the single occurrence in the | ||
| // 7-day window (event_count == 1) and it is recent (within the schedule interval + ingest-lag buffer) | ||
| | EVAL Esql.recent_minutes = DATE_DIFF("minute", Esql.first_time_seen, NOW()) | ||
| | WHERE Esql.recent_minutes <= 10 AND Esql.event_count == 1 |
There was a problem hiding this comment.
Just a comment: an attacker who deploys and then modifies their extension only generates one alert at deploy time. Will this be caught in a different rule?
| note = """## Triage and analysis | ||
| ### Investigating Suspicious Child Process via Azure VM CustomScript Extension | ||
| The Azure CustomScript extension executes a script as SYSTEM via the guest agent. The extension's resource name is | ||
| attacker-controlled and not present on the host, so this rule anchors on the handler binary path | ||
| (`Microsoft.Compute.CustomScriptExtension\\...\\CustomScriptHandler.exe`), which is rename-proof, and alerts when a | ||
| LOLBin or suspicious PowerShell runs anywhere in its process tree. | ||
| ### Possible investigation steps | ||
| - Review the full process tree from `CustomScriptHandler.exe` to the alerting process, including `process.command_line` | ||
| and `process.args`. | ||
| - Identify the descendant: execution proxies (`mshta`, `regsvr32`, `rundll32`, `installutil`, `msbuild`), download tools | ||
| (`certutil`, `bitsadmin`), script hosts (`wscript`, `cscript`), or discovery utilities (`whoami`, `net`, `nltest`, | ||
| `wmic`) are not expected children of a benign CustomScript payload. | ||
| - Correlate with the control-plane event: a `MICROSOFT.COMPUTE/VIRTUALMACHINES/EXTENSIONS/WRITE` in | ||
| `logs-azure.activitylogs-*` for this host around the same time, and the acting principal/source behind it. | ||
| - Retrieve the extension's settings/protectedSettings from the VM (the activity log does not contain the script body) to | ||
| assess intent. | ||
| - Pivot on the host for credential access, new local accounts, persistence, or outbound C2 following the execution. | ||
| - Review who deployed the extension (Entra sign-in logs and RBAC for the principal in the correlated activity log event). | ||
| ### False positive analysis | ||
| - Infrastructure-as-code and configuration-management scripts deployed via CustomScript may legitimately run discovery | ||
| utilities (`whoami`, `net`, `nltest`, `systeminfo`, `wmic`, `tasklist`, `arp`) for bootstrap or inventory. If the | ||
| activity recurs from known automation, baseline it and exclude by `process.command_line`/`process.args`. | ||
| - Software installation and bootstrapping via CustomScript can invoke `msbuild`, `installutil`, `regsvr32`, `regasm`, | ||
| `regsvcs`, `certutil`, or `bitsadmin` to build, register, or download legitimate components. Verify the target | ||
| file/URL and, if benign, scope the exclusion to the specific command or signed binary rather than the whole LOLBin. | ||
| - Legitimate setup scripts (DSC bootstrap, agent installers) may use PowerShell download cradles | ||
| (`Invoke-WebRequest`, `DownloadString`, `-EncodedCommand`) against trusted internal or Microsoft endpoints. Confirm | ||
| the destination host and content before excluding, and exclude by the specific command line, not by host. | ||
| - A known automation principal deploying the extension from expected corporate egress (corroborated by the correlated | ||
| `MICROSOFT.COMPUTE/VIRTUALMACHINES/EXTENSIONS/WRITE` and an approved change) lowers confidence, but still review the | ||
| executed content. Prefer narrow, command- or argument-scoped exclusions over broad host or LOLBin exclusions, since | ||
| the same execution chain is exactly what an attacker abuses. | ||
| ### Response and remediation | ||
| - If unauthorized, remove the extension, isolate the host, rotate credentials reachable from it, and review RBAC on the | ||
| affected subscription/resource group. |
There was a problem hiding this comment.
nit: Remove multiline for better formatting
| (process.name : ("powershell.exe", "pwsh.exe") and | ||
| process.command_line : ("*-enc*", "*EncodedCommand*", "*FromBase64String*", "*DownloadString*", "*DownloadFile*", | ||
| "*Invoke-Expression*", "*IEX *", "* -w hidden*", "*WindowStyle Hidden*", "*Net.WebClient*", | ||
| "*Invoke-WebRequest*", "*Start-BitsTransfer*")) |
There was a problem hiding this comment.
Maybe consider adding "IEX(" and "|IEX" and "-w hidden" without the leading space?
Pull Request
Issue link(s):
Summary - What I changed
Adds detection for extensions installed on Azure VMs that are not native (default) and have never been seen before
azure.resource.namein the tenant. Extensions are post-install scripts that execute commands at higher system level privileges. These have historically been abused by adversaries post serial connection to VMs.How To Test
Query can be used in TRADE stack and other telemetry stacks.
Checklist
bug,enhancement,schema,maintenance,Rule: New,Rule: Deprecation,Rule: Tuning,Hunt: New, orHunt: Tuningso guidelines can be generatedmeta:rapid-mergelabel if planning to merge within 24 hoursContributor checklist