1 points par GN⁺ 2025-03-16 | 1 commentaires | Partager sur WhatsApp
  • Les CVE-2025-25291 et CVE-2025-25292, découvertes dans ruby-saml 1.17.0 et versions antérieures, permettent de se connecter en tant qu’utilisateur arbitraire avec une seule signature valide, augmentant le risque de prise de contrôle de compte dans les environnements SAML SSO
  • La vulnérabilité provient d’une différence entre parseurs dans le chemin de vérification de signature, où REXML et Nokogiri peuvent interpréter des éléments Signature différents dans un même document XML
  • SignedInfo, SignatureValue, le hachage de l’assertion et DigestValue sont combinés à partir de résultats de parseurs différents : chaque contrôle réussit, mais le lien entre le hachage et la signature peut être rompu
  • En réévaluant l’adoption de ruby-saml, GitHub a mené un bug bounty et une revue par Security Lab, a trouvé chez GitLab une instance exploitable et en a informé son équipe sécurité ; aujourd’hui, l’authentification GitHub n’utilise pas ruby-saml
  • Les utilisateurs doivent mettre à jour vers ruby-saml 1.18.0 ; les bibliothèques qui dépendent de ruby-saml, comme omniauth-saml, doivent aussi être mises à niveau vers une version qui référence la version corrigée

Impact du contournement d’authentification dans ruby-saml

  • Deux vulnérabilités de contournement d’authentification à gravité élevée ont été confirmées dans ruby-saml 1.17.0 et versions antérieures
    • CVE-2025-25291
    • CVE-2025-25292
  • Un attaquant disposant d’une seule signature valide créée avec la clé utilisée pour vérifier la SAML response ou l’assertion de l’organisation cible peut fabriquer directement une assertion SAML et se connecter en tant qu’utilisateur arbitraire
  • Les sources possibles de signature sont les suivantes
    • Une assertion ou response signée d’un autre utilisateur disposant de faibles privilèges
    • Dans certains cas, les metadata signées d’un IdP SAML accessible publiquement
  • Cette vulnérabilité peut au final être exploitée pour une prise de contrôle de compte
  • GitHub n’utilise actuellement pas ruby-saml pour son authentification, mais a évalué ruby-saml alors qu’il envisageait de réutiliser une bibliothèque open source pour l’authentification SAML
  • ruby-saml est aussi utilisé dans d’autres projets et produits populaires ; GitHub a découvert chez GitLab une instance exploitable et en a informé l’équipe sécurité de GitLab

Pourquoi GitHub a réexaminé ruby-saml

  • GitHub a utilisé ruby-saml jusqu’en 2014, puis est passé à sa propre implémentation SAML faute de fonctionnalités nécessaires à l’époque
  • Par la suite, cette implémentation interne a aussi fait l’objet de rapports de bug bounty, notamment CVE-2024-9487, une vulnérabilité liée aux assertions chiffrées, et GitHub a commencé à envisager de réintroduire ruby-saml
  • En octobre 2024, une vulnérabilité de contournement d’authentification dans ruby-saml, CVE-2024-45409, découverte par ahacker1, a été rendue publique
  • GitHub a lancé un bug bounty privé afin d’évaluer plus finement la possibilité de migrer vers ruby-saml
    • Les chercheurs sélectionnés ont obtenu un accès à un environnement de test GitHub effectuant l’authentification SAML avec ruby-saml
    • GitHub Security Lab a également examiné la surface d’attaque de ruby-saml

Une incohérence de vérification créée par deux parseurs XML

  • Lors de la revue de code, ahacker1 et GitHub Security Lab ont confirmé que deux parseurs XML étaient utilisés ensemble dans le chemin de vérification de signature de ruby-saml
    • REXML : un parseur XML implémenté en Ruby pur
    • Nokogiri : prend en charge le parsing XML et HTML, et fournit une API encapsulant libxml2, libgumbo, Xerces pour JRuby, etc.
  • Le chemin concerné est la méthode validate_signature dans xml_security.rb
  • Cette méthode lit le premier élément Signature et le SignatureValue réel avec REXML
    • REXML::XPath.first(@working_copy, "//ds:Signature", {"ds"=>DSIG})
  • En revanche, dans le même flux de vérification, Signature et SignedInfo sont de nouveau recherchés puis canonisés avec Nokogiri
    • document.at_xpath('//ds:Signature', 'ds' => DSIG)
    • noko_signed_info_element.canonicalize(canon_algorithm)
  • L’assertion est extraite, canonisée et hachée avec Nokogiri, mais la valeur de comparaison, DigestValue, provient de REXML
  • Les matériaux de vérification finaux se séparent ainsi
    • L’assertion est extraite et canonisée avec Nokogiri, puis hachée
    • Le hachage de comparaison vient du DigestValue lu par REXML
    • SignedInfo est extrait et canonisé avec Nokogiri
    • SignatureValue est extrait avec REXML

Le lien de sécurité rompu dans la vérification de signature SAML

  • Une SAML response transmet les informations de l’utilisateur connecté de l’IdP au SP au format XML
  • Avec le HTTP POST binding, la SAML response passe par le navigateur de l’utilisateur avant d’arriver au SP ; une vérification de signature est donc nécessaire pour empêcher l’utilisateur de modifier le message
  • Dans une SAML response simplifiée, les informations importantes se trouvent généralement dans Subject et NameID à l’intérieur de Assertion
  • En général, l’assertion ou l’ensemble de la SAML response peut être signé
  • Lorsque l’assertion est signée, la vérification se déroule en deux étapes
    • Supprimer Signature de l’assertion, canoniser et hacher l’assertion, puis comparer le résultat à DigestValue
    • Canoniser SignedInfo et vérifier la signature avec SignatureValue
  • Dans cette vulnérabilité, même si les deux étapes réussissent, elles ne garantissent pas qu’elles portent sur les mêmes données
    • Le hachage peut être celui de l’assertion réelle
    • La signature peut être celle d’un autre élément SignedInfo
  • La propriété de sécurité nécessaire est que le contenu haché, le hachage et la signature soient directement liés ; après vérification, les informations ne doivent être lues que dans la partie effectivement vérifiée

Construction d’un exploit réel

  • La condition clé était de faire en sorte que REXML et Nokogiri voient des Signature différentes dans le même document XML, ce qui s’est avéré possible
  • Pendant le bug bounty, ahacker1 a d’abord créé un exploit fonctionnel utilisant une différence entre parseurs
  • GitHub Security Lab a créé un autre exploit fondé sur une différence entre parseurs à l’aide du fuzzer Ruby ruzzy de Trail of Bits
  • L’exemple d’exploit insère dans l’élément StatusDetail une Signature supplémentaire visible uniquement par Nokogiri
  • Le flux de vérification se sépare ainsi
    • Le SignedInfo de la signature vue par Nokogiri est canonisé
    • Il est vérifié avec le SignatureValue extrait de la signature vue par REXML
    • L’assertion trouvée par ID par Nokogiri est canonisée et hachée
    • Le hachage est comparé au DigestValue lu par REXML
  • Au final, un SignedInfo valide et une signature valide correspondent entre eux, tandis que l’assertion modifiée et son digest calculé correspondent également, ce qui conduit ruby-saml à accepter l’assertion

Mesures d’atténuation et limites de détection

  • Vérifier les erreurs de parsing lors du parsing d’une SAML response avec Nokogiri peut bloquer certains exploits privés actuellement connus
  • Les erreurs de parsing Nokogiri ne lèvent pas d’exception ; il faut donc vérifier directement le membre errors du document parsé
  • L’exemple de code utilise les options Nokogiri::XML::ParseOptions::STRICT | Nokogiri::XML::ParseOptions::NONET et déclenche une erreur lorsque doc.errors.any?
  • Cette approche n’est pas une correction complète, mais elle rend au moins un exploit inexécutable
  • Aucun indicateur de compromission fiable n’est connu
    • Un indicateur potentiel ne fonctionne que dans un environnement de type debug
    • Le publier révélerait trop de détails d’implémentation d’un exploit fonctionnel, il n’est donc pas rendu public
  • La méthode de vérification recommandée consiste à rechercher côté SP des connexions SAML suspectes, par exemple depuis des adresses IP ne correspondant pas à l’emplacement attendu de l’utilisateur

Orientation du correctif et éléments à mettre à jour

  • Le correctif initial ne supprime pas l’un des parseurs XML en raison de problèmes de compatibilité d’API
  • Le problème plus fondamental était la séparation entre vérification du hachage et vérification de la signature, séparation devenue exploitable via des différences entre parseurs
  • La suppression d’un parseur XML était déjà prévue pour d’autres raisons, et pourrait intervenir dans une version majeure avec d’autres améliorations
  • Les utilisateurs de ruby-saml doivent mettre à jour vers la version corrigée 1.18.0
  • Les bibliothèques utilisant ruby-saml doivent également être vérifiées
    • Exemple : omniauth-saml
    • Ces bibliothèques doivent être mises à jour vers une version référençant la version corrigée de ruby-saml
  • GitHub Security Lab prévoit de publier ultérieurement un exploit de preuve de concept dans le GitHub Security Lab repository

Calendrier de divulgation et de réponse

  • 2024-11-04 : réception d’un rapport de bug bounty démontrant un contournement d’authentification dans l’environnement de test GitHub qui évaluait l’authentification SAML avec ruby-saml
  • 2024-11-04 : début de l’identification et des tests de mesures d’atténuation potentielles
  • 2024-11-12 : découverte d’un second contournement d’authentification neutralisant le premier plan d’atténuation
  • 2024-11-13 : premier contact avec Sixto Martín, mainteneur de ruby-saml
  • 2024-11-14 : signalement à ruby-saml des différences entre les deux parseurs, avec réponse immédiate du mainteneur
  • 2024-11-14 : le mainteneur et ahacker1 commencent à travailler sur un correctif potentiel
    • L’une des idées initiales consistait à supprimer l’un des parseurs XML, mais cela n’était pas possible sans casser la compatibilité descendante
  • 2025-02-04 : ahacker1 propose un correctif non rétrocompatible
  • 2025-02-06 : ahacker1 propose également un correctif rétrocompatible
  • 2025-02-12 : fin du délai de 90 jours de l’advisory GitHub Security Lab
  • 2025-02-16 : le mainteneur commence à travailler sur une approche de correction préservant la rétrocompatibilité et facile à comprendre
  • 2025-02-17 : premier contact avec GitLab afin de coordonner la publication de ruby-saml et celle des produits GitLab on-premise
  • 2025-03-12 : publication de la version corrigée de ruby-saml

1 commentaires

 
GN⁺ 2025-03-16
Avis sur Hacker News
  • Je considère que l’implémentation SAML de GitHub ne sert à rien
    L’intention initiale était de permettre d’utiliser des comptes personnels au sein d’une entreprise ; cela fonctionne dans une certaine mesure sur le site de GitHub, mais une fois qu’une application connectée via GitHub a été approuvée au niveau de l’organisation, rien n’empêche l’accès à la liste des membres de l’organisation
    Une session SAML n’est nécessaire que lorsque l’application récupère des données avec le jeton qu’elle a reçu de cet utilisateur ; en pratique, les outils SAST utilisent presque toujours des jetons d’instance d’application et affichaient le code dès lors qu’il existait simplement un compte GitHub dans l’organisation
    Tailscale a corrigé le problème après en avoir été informé, SonarCloud a demandé de n’en parler à personne, et GitHub a répondu quelques semaines plus tard qu’il s’agissait d’un « comportement entièrement attendu » ; pourtant aucun des fournisseurs informés ne l’avait compris ainsi, et la documentation contredisait la réponse de GitHub
    Signaler des bugs de sécurité, même découverts par hasard, n’est pas gratifiant, et il est difficile d’imaginer en faire son métier

    • Le modèle qui consiste à « apporter des comptes personnels dans l’entreprise » crée aussi des problèmes au-delà de l’autorisation
      GitHub a très occasionnellement utilisé par défaut l’adresse e-mail personnelle lors de la fusion de PR professionnels ; donc si l’on me demande, je conseillerais de ne pas mélanger personnel et professionnel dans le même compte, que ce soit sur GitHub ou ailleurs
    • On peut aussi comprendre dans une certaine mesure la position des fournisseurs, car GitHub rend extrêmement difficile une implémentation correcte ici
      En créant https://dev.log.xyz, un outil d’analyse de dépôts/commits/PR, il a fallu beaucoup d’efforts pour garantir que « ce qui est visible sur GitHub est aussi visible dans Devlog », et toute l’expérience a été très frustrante
      Le sélecteur d’autorisations OAuth de GitHub est lui aussi excessivement confus, si bien qu’il est difficile de savoir quelles informations de quelles organisations on partage en utilisant « Se connecter avec GitHub »
    • Ce mode de fonctionnement se répète à tous les niveaux
      Il est déjà difficile de convaincre de jeunes développeurs familiers de JavaScript que la validation côté client ne suffit pas ; c’est encore plus difficile avec les décideurs qui fixent les exigences fonctionnelles et les budgets
    • L’hypothèse selon laquelle des identifiants partagés apportent du confort et que le SSO peut améliorer la sécurité s’effondre avec une seule vulnérabilité de ce type
      N’importe quelle forme de coffre-fort à mots de passe, même un stockage physique ou la réutilisation de mots de passe, peut au final s’avérer plus sûre
      En fin de compte, le minimalisme l’emporte encore
    • Pour ceux qui voudraient relier ce qui précède à cette recherche de vulnérabilité, cela ne semble pas lié
      Il est écrit : “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”
  • J’ai récemment dû implémenter SAML, et ce titre ne me surprend absolument pas
    La spécification SAML elle-même est assez raisonnable, mais sa base, les signatures XML, et plus encore la canonicalisation XML, est d’un niveau de folie difficile à qualifier de standard
    Seul un comité pouvait produire une spécification aussi tordue et dévoyée ; j’ai l’impression qu’un esprit individuel n’aurait pas pu contenir et combiner des idées aussi contradictoires
    Rien que le fait de transmettre la signature hors bande aurait rendu SAML agréable à implémenter

    • C’est bien pire que ce que tu dis
      XML signifie littéralement eXtensible Markup Language, et le comité de normalisation SAML a encore inventé par-dessus son propre langage de mécanisme d’extension
      Empiler un protocole sur un autre protocole pour une quantité minuscule de données, guère différente de ce qu’on mettrait dans un cookie d’authentification, relève d’un type très particulier de stupidité que seuls les comités les plus gros et bureaucratiques peuvent produire
    • Je ne sais même pas si le SSO est récupérable à la base
      L’idée de se connecter séparément à des comptes différents semble correcte
      Une architecture qui relie les comptes entre eux pour permettre de les compromettre massivement d’un seul coup est fondamentalement plus dangereuse
  • SAML, et plus largement XML-DSIG, est selon moi littéralement le pire des protocoles de sécurité largement utilisés
    En général, il faut migrer vers OAuth à presque n’importe quel prix, et je refuserais au minimum de lancer un nouveau produit qui en dépende
    C’est très dangereux, et à moins qu’une percée n’apparaisse dans la validation pratique des formats, il est difficile d’imaginer que ce soit la dernière vulnérabilité DSIG, ou même la pire

    • Un jour, j’écrirai tout ce que fait XML DSig d’incroyablement stupide
      Même sans toucher à la cryptographie, c’est déjà le sommet de la pensée façon logiciel d’entreprise
      Quelqu’un devrait vraiment fouiller les listes de diffusion et les organismes de normalisation derrière des choses comme WS-* et OASIS/XACML
    • Ce sera amusant de voir comment Security Cryptography Whatever traitera le bazar SAML de cette semaine
    • Si j’ai bien compris, SAML conserve encore un élément différenciant : le fournisseur SSO peut annuler une session
      C’est bien ça ?
  • Beurk, personne ne devrait utiliser REXML sauf s’il n’y a vraiment pas d’autre option
    Il accepte volontiers de parser du XML invalide, ce qui provoque ensuite une infinité de problèmes dans les étapes suivantes
    Il parse littéralement du XML avec des expressions régulières, et constitue un excellent exemple de pourquoi il ne faut pas le faire
    Les projets n’ont pas commencé à utiliser Nokogiri pour des raisons de performance, mais pour des raisons de correction

    • N’est-ce pas un exemple de manuel ?
      Ne pas parser avec des expressions régulières quelque chose qui n’est pas un langage régulier
    • L’un des risques des assistants de code IA est qu’ils ne voient pas forcément le contexte plus large des bibliothèques utilisées dans de grosses bases de code
      J’ai récemment testé o3, et chaque fois qu’il tentait de corriger un problème sans rapport avec la bibliothèque d’un bloc de code précis, il changeait sans cesse la bibliothèque utilisée par ce bloc
      Je n’ai pas observé ce phénomène avec Sonnet
      On voit facilement comment, au fil des corrections, un problème peut s’introduire en remplaçant par une bibliothèque/gem inférieure déjà présente dans la base de code ou la bibliothèque standard, de sorte que les tests passent et qu’aucune modification du Gemfile ne soit nécessaire
  • SAML n’est pas sûr par conception
    Il existe depuis longtemps des articles qui l’expliquent mieux, par exemple https://joonas.fi/2021/08/saml-is-insecure-by-design/
    La formule qui m’est restée en tête dans cet ancien fil était : « signez les octets, pas le sens »
    Les différences entre parseurs sont prévisibles et parfois inévitables
    Ce que l’on cherche à obtenir d’une réponse signée est crucial
    L’un des dilemmes de TLS moderne est que l’on veut parfois faire confiance à une CA interne, ce qui est la voie facile, mais si l’on accepte le certificat de CA d’un partenaire et qu’il y a plusieurs partenaires, on ne peut plus se contenter de regarder le certificat final : la racine de la chaîne devient tout aussi importante dans la prise de décision
    C’est pourquoi il est recommandé d’éviter aussi, si possible, l’algorithme de signature AWS
    La V4 est théoriquement sûre, mais AWS s’est déjà trompé deux fois, et SigV1 comme SigV3 étaient non sûrs par conception tout en ayant, d’une manière ou d’une autre, passé la revue de conception et été publiés

  • Excellent article
    Comme l’article le mentionne aussi, il faut applaudir très fort ahacker1
    Il mène un travail très sophistiqué et précieux pour rendre les implémentations SAML sûres, et SSOReady lui est vraiment reconnaissant pour son travail
    Plus tôt cette semaine, WorkOS a également publié un bon article sur sa collaboration avec ahacker1 : https://workos.com/blog/samlstorm

  • Il y a un passage disant : « nous avons trouvé dans GitLab un cas où cette vulnérabilité était exploitable et l’avons signalé à l’équipe sécurité » ; pour ceux que ça intéresse, GitLab a déjà publié un correctif
    https://about.gitlab.com/releases/2025/03/12/patch-release-g...

  • Un article connexe est celui de Latacora, publié en 2019, How (not) to sign a JSON object[1]
    En résumé, signer des structures arborescentes imbriquées est difficile et plein de pièges
    Il est plus simple que l’enveloppe contienne le message sous forme de chaîne brute, puis de signer cette chaîne brute
    [1]: https://www.latacora.com/blog/2019/07/24/how-not-to/

  • La conclusion la plus simple ici n’est-elle pas qu’il faut chercher la signature à l’endroit où elle est censée se trouver ?
    Ne pas utiliser un XPath trop générique comme « //ds:Signature », qui permettrait de trouver n’importe quelle signature à un emplacement inattendu

    • Les réponses à ce genre de vulnérabilités me semblent généralement trop timides
      Il ne faut pas seulement retirer chirurgicalement le composant dangereux ; il faut aussi jeter un peu le bébé avec l’eau du bain, couper largement et traiter ça comme une chimiothérapie
      Tout administrateur IT qui se respecte devrait exclure SAML de ses plans futurs
      L’idée même du SSO est suspecte, et comme le parsing XML s’est fait frapper deux fois cette semaine, il faudrait l’éviter à l’avenir
      Qu’est-ce qui ne va pas avec une politique consistant à remplacer XML par JSON ?
    • Pour le dire de façon un peu radicale, la conclusion est qu’il faut prendre un gros gourdin et empêcher les développeurs web de s’approcher du code sensible à la sécurité
      Cela vaut dès la conception, les protocoles et les formats de données
      Les habitudes et considérations de conception du développement web général ne correspondent pas à ce dont le code de sécurité a besoin, et sont souvent même à l’opposé de ce qu’il faut pour écrire du code correct
  • C’est un peu agaçant que l’article de blog explique la vulnérabilité tout en omettant justement la différence entre parseurs qui posait problème
    C’est comme écrire l’introduction d’une histoire et en supprimer le point culminant

    • L’article de blog mentionné dans le commentaire frère <https://news.ycombinator.com/item?id=43374972> contenait des détails pertinents
      En faisant (...//ds:DigestValue).firstChild.nodeValue, le code ne vérifiait pas que .firstChild était un Node ; dans le cas problématique, c’était un Comment
      Ainsi, le côté non normalisé voyait une signature « masquée », tandis que le côté corrigé qui supprimait les commentaires voyait un Node ; quand deux implémentations jugent différemment un document signé, des choses qui ne font pas rire peuvent arriver
    • Il semble qu’ils ne voulaient pas porter la responsabilité de divulguer directement un zero-day permettant de contourner les autorisations dans d’innombrables systèmes à travers le monde, avant que les responsables de ces systèmes aient eu l’occasion de corriger
      Les détails concrets sortiront sans doute bientôt