Correction de la vulnérabilité XSS de `marked`
15 mai 2016
0 minutes de lectureIl y a quelques semaines, nous avons ajouté à notre base de données une vulnérabilité de cross-site scripting (XSS) dans le package populaire marked. Cet article explique la vulnérabilité, montre comment l’exploiter dans une application de démonstration et explique comment corriger le problème dans votre application.
marked analyse le Markdown et le convertit en HTML, ce qui permet de transformer facilement des entrées utilisateur affichées — commentaires, avis sur des produits, demandes d’assistance — en texte enrichi (plus ou moins), avec des liens, du gras, de l’italique et bien plus. Comme Markdown ne prend pas en charge JavaScript, on le considère souvent comme immunisé contre le cross-site scripting et donc sûr pour afficher des entrées utilisateur.
En réalité, Markdown réduit le risque de XSS, mais ne l’élimine pas complètement. Cette vulnérabilité XSS de marked, facile à exploiter, illustre bien cette différence et donne à réfléchir.
Comme le montre notre rapport State of Open Source Security 2019, les vulnérabilités XSS sont toujours plus nombreuses. La plupart des vulnérabilités divulguées ont été signalées dans l’écosystème PHP Packagist, suivi de npm et de Maven Central.
La vulnérabilité
Bien que Markdown ne prenne pas en charge les scripts, marked (comme d’autres outils Markdown) prend en charge le HTML intégré. Celui-ci peut contenir des balises, que des attaquants peuvent utiliser pour injecter des scripts malveillants. Comme marked sert souvent à afficher des entrées utilisateur sur une page, ses auteurs ont ajouté une option de sécurité pour contrer ce risque. Le package propose l’option sanitize, qui détecte le HTML et les entrées dangereuses, puis les encode ou les supprime.
Bien que sanitize soit (malheureusement) désactivée par défaut, vous pouvez l’activer dans votre application. Voici un exemple de l’option sanitize en action :
Repérer le HTML est important, mais l’assainissement ne s’arrête pas là. Markdown ne prend pas en charge les scripts, mais il prend en charge les liens, ce qui permet de créer des liens JavaScript (par exemple, javascript:alert(1)) susceptibles de causer des dommages lorsqu’un utilisateur clique dessus. La fonctionnalité sanitize le prend en compte et supprime les liens qui ressemblent à javascript:. Elle supprime même les liens utilisant l’entité HTML pour les deux-points, : (par exemple, javascript&58;alert(1)). Malheureusement, malgré cette précaution, un cas lui échappe…
Le HTML est un format très permissif, et les navigateurs sont très tolérants lorsqu’ils le traitent. Par exemple, lors du traitement des entités HTML, les navigateurs n’exigent pas le deux-points final et acceptent aussi bien : que :. En revanche, l’assainissement de marked exige le deux-points et traite le texte comme du texte ordinaire s’il ne le trouve pas. Ainsi, : sera supprimé, mais &58this; sera transmis tel quel à la sortie. Un attaquant peut exploiter cette technique pour contourner marked tout en faisant exécuter un script par les navigateurs.
Voici un exemple de code illustrant les cas où sanitize fonctionne et ceux où elle échoue :
Le navigateur interprétera : de la même manière que : et exécutera le script au clic. Bien sûr, le script que nous avons inclus est assez inoffensif, mais un attaquant pourrait injecter une charge utile bien plus sophistiquée, contourner la politique de même origine du navigateur et provoquer tous les dégâts qu’une attaque XSS peut entraîner.
Exploitation en direct dans Goof
Comme nous l’avons fait en évoquant la vulnérabilité liée au Buffer de mongoose, nous avons ajouté cette vulnérabilité à notre application vulnérable, Goof. Exploiter une vulnérabilité et examiner le code concerné permet de mieux comprendre le problème. Vous pouvez cloner Goof et le lancer en suivant les instructions sur GitHub.
Goof est une application de gestion de tâches qui utilise marked pour prendre en charge Markdown dans ses notes. Goof est une application de gestion de tâches de premier ordre : une telle application DOIT prendre en charge les liens, le gras et l’italique !
Par exemple, saisir les tâches Buy **beer** et [snyk](https://snyk.io/) produira le résultat attendu : du texte en gras et un lien hypertexte, comme ici :

Essayons maintenant de saisir une charge utile malveillante. La capture d’écran suivante montre l’état visuel et celui du DOM après la saisie de chacune des trois charges utiles d’attaque ci-dessus. Comme il s’agit d’une liste de tâches, la première saisie apparaît en dernier (en troisième position) dans la liste.
Comme vous pouvez le voir, les deux éléments du bas, correspondant aux deux premières tentatives d’attaque, ont été réduits à <p></p> et <p>)</p> par l’assainisseur. La charge utile tout en haut a toutefois créé un lien hypertexte qui exécutera javascript:this;alert(1). L’exécution de this ne fait rien (elle fait simplement référence à une variable existante), tandis que l’alerte affiche une fenêtre contextuelle.
Après avoir rendu l’alerte de notre exploit un peu plus claire et cliqué sur le lien, voici ce qui s’affiche :

Vous pouvez reproduire vous-même cette attaque en installant Goof en local et en essayant les charges utiles d’exploitation dans le répertoire exploits.
Comment corriger le problème
Fait assez inhabituel, aucune version officielle de marked ne corrige le problème. Le dépôt de marked est inactif depuis l’été dernier, et la vulnérabilité n’a été divulguée que plus tard.
Vous pouvez toutefois corriger facilement le problème en appliquant un correctif avec le Wizard de Snyk. Ce correctif a été créé par notre équipe de recherche en sécurité et s’appuie sur la pull request d’origine de Matt Austin sur le dépôt.
Comme pour tous les autres correctifs de Snyk, vous pouvez consulter les fichiers détaillés dans notre base de données des vulnérabilités open source. Il existe en fait trois correctifs différents pour les différentes versions de marked. Le plus simple ne dépasse pas ceci :

Mise à jour : les responsables de marked ont finalement publié une nouvelle version de marked (v0.3.6) le 30 juillet 2016, qui corrige ce problème.
Vous pouvez également envisager d’utiliser un autre package Markdown, comme markdown-it ou remarkable. Rien ne garantit qu’ils soient exempts de vulnérabilités, mais aucune vulnérabilité connue non corrigée ne les affecte pour le moment.
Nouvelle publication, ancienne vulnérabilité
Dernier point intéressant : cette vulnérabilité est en réalité assez ancienne. Le problème a été signalé en mai 2015, mais n’a été enregistré dans les bases de données des vulnérabilités que le mois dernier. De tels délais ne sont pas rares : le volume de problèmes signalés sur GitHub est extrêmement élevé et difficile à suivre.
Si vous découvrez un problème de sécurité signalé dans un package npm, qu’il soit corrigé ou non, faites-le-nous savoir à l’adresse security@snyk.io : nous l’examinerons et l’ajouterons à notre base de données. L’ampleur de l’écosystème npm exige que nous travaillions tous ensemble pour rester informés de ces problèmes et contribuer à notre sécurité.
Lancez-vous dans les compétitions Capture The Flag
Apprenez à résoudre des défis Capture The Flag en regardant à la demande notre atelier virtuel d’initiation.