- Die in ruby-saml 1.17.0 und älter gefundenen CVE-2025-25291 und CVE-2025-25292 ermöglichen mit nur einer gültigen Signatur die Anmeldung als beliebiger Benutzer und erhöhen damit das Risiko einer Kontoübernahme in SAML-SSO-Umgebungen
- Die Schwachstellen entstehen durch Parser-Unterschiede im Signaturprüfpfad, bei denen REXML und Nokogiri unterschiedliche
Signature-Elemente desselben XML-Dokuments interpretieren können SignedInfo,SignatureValue, der Assertion-Hash undDigestValuewerden aus unterschiedlichen Parser-Ergebnissen kombiniert, sodass jede Prüfung einzeln besteht, aber die Verknüpfung zwischen Hash und Signatur getrennt werden kann- GitHub führte während der Prüfung einer erneuten Einführung von ruby-saml ein Bug-Bounty und ein Review durch das Security Lab durch, fand bei GitLab eine ausnutzbare Instanz und informierte das Security-Team; derzeit nutzt GitHub ruby-saml nicht für die Authentifizierung
- Nutzer sollten auf ruby-saml 1.18.0 aktualisieren; auch Bibliotheken, die wie
omniauth-samlauf ruby-saml verweisen, sollten auf Releases aktualisiert werden, die auf die korrigierte Version verweisen
Auswirkungen der Authentifizierungsumgehung in ruby-saml
- In ruby-saml 1.17.0 und älter wurden zwei schwerwiegende Authentifizierungsumgehungen bestätigt
- CVE-2025-25291
- CVE-2025-25292
- Wenn ein Angreifer über eine gültige Signatur verfügt, die mit dem Schlüssel erzeugt wurde, der zur Prüfung von SAML Responses oder Assertions der Zielorganisation verwendet wird, kann er selbst eine SAML Assertion erstellen und sich als beliebiger Benutzer anmelden
- Mögliche Quellen für eine Signatur sind:
- eine signierte Assertion oder Response eines anderen Benutzers mit geringen Rechten
- in einigen Fällen signierte Metadaten eines öffentlich zugänglichen SAML-IdP
- Diese Schwachstelle kann letztlich für Angriffe zur Kontoübernahme genutzt werden
- GitHub verwendet ruby-saml derzeit nicht für die Authentifizierung, evaluierte ruby-saml jedoch im Rahmen der Prüfung, wieder eine Open-Source-Bibliothek für SAML-Authentifizierung einzusetzen
- ruby-saml wird auch in anderen beliebten Projekten und Produkten eingesetzt; GitHub fand bei GitLab eine ausnutzbare Instanz und benachrichtigte das GitLab-Security-Team
Warum GitHub ruby-saml erneut geprüft hat
- GitHub nutzte ruby-saml bis 2014, wechselte damals aber wegen fehlender benötigter Funktionen zu einer eigenen SAML-Implementierung
- Später gab es auch für die eigene Implementierung Bug-Bounty-Berichte, etwa zu CVE-2024-9487, einer Schwachstelle im Zusammenhang mit verschlüsselten Assertions; daraufhin begann GitHub, eine Wiedereinführung von ruby-saml zu prüfen
- Im Oktober 2024 wurde die von ahacker1 entdeckte Authentifizierungsumgehung in ruby-saml CVE-2024-45409 veröffentlicht
- Um die Möglichkeit eines Wechsels zu ruby-saml genauer zu bewerten, startete GitHub ein privates Bug-Bounty
- Ausgewählte Forschende erhielten Zugang zu einer GitHub-Testumgebung, in der die SAML-Authentifizierung mit ruby-saml durchgeführt wurde
- Auch das GitHub Security Lab prüfte die Angriffsfläche von ruby-saml
Prüfungsinkonsistenz durch zwei XML-Parser
- Bei der Code-Review stellten ahacker1 und das GitHub Security Lab fest, dass im Signaturprüfpfad von ruby-saml zwei XML-Parser gemeinsam verwendet werden
- REXML: ein rein in Ruby implementierter XML-Parser
- Nokogiri: unterstützt XML- und HTML-Parsing und bietet APIs, die libxml2, libgumbo und Xerces für JRuby kapseln
- Der betroffene Pfad ist die Methode
validate_signatureinxml_security.rb - Diese Methode liest das erste
Signature-Element und den eigentlichenSignatureValuemit REXMLREXML::XPath.first(@working_copy, "//ds:Signature", {"ds"=>DSIG})
- Im selben Prüfablauf werden
SignatureundSignedInfodagegen erneut mit Nokogiri abgefragt und kanonisiertdocument.at_xpath('//ds:Signature', 'ds' => DSIG)noko_signed_info_element.canonicalize(canon_algorithm)
- Die Assertion wird mit Nokogiri extrahiert, kanonisiert und gehasht, während der als Vergleichswert verwendete
DigestValueaus REXML stammt - Das endgültige Prüfmaterial wird dadurch wie folgt aufgespalten
- Die Assertion wird mit Nokogiri extrahiert, kanonisiert und anschließend gehasht
- Der Vergleichs-Hash stammt aus dem von REXML gelesenen
DigestValue SignedInfowird mit Nokogiri extrahiert und kanonisiertSignatureValuewird mit REXML extrahiert
Unterbrochene Sicherheitsverbindung bei der SAML-Signaturprüfung
- Eine SAML Response übermittelt Login-Benutzerinformationen vom IdP an den SP im XML-Format
- Bei Verwendung des HTTP POST Binding läuft die SAML Response über den Browser des Benutzers zum SP; daher ist eine Signaturprüfung erforderlich, damit der Benutzer die Nachricht nicht manipulieren kann
- In einer vereinfachten SAML Response befinden sich die wichtigen Informationen meist in
SubjectundNameIDinnerhalb derAssertion - Üblicherweise kann entweder die Assertion oder die gesamte SAML Response signiert sein
- Ist die Assertion signiert, läuft die Prüfung in zwei Schritten ab
- Die Assertion ohne
Signaturewird kanonisiert und gehasht, dann mitDigestValueverglichen SignedInfowird kanonisiert und die Signatur mitSignatureValuegeprüft
- Die Assertion ohne
- Bei dieser Schwachstelle garantieren die beiden Schritte selbst dann nicht dieselben Daten, wenn beide jeweils erfolgreich sind
- Der Hash kann der Hash der tatsächlichen Assertion sein
- Die Signatur kann eine Signatur für ein anderes
SignedInfo-Element sein
- Die erforderliche Sicherheitseigenschaft besteht darin, dass gehashter Inhalt, Hash und Signatur direkt miteinander verknüpft sind; nach der Prüfung dürfen Informationen nur aus dem tatsächlich geprüften Teil gelesen werden
Aufbau des tatsächlichen Exploits
- Die zentrale Bedingung war, REXML und Nokogiri dazu zu bringen, im selben XML-Dokument unterschiedliche
Signature-Elemente zu sehen; das war tatsächlich möglich - ahacker1 erstellte im Rahmen des Bug-Bountys zuerst einen funktionierenden Exploit, der Parser-Unterschiede nutzte
- Inspiriert wurde er von den 2021 von Juho Forsén von Mattermost veröffentlichten XML roundtrips vulnerabilities
- Das GitHub Security Lab nutzte den Ruby-Fuzzer ruzzy von Trail of Bits, um einen weiteren Exploit auf Basis von Parser-Unterschieden zu erstellen
- Der Beispiel-Exploit platziert ein zusätzliches
Signature-Element, das nur Nokogiri sieht, innerhalb des ElementsStatusDetail - Der Prüfablauf wird dadurch wie folgt getrennt
- Das
SignedInfoder Signatur, die Nokogiri sieht, wird kanonisiert - Die Prüfung erfolgt mit dem
SignatureValue, der aus der von REXML gesehenen Signatur extrahiert wurde - Die von Nokogiri per ID gefundene Assertion wird kanonisiert und gehasht
- Der Hash wird mit dem von REXML gelesenen
DigestValueverglichen
- Das
- Am Ende passen ein gültiges
SignedInfound eine gültige Signatur zusammen, und ebenso die manipulierte Assertion und ihr berechneter Digest, sodass ruby-saml die Assertion akzeptiert
Abhilfen und Grenzen der Erkennung
- Wenn beim Parsen der SAML Response mit Nokogiri Parsing-Fehler geprüft werden, lassen sich einige der derzeit bekannten nicht öffentlichen Exploits blockieren
- Nokogiri-Parsing-Fehler treten nicht als Exceptions auf; daher muss das
errors-Member des geparsten Dokuments direkt geprüft werden - Der Beispielcode verwendet die Optionen
Nokogiri::XML::ParseOptions::STRICT | Nokogiri::XML::ParseOptions::NONETund löst einen Fehler aus, wenndoc.errors.any?gilt - Diese Methode ist keine vollständige Korrektur, macht aber mindestens einen Exploit nicht ausführbar
- Verlässliche Indicators of Compromise sind nicht bekannt
- Ein potenzieller Indikator funktioniert nur in einer debug-ähnlichen Umgebung
- Er wird nicht veröffentlicht, weil dafür zu viele Details zur Implementierung eines funktionierenden Exploits offengelegt werden müssten
- Die empfohlene Prüfmethode besteht darin, auf SP-Seite nach verdächtigen Logins zu suchen, etwa SAML-Anmeldungen von IP-Adressen, die nicht zum erwarteten Standort des Benutzers passen
Korrekturrichtung und zu aktualisierende Komponenten
- Die anfängliche Korrektur entfernte wegen API-Kompatibilitätsproblemen keinen der XML-Parser
- Das grundlegendere Problem war die Trennung von Hash-Prüfung und Signaturprüfung, die durch Parser-Unterschiede ausnutzbar wurde
- Die Entfernung eines der XML-Parser war aus anderen Gründen bereits geplant und könnte zusammen mit weiteren Verbesserungen in einem Major Release erfolgen
- Nutzer von ruby-saml sollten auf die korrigierte Version 1.18.0 aktualisieren
- Auch Bibliotheken, die ruby-saml verwenden, sollten geprüft werden
- Beispiel: omniauth-saml
- Diese Bibliothek muss auf eine Version aktualisiert werden, die auf die korrigierte ruby-saml-Version verweist
- Das GitHub Security Lab plant, künftig im GitHub Security Lab repository Proof-of-Concept-Exploits zu veröffentlichen
Zeitplan für Veröffentlichung und Reaktion
- 2024-11-04: Ein Bug-Bounty-Bericht ging ein, der eine Authentifizierungsumgehung in einer GitHub-Testumgebung nachwies, in der SAML-Authentifizierung mit ruby-saml evaluiert wurde
- 2024-11-04: Die Identifizierung und das Testen potenzieller Abhilfen begannen
- 2024-11-12: Eine zweite Authentifizierungsumgehung wurde entdeckt, die den ersten Abhilfeplan aushebelte
- 2024-11-13: Erster Kontakt mit dem ruby-saml-Maintainer Sixto Martín
- 2024-11-14: Die Unterschiede zwischen den beiden Parsern wurden an ruby-saml gemeldet, und der Maintainer reagierte sofort
- 2024-11-14: Der Maintainer und ahacker1 begannen mit der Arbeit an einem potenziellen Patch
- Eine der ersten Ideen war, einen der XML-Parser zu entfernen, was jedoch ohne Bruch der Abwärtskompatibilität nicht möglich war
- 2025-02-04: ahacker1 schlug eine nicht abwärtskompatible Korrektur vor
- 2025-02-06: ahacker1 schlug auch eine abwärtskompatible Korrektur vor
- 2025-02-12: Die 90-Tage-Frist des GitHub Security Lab Advisory endete
- 2025-02-16: Der Maintainer begann mit einer Korrekturrichtung, die die Abwärtskompatibilität wahrt und leicht verständlich ist
- 2025-02-17: Erster Kontakt mit GitLab, um das ruby-saml-Release mit Releases von GitLabs On-Premises-Produkten abzustimmen
- 2025-03-12: Die korrigierte ruby-saml-Version wurde veröffentlicht
1 Kommentare
Meinungen auf Hacker News
Ich halte GitHubs SAML-Implementierung für nutzlos.
Die ursprüngliche Idee ist, persönliche Accounts in ein Enterprise mitzunehmen und dort zu nutzen. Innerhalb der GitHub-Website funktioniert das bis zu einem gewissen Grad, aber sobald eine App, bei der man sich mit GitHub anmeldet, auf Organisationsebene genehmigt wurde, verhindert nichts, dass sie die Organisationsmitgliedschaft ausliest.
Eine SAML-Session ist nur nötig, wenn die App mit dem Token, das sie von diesem Nutzer erhalten hat, Daten abruft. In der Praxis nutzten SAST-Tools aber fast immer App-Instance-Tokens und zeigten Code an, sobald es nur einen GitHub-Account innerhalb der Organisation gab.
Tailscale hat es nach dem Hinweis behoben, Sonarcloud bat darum, es niemandem zu erzählen, und GitHub antwortete nach einigen Wochen, das sei „vollständig erwartetes Verhalten“. Keiner der informierten Anbieter verstand es jedoch so, und auch die Dokumentation widersprach GitHubs Antwort.
Sicherheitslücken zu melden lohnt sich selbst dann kaum, wenn man zufällig darauf stößt; schwer vorstellbar, das beruflich zu machen.
GitHub hat in seltenen Fällen beim Mergen von Arbeits-PRs die private E-Mail-Adresse als Standard verwendet. Wenn mich jemand fragt, würde ich daher raten, private und berufliche Nutzung weder bei GitHub noch anderswo im selben Account zu vermischen.
Beim Bau von https://dev.log.xyz, einem Tool zur Analyse von Repositories/Commits/PRs, war es sehr aufwendig sicherzustellen, dass „man in Devlog nur sehen kann, was man auch auf GitHub sehen kann“, und die gesamte Erfahrung war sehr frustrierend.
Auch GitHubs OAuth-Berechtigungsauswahl ist übermäßig verwirrend, sodass man beim „Login mit GitHub“ schwer sicher sein kann, welche Informationen welcher Organisation geteilt werden.
Schon junge Entwickler, die mit JavaScript vertraut sind, davon zu überzeugen, dass clientseitige Validierung allein nicht ausreicht, ist schwierig; bei Geschäftsverantwortlichen, die Funktionsanforderungen und Budgets festlegen, erst recht.
Jede Form von Passwortspeicher, sogar ein physischer Speicher oder selbst Passwortwiederverwendung, kann am Ende sicherer sein.
Letztlich hat Minimalismus wieder einmal gewonnen.
Dort steht: „GitHub doesn’t currently use ruby-saml for authentication, but began evaluating the use of the library with the intention of using an open source library for SAML authentication once more“.
Ich musste kürzlich eine SAML-Implementierung bauen, und dieser Titel überrascht mich überhaupt nicht.
Die SAML-Spezifikation selbst ist ziemlich vernünftig, aber die Grundlage, XML-Signaturen und darüber hinaus XML-Kanonisierung, ist – wenn man das überhaupt einen Standard nennen kann – wirklich wahnsinnig.
Eine derart verdrehte und verdorbene Spezifikation kann nur ein Gremium hervorbringen; ein einzelner Mensch hätte so widersprüchliche Gedanken wohl nicht im Kopf halten und zusammenfügen können.
Hätte man die Signatur einfach out-of-band übertragen, wäre SAML etwas geworden, das sich angenehm implementieren lässt.
XML steht buchstäblich für eXtensible Markup Language, aber das SAML-Standardisierungsgremium hat darauf noch einmal seine eigene Sprache für Erweiterungsmechanismen erfunden.
Für ein winziges Stück Daten, das sich kaum von Informationen in einem Authentifizierungs-Cookie unterscheidet, ein weiteres Protokoll auf ein Protokoll zu stapeln, ist eine besondere Art von Dummheit, die nur die größten und bürokratischsten Gremien hervorbringen können.
Die Idee, sich jeweils bei unterschiedlichen Accounts anzumelden, wirkt an sich in Ordnung.
Eine Struktur, die Accounts miteinander verbindet, sodass sie auf einen Schlag in großem Maßstab kompromittiert werden können, ist grundsätzlich gefährlicher.
SAML, weiter gefasst XML-DSIG, halte ich unter den weit verbreiteten Sicherheitsprotokollen buchstäblich für das schlechteste.
Im Allgemeinen sollte man um nahezu jeden Preis zu OAuth wechseln, und zumindest würde ich mich weigern, ein neues Produkt auf den Markt zu bringen, das darauf angewiesen ist.
Es ist sehr gefährlich, und solange es keinen Durchbruch bei praktikabler Formatverifikation gibt, fällt es schwer, sich vorzustellen, dass dies die letzte oder schlimmste DSIG-Schwachstelle gewesen sein soll.
Dabei habe ich die Kryptografie noch nicht einmal angefasst, und trotzdem ist es schon der Gipfel von Enterprise-Software-Denken.
Jemand sollte tief in die Abgründe der Mailinglisten und Standardisierungsgremien rund um WS-* und OASIS/XACML eintauchen.
Stimmt das?
Uff, niemand sollte REXML verwenden, außer wenn es keine andere Option gibt.
Es parst bereitwillig auch fehlerhaftes XML und verursacht dadurch in späteren Schritten unendlich viele Probleme.
Es parst XML buchstäblich mit regulären Ausdrücken und ist ein hervorragendes Beispiel dafür, warum man das nicht tun sollte.
Projekte begannen nicht wegen der Performance mit Nokogiri, sondern wegen der Korrektheit.
Dinge, die keine regulären Sprachen sind, nicht mit regulären Ausdrücken zu parsen.
Ich habe kürzlich o3 getestet, und jedes Mal, wenn es versuchte, ein von der Bibliothek eines bestimmten Codeblocks unabhängiges Problem zu beheben, änderte es ständig die Bibliothek, die dieser Block verwendete.
Bei Sonnet habe ich dieses Verhalten nicht gesehen.
Es scheint leicht, dass sich auf diese Weise im Zuge einer Änderung Probleme einschleichen, indem auf eine schlechtere Bibliothek/ein schlechteres Gem umgestellt wird, das bereits in der Codebasis oder Standardbibliothek vorhanden ist, sodass die Tests bestehen und keine Gemfile-Änderung nötig ist.
SAML ist per Design unsicher
Es gibt schon seit Langem Artikel, die das besser erklären, zum Beispiel https://joonas.fi/2021/08/saml-is-insecure-by-design/
Ein Satz, der mir aus diesem alten Thread in Erinnerung geblieben ist, war: „Signiere Bytes, nicht Bedeutung.“
Unterschiede zwischen Parsern sind vorhersehbar und manchmal unvermeidlich.
Entscheidend ist, was man aus einer signierten Antwort gewinnen will.
Eines der Dilemmata moderner TLS-Nutzung ist, dass man manchmal einer internen CA vertrauen möchte; das ist der einfache Weg. Akzeptiert man aber das CA-Zertifikat eines Partners, und hat man mehrere Partner, kann man nicht mehr nur auf das Endzertifikat schauen — auch die Root der Chain wird für die Entscheidung genauso wichtig.
Deshalb würde ich, wenn möglich, auch vom AWS-Signaturalgorithmus abraten.
V4 ist theoretisch sicher, aber AWS hat es zweimal vermasselt; SigV1 und SigV3 waren per Design unsicher und haben es trotzdem irgendwie durch das Design-Review bis zur Veröffentlichung geschafft.
Hervorragender Artikel.
Wie auch im Text erwähnt, gebührt ahacker1 großer Applaus.
Er leistet sehr sorgfältige und wertvolle Arbeit, um SAML-Implementierungen sicherer zu machen, und auch SSOReady ist ihm für seine Arbeit wirklich dankbar.
Anfang dieser Woche hat auch WorkOS einen guten Beitrag über die Zusammenarbeit mit ahacker1 veröffentlicht: https://workos.com/blog/samlstorm
Es gibt die Stelle: „Wir haben in GitLab einen ausnutzbaren Fall dieser Schwachstelle gefunden und das Security-Team informiert.“ Für alle, die es interessiert: GitLab hat bereits einen Fix veröffentlicht.
https://about.gitlab.com/releases/2025/03/12/patch-release-g...
Als verwandter Artikel gibt es den Latacora-Beitrag von 2019, How (not) to sign a JSON object[1].
Kurz gesagt: verschachtelte Baumstrukturen zu signieren ist schwierig und voller Fallstricke.
Einfacher ist es, wenn der Umschlag die Nachricht als rohen String enthält und genau dieser rohe String signiert wird.
[1]: https://www.latacora.com/blog/2019/07/24/how-not-to/
Ist die einfachere Schlussfolgerung hier nicht, dass man die Signatur dort suchen sollte, wo sie sein muss?
Also nicht mit einem viel zu allgemeinen XPath wie „//ds:Signature“ irgendeine Signatur an einer unerwarteten Stelle finden.
Man sollte nicht nur die gefährliche Komponente chirurgisch entfernen, sondern auch ein bisschen das Kind mit dem Bade ausschütten, großzügig herausschneiden und es wie eine Chemotherapie behandeln.
Jeder IT-Administrator mit Selbstachtung sollte SAML aus seinen künftigen Planungen streichen.
Die ganze Idee von SSO ist ebenfalls fragwürdig, und XML-Parsing hat diese Woche gleich zweimal zugeschlagen, also sollte man es künftig meiden.
Was wäre an einer Policy falsch, XML durch JSON zu ersetzen?
Das gilt schon bei Design, Protokollen und Datenformaten.
Die Gewohnheiten und Designüberlegungen normaler Webentwicklung passen nicht zu dem, was Security-Code braucht, und stehen oft sogar im direkten Gegensatz zu dem, was man braucht, um korrekten Code zu schreiben.
Es ist etwas ärgerlich, dass der Blogbeitrag bei der Erklärung der Schwachstelle ausgerechnet den problematischen Parser-Unterschied auslässt.
Das ist, als würde man die Einleitung der Geschichte schreiben und den Höhepunkt weglassen.
Bei
(...//ds:DigestValue).firstChild.nodeValuewurde nicht geprüft, ob.firstChildein Node ist; im problematischen Fall war es ein Comment.Dadurch sah die nicht normalisierte Seite die „verdeckte“ Signatur, während die angepasste Seite, die Kommentare verworfen hatte, den Node sah — und wenn zwei Implementierungen bei einem signierten Dokument zu unterschiedlichen Einschätzungen kommen, wird es unschön.
Die konkreten Details werden sicher bald folgen.