1 Punkte von GN⁺ 2025-03-16 | 1 Kommentare | Auf WhatsApp teilen
  • 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 und DigestValue werden 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-saml auf 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_signature in xml_security.rb
  • Diese Methode liest das erste Signature-Element und den eigentlichen SignatureValue mit REXML
    • REXML::XPath.first(@working_copy, "//ds:Signature", {"ds"=>DSIG})
  • Im selben Prüfablauf werden Signature und SignedInfo dagegen erneut mit Nokogiri abgefragt und kanonisiert
    • document.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 DigestValue aus 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
    • SignedInfo wird mit Nokogiri extrahiert und kanonisiert
    • SignatureValue wird 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 Subject und NameID innerhalb der Assertion
  • Ü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 Signature wird kanonisiert und gehasht, dann mit DigestValue verglichen
    • SignedInfo wird kanonisiert und die Signatur mit SignatureValue geprüft
  • 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
  • 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 Elements StatusDetail
  • Der Prüfablauf wird dadurch wie folgt getrennt
    • Das SignedInfo der 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 DigestValue verglichen
  • Am Ende passen ein gültiges SignedInfo und 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::NONET und löst einen Fehler aus, wenn doc.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

 
GN⁺ 2025-03-16
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.

    • Der Ansatz, „persönliche Accounts in ein Enterprise mitzunehmen“, schafft auch Probleme jenseits der Autorisierung.
      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.
    • Aus Sicht der Anbieter kann ich es bis zu einem gewissen Grad verstehen, denn GitHub macht es hier extrem schwer, es korrekt zu implementieren.
      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.
    • Diese Betriebsweise wiederholt sich auf allen Ebenen.
      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.
    • Die Annahme, dass gemeinsame Zugangsdaten Komfort bringen und SSO die Sicherheit verbessern kann, bricht durch eine solche Schwachstelle zusammen.
      Jede Form von Passwortspeicher, sogar ein physischer Speicher oder selbst Passwortwiederverwendung, kann am Ende sicherer sein.
      Letztlich hat Minimalismus wieder einmal gewonnen.
    • Für alle, die das mit der aktuellen Schwachstellenforschung in Verbindung bringen wollen: Das scheint nicht zusammenzuhängen.
      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.

    • Es ist noch viel schlimmer, als du sagst.
      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.
    • Ich weiß nicht, ob SSO überhaupt zu retten ist.
      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.

    • Irgendwann werde ich all die unglaublich dummen Dinge aufschreiben, die XML DSig tut.
      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.
    • Es dürfte interessant werden, wie Security Cryptography Whatever das SAML-Chaos dieser Woche behandelt.
    • Wenn ich es richtig verstanden habe, bleibt SAML noch als Unterscheidungsmerkmal, dass der SSO-Anbieter Sessions widerrufen kann.
      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.

    • Ist das nicht ein Lehrbuchbeispiel?
      Dinge, die keine regulären Sprachen sind, nicht mit regulären Ausdrücken zu parsen.
    • Eine der Gefahren von KI-Code-Assistenten ist, dass sie nicht unbedingt den breiteren Kontext der Bibliotheken sehen, die in großen Codebasen verwendet werden.
      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.

    • Reaktionen auf Schwachstellen wirken meist zu lax.
      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?
    • Etwas zugespitzt: Die Schlussfolgerung ist, dass man mit einem großen Knüppel dafür sorgen sollte, dass Webentwickler nicht in die Nähe sicherheitskritischen Codes kommen.
      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.

    • Im Blogbeitrag aus dem Schwesterkommentar <https://news.ycombinator.com/item?id=43374972> standen die entsprechenden Details.
      Bei (...//ds:DigestValue).firstChild.nodeValue wurde nicht geprüft, ob .firstChild ein 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.
    • Vermutlich wollte man nicht die Verantwortung dafür übernehmen, einen Zero-Day, der in zahllosen Systemen weltweit eine Rechteumgehung ermöglicht, direkt öffentlich zu machen, bevor die Betreiber dieser Systeme eine Chance zur Behebung hatten.
      Die konkreten Details werden sicher bald folgen.