azure-auto-hybrid-worker-rce

Submit a runbook job targeting a Hybrid Runbook Worker Group; the runbook runs as LOCAL SYSTEM (or a stored credential) on the designated VM/on-prem host.

derived azure emits CanExecuteCommand

match

A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.

{'principal': None} CanTrigger {'runbook': None} {'runbook': None} LocatedIn {'workerGroup': None}

where

node_type(?runbook) == GenericCompute node_type(?workerGroup) == RemoteManagementService ?workerGroup has at least one registered HybridRunbookWorker (worker node) job is submitted with runOn = ?workerGroup.name

emit

source typeIdentity
target typeVirtualMachine
source?principal
target<worker VM(s) registered in ?workerGroup>
permissionsMicrosoft.Automation/automationAccounts/jobs/write
conditionsservice_state
state logicACTIVE when the principal holds jobs/write AND the targeted HybridRunbookWorkerGroup has registered workers AND the account is not suspended. CONDITIONAL(service_state) when the worker group has no currently registered workers (workers may register later). Inherit from CanTrigger edge: BLOCKED if jobs/write is covered by a deny assignment.

Narrative

{principal.name} can submit a runbook job to Hybrid Runbook Worker Group {workerGroup.name} (automationAccounts/jobs/write with runOn={workerGroup.name}); the runbook executes arbitrary PowerShell/Python as LOCAL SYSTEM on worker VM {target.name}, yielding RCE on the host and any identity the VM runs as.

Raw rule rules/derived/azure/automation.yaml

id: azure-auto-hybrid-worker-rce
emits: CanExecuteCommand
description: Submit a runbook job targeting a Hybrid Runbook Worker Group; the runbook runs as LOCAL SYSTEM
  (or a stored credential) on the designated VM/on-prem host.
match:
- - principal: null
  - CanTrigger
  - runbook: null
- - runbook: null
  - LocatedIn
  - workerGroup: null
where:
- node_type(?runbook) == GenericCompute
- node_type(?workerGroup) == RemoteManagementService
- ?workerGroup has at least one registered HybridRunbookWorker (worker node)
- job is submitted with runOn = ?workerGroup.name
emit:
  source_type: Identity
  target_type: VirtualMachine
  source: ?principal
  target: <worker VM(s) registered in ?workerGroup>
  permissions:
  - Microsoft.Automation/automationAccounts/jobs/write
  conditions:
  - service_state
  state_logic: 'ACTIVE when the principal holds jobs/write AND the targeted HybridRunbookWorkerGroup has
    registered workers AND the account is not suspended. CONDITIONAL(service_state) when the worker group
    has no currently registered workers (workers may register later). Inherit from CanTrigger edge: BLOCKED
    if jobs/write is covered by a deny assignment.'
  confidence: 0.93
  derived_from:
  - 'azure-auto-jobs-write: ?principal CanTrigger ?runbook'
  - 'can-execute-as.yaml: execute-as-via-command (CanExecuteCommand + ExecutesAs => CanExecuteAs on worker
    VM''s identity)'
  - 'cicd-chains.yaml: cicd-modify-buildspec-executes-as (if principal also CanModifyCode the runbook)'
  false_positive_note: "Hybrid Worker RCE targets the PHYSICAL WORKER VM, not the cloud sandbox. The runbook\
    \ executes as LOCAL SYSTEM (Windows) or the configured user (Linux) on the worker host \u2014 this\
    \ is OS-level command execution, not just MI token access. Only emit when the job includes runOn=<HybridWorkerGroup>\
    \ and at least one registered worker exists in that group. Cloud-only jobs (no runOn) route to the\
    \ managed sandbox and do NOT produce CanExecuteCommand. If the worker VM has its own managed identity,\
    \ can-execute-as execute-as-via-command then fires: CanExecuteCommand(principal, worker-VM) + ExecutesAs(worker-VM,\
    \ MI) => CanExecuteAs."
  narrative: '{principal.name} can submit a runbook job to Hybrid Runbook Worker Group {workerGroup.name}
    (automationAccounts/jobs/write with runOn={workerGroup.name}); the runbook executes arbitrary PowerShell/Python
    as LOCAL SYSTEM on worker VM {target.name}, yielding RCE on the host and any identity the VM runs
    as.'
move · open · esc close