
Abusing and Detecting Alternative Data Channel Command Execution on Azure Virtual Machines
Hausec details a covert command execution technique on Azure VMs abusing the userData property of the Instance Metadata Service (IMDS): an attacker with VM write privileges uses Invoke-AzVMRunCommand once to deploy a PowerShell "agent" that polls IMDS for base64-encoded commands, executes them, and exfiltrates results back via the Azure REST API using a smuggled access token — enabling repeat command execution without further RunCommand calls. The technique is implemented in PowerZure via Invoke-AzureVMUserDataCommand and Invoke-AzureVMUserDataAgent, and the post includes detection guidance covering artifact locations, Activity log alerts on Invoke-AzVMRunCommand, and PowerShell logging.
What it is
A covert command-execution technique for Azure VMs that avoids repeated Invoke-AzVMRunCommand calls by abusing the userData property of the Instance Metadata Service (IMDS). Implemented in PowerZure as Invoke-AzureVMUserDataCommand and Invoke-AzureVMUserDataAgent. The value below the summary is the concrete detection surface: exact artifact paths, the persistence mechanism, and the token-smuggling design constraint.
How it works
The asymmetry that makes this work: IMDS (http://169.254.169.254/metadata/instance) accepts only GET from the local VM, so the VM can read userData but cannot write metadata back through IMDS. Writes require the Azure REST API (https://management.azure.com/subscriptions/...), which supports PATCH/PUT. The technique bridges this by smuggling an Azure REST access token into the uploaded userData alongside the command — the agent then uses that token to authenticate its result upload.
The VM reads userData locally with:
$userData = Invoke-RestMethod -Headers @{"Metadata"="true"} -Method GET -NoProxy -Uri "http://169.254.169.254/metadata/instance/compute/userData?api-version=2021-01-01&format=text"
[System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($userData))Persistence is a Scheduled Task triggered on an Azure-specific Event ID that fires several times per minute, giving near-continuous polling without a long-running process.
Preconditions
All three must hold, or the technique fails:
- The account uploading data has VM write privileges (
Microsoft.Compute/virtualMachines/write— included in VM Contributor, Contributor, etc.). Invoke-AzVMRunCommandcan be executed by users without approval.- The VM is powered on.
What to do
Detection artifacts the summary only gestures at, given here in full:
- PowerZure agent script:
C:\WindowsAzure\SecAgent\AzureInstanceMetadataService.ps1 - RunCommand payload residue:
C:\Packages\Plugins\Microsoft.CPlat.Core.RunCommandWindows\1.1.9\Downloads - Activity log:
Invoke-AzVMRunCommandalways logs — alert on and review it. - PowerShell logging captures all agent activity since commands execute in-script.
- Manual check: inspect the
userDatafield in the portal. The author reports never having seen it legitimately populated; treat any content as suspect and verify its purpose.
Caveats
The * in "without RunCommand" is real — Invoke-AzVMRunCommand is still required once to plant the agent, so that initial call is your most reliable detection anchor. Paths and event-driven scheduling are PowerZure-implementation specifics; a bespoke agent could relocate or rename them.
Organisations named here
- Invoke-AzureVMUserDataAgent
- Invoke-AzureVMUserDataCommand
Technologies named here
- Azure Virtual Machines
- PowerZure
- Invoke-AzVMRunCommand
- Azure Instance Metadata Service
- Azure REST API
- Azure
- PowerShell
Related in Offensive Security