Azure Run Command Correlated with Process Execution

Correlates successful Azure Virtual Machine Run Command operations with endpoint process execution on the same host within minutes. Adversaries abuse Run Command to run scripts remotely as SYSTEM or root while activity logs only record the control-plane action; Elastic Defend process telemetry reveals the on-guest payload.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2026/05/20"
  3integration = ["azure", "endpoint"]
  4maturity = "production"
  5updated_date = "2026/05/20"
  6
  7[rule]
  8author = ["Elastic"]
  9description = """
 10Correlates successful Azure Virtual Machine Run Command operations with endpoint process execution on the same host
 11within minutes. Adversaries abuse Run Command to run scripts remotely as SYSTEM or root while activity logs only record the
 12control-plane action; Elastic Defend process telemetry reveals the on-guest payload.
 13"""
 14false_positives = [
 15    """
 16    Legitimate automation that deploys configuration via Azure Run Command and launches PowerShell with unrestricted
 17    policy and numbered script files (for example `script1.ps1`) may match. Baseline known deployment pipelines, VM
 18    names, and principal IDs before tuning.
 19    """,
 20]
 21from = "now-9m"
 22language = "esql"
 23license = "Elastic License v2"
 24name = "Azure Run Command Correlated with Process Execution"
 25note = """## Triage and analysis
 26
 27### Investigating Azure Run Command Correlated with Process Execution
 28
 29This ES|QL rule correlates Azure Activity Log `MICROSOFT.COMPUTE/VIRTUALMACHINES/RUNCOMMAND/ACTION` events with
 30endpoint process starts, joined on host name within a two-minute bucket and a 0–120 second delay between Run Command and process start.
 31
 32Pivot into raw `logs-azure.activitylogs-*` and `logs-endpoint.events.process-*` events for full command lines and
 33resource identifiers.
 34
 35### Possible investigation steps
 36
 37- Review `user.email` and `azure.activitylogs.identity.authorization.evidence.principal_id` for who invoked Run Command.
 38- Inspect `Esql.process_command_line_values` for script paths and arguments beyond the matched pattern.
 39- Confirm `Esql.host_name` maps to the intended VM and whether Run Command timing aligns with change windows.
 40- Hunt for additional Run Command or PowerShell activity from the same principal or subscription.
 41
 42### Response and remediation
 43
 44- If unauthorized, isolate the VM, revoke credentials used for Run Command, and review role assignments on the VM and
 45  subscription.
 46- Collect endpoint artifacts and Azure activity logs for incident reporting.
 47"""
 48references = [
 49    "https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#virtual-machine-contributor",
 50    "https://posts.specterops.io/attacking-azure-azure-ad-and-introducing-powerzure-ca70b330511a",
 51    "https://adsecurity.org/?p=4277",
 52]
 53risk_score = 47
 54rule_id = "ebbc1959-3309-4abf-b6cb-2bee3dbc9a7b"
 55severity = "medium"
 56tags = [
 57    "Domain: Cloud",
 58    "Domain: Endpoint",
 59    "OS: Windows",
 60    "OS: Linux",
 61    "Use Case: Threat Detection",
 62    "Tactic: Execution",
 63    "Data Source: Azure",
 64    "Data Source: Microsoft Azure",
 65    "Data Source: Azure Activity Logs",
 66    "Data Source: Elastic Defend",
 67    "Resources: Investigation Guide",
 68]
 69timestamp_override = "event.ingested"
 70type = "esql"
 71
 72query = '''
 73FROM logs-azure.activitylogs-*, logs-endpoint.events.process-* METADATA _id, _version, _index
 74| WHERE 
 75  (
 76    event.category == "process" AND KQL("event.action:start")
 77    AND process.parent.name == "powershell.exe"
 78    AND process.parent.command_line LIKE "powershell  -ExecutionPolicy Unrestricted -File script?.ps1"
 79    AND process.name != "conhost.exe"
 80  ) OR
 81  (
 82    KQL("event.category:process and event.action:exec and process.parent.name:(dash or bash or sh) and process.parent.args:/var/lib/waagent/run-command/download/*/script.sh")
 83   ) OR 
 84  (
 85    event.module == "azure"
 86    AND event.action == "MICROSOFT.COMPUTE/VIRTUALMACHINES/RUNCOMMAND/ACTION"
 87    AND NOT KQL("event.outcome:failure")
 88   )
 89
 90// Azure hostname comes as upper-case while Endpoint event comes as lowercase
 91| EVAL Esql.host_name = COALESCE(
 92    TO_LOWER(host.name),
 93    TO_LOWER(azure.resource.name)
 94  )
 95| EVAL ts_runcommand = CASE(event.module == "azure", @timestamp, null)
 96| EVAL ts_endpoint = CASE(event.category == "process", @timestamp, null)
 97| EVAL is_runcommand = CASE(event.module == "azure", 1, null)
 98| EVAL is_endpoint = CASE(event.category == "process", 1, null)
 99| EVAL Esql.time_bucket = DATE_TRUNC(2 minutes, @timestamp)
100| STATS
101    runcommand_count = COUNT(is_runcommand),
102    endpoint_count = COUNT(is_endpoint),
103    user.email = VALUES(user.email),
104    azure.activitylogs.identity.authorization.evidence.principal_id = VALUES(azure.activitylogs.identity.authorization.evidence.principal_id),
105    azure.activitylogs.tenant_id = VALUES(azure.activitylogs.tenant_id),
106    azure.subscription_id = VALUES(azure.subscription_id),
107    source.ip = VALUES(source.ip),
108    source.geo.country_name = VALUES(source.geo.country_name),
109    source.as.number = VALUES(source.as.number),
110    Esql.process_command_line_values = VALUES(process.command_line),
111    first_runcommand = MIN(ts_runcommand),
112    first_ps_exec = MIN(ts_endpoint),
113    outcome = VALUES(event.outcome)
114  BY Esql.host_name, Esql.time_bucket
115| WHERE runcommand_count >= 1 AND endpoint_count >= 1
116| EVAL delta_ms = TO_LONG(first_ps_exec) - TO_LONG(first_runcommand)
117| EVAL delta_sec = delta_ms / 1000
118| WHERE delta_sec >= 0 AND delta_sec <= 120
119| KEEP
120    user.email,
121    azure.activitylogs.identity.authorization.evidence.principal_id,
122    source.ip,
123    source.as.number,
124    source.geo.country_name,
125    azure.activitylogs.tenant_id,
126    azure.subscription_id,
127    Esql.*
128'''
129
130
131[[rule.threat]]
132framework = "MITRE ATT&CK"
133
134[[rule.threat.technique]]
135id = "T1059"
136name = "Command and Scripting Interpreter"
137reference = "https://attack.mitre.org/techniques/T1059/"
138
139[[rule.threat.technique.subtechnique]]
140id = "T1059.001"
141name = "PowerShell"
142reference = "https://attack.mitre.org/techniques/T1059/001/"
143
144[[rule.threat.technique]]
145id = "T1651"
146name = "Cloud Administration Command"
147reference = "https://attack.mitre.org/techniques/T1651/"
148
149[rule.threat.tactic]
150id = "TA0002"
151name = "Execution"
152reference = "https://attack.mitre.org/tactics/TA0002/"

Triage and analysis

Investigating Azure Run Command Correlated with Process Execution

This ES|QL rule correlates Azure Activity Log MICROSOFT.COMPUTE/VIRTUALMACHINES/RUNCOMMAND/ACTION events with endpoint process starts, joined on host name within a two-minute bucket and a 0–120 second delay between Run Command and process start.

Pivot into raw logs-azure.activitylogs-* and logs-endpoint.events.process-* events for full command lines and resource identifiers.

Possible investigation steps

  • Review user.email and azure.activitylogs.identity.authorization.evidence.principal_id for who invoked Run Command.
  • Inspect Esql.process_command_line_values for script paths and arguments beyond the matched pattern.
  • Confirm Esql.host_name maps to the intended VM and whether Run Command timing aligns with change windows.
  • Hunt for additional Run Command or PowerShell activity from the same principal or subscription.

Response and remediation

  • If unauthorized, isolate the VM, revoke credentials used for Run Command, and review role assignments on the VM and subscription.
  • Collect endpoint artifacts and Azure activity logs for incident reporting.

References

Related rules

to-top