Ghost est l’un des systèmes de gestion de contenu (CMS) basés sur Node.js les plus populaires. Selon le fournisseur, il y a actuellement plus de 2,5 millions d’installations et le projet compte plus de 38 000 étoiles sur GitHub. Au cours de nos recherches sur les applications open source, l’équipe SonarSource Security Research a analysé le code et trouvé une vulnérabilité dans Ghost 4.3.2 qui permet aux attaquants de prendre le contrôle des comptes d’administrateur.
Dans cet article de blog, nous allons d’abord examiner certaines technologies Web nécessaires pour comprendre la vulnérabilité. Ensuite, nous montrerons la vulnérabilité et comment elle a pu être exploitée par des attaquants. Enfin, nous expliquerons comment éviter ou résoudre de tels problèmes pendant le développement.
Impacter
La vulnérabilité de code, CVE-2021-29484, a été introduite dans Ghost 4.0.0 et corrigée dans la version 4.3.3. Il s’agit d’un problème de Cross-Site Scripting (XSS) basé sur DOM qui permet aux attaquants de prendre le contrôle de comptes, y compris les administrateurs. Cela leur permettrait de lire ou de modifier toute donnée sur le site.
L’exploitation de cette vulnérabilité nécessite que la victime visite un lien malveillant tout en étant connectée à la zone d’administration de Ghost. Les versions affectées de Ghost sont vulnérables dans la configuration par défaut, et il n’y a aucun paramètre pour désactiver le composant affecté.
La vidéo suivante montre l’exploitation de la vulnérabilité en faisant cliquer un administrateur sur un lien malveillant qui crée un nouveau compte privilégié pour l’attaquant sans que la victime s’en aperçoive :
Détails techniques
Nous allons d’abord expliquer les technologies Web qui sont importantes pour comprendre cette vulnérabilité : la politique de même origine et la messagerie d’origine croisée. Ensuite, nous expliquons comment fonctionne la vulnérabilité et comment éviter de tels problèmes pendant le développement.
Fond
Lorsqu’un site Web intègre un autre site Web à l’aide d’un <iframe>
élément, certaines règles contrôlent la façon dont les deux sites peuvent interagir les uns avec les autres. Cet ensemble de règles est appelé la politique de même origine (SOP). Il empêche différents sites Web de se lire ou de se modifier directement à moins qu’ils ne proviennent du même origine. L’origine d’un site Web se compose du protocole, de l’hôte et du port de l’URL du site Web. Par exemple, https://example.com
est l’origine de https://example.com/test/?id=42
(le port est omis ici car il peut être dérivé du protocole).
En conséquence, un site Web sur https://attacker.com
ne peut pas lire ou manipuler les données de https://facebook.com
, mais https://attacker.com/xxx
peut accéder au contenu de https://attacker.com/yyy
. Il s’agit d’un mécanisme de sécurité important car sinon, chaque site Web que vous visitez pourrait voler vos messages Facebook privés ou lire vos données bancaires, simplement en incorporant le site de la victime.
Cependant, il existe toujours un moyen pour les sites Web de communiquer avec d’autres sites Web qui sont origine croisée, ce qui signifie qu’ils ont des origines différentes. Pour ce faire, les sites Web peuvent envoyer et recevoir des événements de message à l’aide de l’API postMessage. Cette méthode est assez sécurisée par défaut car elle ne permet pas aux sites d’accéder directement au DOM de l’autre, mais il y a toujours de la place pour que les choses tournent mal lors du traitement de ces messages, comme nous le verrons dans la section suivante.
XSS basé sur DOM dans l’aperçu du thème (CVE-2021-29484)
Ghost est un CMS qui se compose de deux composants. Le premier composant est la page contenant le contenu, l’autre est la zone d’administration. L’interface d’administration est généralement servie sur le /ghost/
sous-chemin d’un site Ghost, mais il peut également être servi sur un autre domaine si les utilisateurs souhaitent utiliser une configuration extra-sécurisée. La zone d’administration permet aux utilisateurs dotés de divers rôles de se connecter et d’effectuer des tâches, par exemple la rédaction de nouveaux articles de blog, la modification des paramètres ou la modification du thème du site.
Dans Ghost 4.0.0, une fonctionnalité de prévisualisation du thème a été ajoutée à l’interface d’administration. Il se compose d’une page HTML statique qui est servie dans le contexte de la zone d’administration à /ghost/preview
. La page, simplifiée par souci de concision, ressemble à ceci :
core/server/web/admin/views/preview.html :
1 <script type="text/javascript" charset="utf-8">
2 (function(){
3 function onReceive(message) {
… // ...
6 document.write(message.data);
… // ...
9 }
… // ...
34 if (window.addEventListener){
35 addEventListener("message", onReceive, true);
… // ...
38 }
… // ...
42 })();
… // ...
53 </script>
Il contient un script qui écoute message
événements (ligne 35). Si un tel événement se produit, son contenu est ajouté à la page à la ligne 6, mais sans vérifier l’origine de l’événement. Ceci constitue une vulnérabilité car un site de n’importe quelle origine pourrait envoyer un tel message. L’ensemble du composant de prévisualisation du thème est intégrable de n’importe où, car il n’y a pas X-Frame-Options
en-tête et non frame-ancestors
directive dans le Content-Security-Polic
y en-tête qui l’empêcherait.
Cela permet un XSS basé sur DOM dans le contexte du panneau d’administration. Un attaquant pourrait créer un site Web qui intègre la page d’aperçu du thème et lui envoie une charge utile HTML malveillante. La charge utile sera ensuite insérée dans la page, exécutant tout JavaScript qu’elle contient. Puisque la victime est connectée, l’attaquant peut maintenant faire tout ce que la victime est autorisée à faire.
Les attaquants pourraient l’utiliser pour s’emparer de comptes privilégiés, tels que des administrateurs ou des propriétaires, en les incitant à visiter un site Web contrôlé par un attaquant tout en étant connecté. La charge utile malveillante pourrait créer un nouveau compte administrateur pour l’attaquant, ce qui fournirait un accès illimité à la zone d’administration de Ghost. Ceci est démontré dans la vidéo de démonstration ci-dessus.
exploit.html :
<iframe name="iframe" src="http://ghost:2368/ghost/preview"></iframe>
<script>
window.addEventListener('message', (event) => {
if (event.data === 'loaded') {
const payload = 'alert(origin)';
iframe.postMessage(`<script>${payload}<x2fscript>`, '*');
}
});
</script>
Cet exemple d’exploit fonctionne en incorporant la page d’aperçu du thème d’une instance Ghost dans un iframe, puis en utilisant l’API postMessage pour envoyer un message contenant un script malveillant une fois l’iframe chargé. Lorsqu’une victime, par exemple un utilisateur administrateur, visite la page de l’attaquant, la charge utile du script est exécutée et peut effectuer n’importe quelle action en tant qu’administrateur. Cela entraînerait la prise de contrôle du site Ghost, car l’attaquant pourrait tout lire et tout modifier.
Cette vulnérabilité montre que même dans des bases de code de haute qualité, des choses peuvent passer à travers. Une approche automatisée permet de détecter les problèmes avant qu’ils n’entrent en production ou même avant qu’ils ne quittent l’IDE.
Pièce
Dans ce cas, le fournisseur a choisi de supprimer le composant concerné car il n’était de toute façon pas utilisé. Dans d’autres scénarios, il se peut que l’option ne soit pas aussi simple.
Le principal problème était que tout Le site Web aurait pu envoyer un événement de message et le composant de prévisualisation du thème ne validerait pas d’où il venait. Heureusement, les événements de message ont la propriété origin qui peut être utilisée pour valider l’expéditeur. Une solution simple consisterait à comparer l’origine de l’événement avec un ensemble d’origines autorisées et à rejeter tout message provenant d’ailleurs. Exemple:
const allowedOrigins = [
'https://example.com',
'https://blog.example.com',
];
window.addEventListener('message', (event) => {
if (!allowedOrigins.includes(event.origin)) {
return;
}
handleEvent(event);
});
Ainsi, si votre code gère des événements de message d’origine croisée, vous pouvez vérifier s’il utilise les messages de manière potentiellement dangereuse, par exemple en insérant des données non filtrées dans la page. Dans ce cas, nous vous recommandons de vérifier l’origine pour vérifier que les événements proviennent d’origines non malveillantes, comme le montre l’exemple ci-dessus.
Chronologie
Date |
action |
2021-04-27 |
Nous envoyons un avis détaillé par e-mail |
2021-04-27 |
Le fournisseur confirme le problème, demande une preuve de concept supplémentaire (PoC) |
2021-04-27 |
Nous envoyons un PoC supplémentaire qui démontre l’impact |
2021-04-28 |
Le vendeur demande des éclaircissements supplémentaires |
2021-04-28 |
Nous fournissons plus de détails |
2021-04-29 |
Le fournisseur publie la version 4.3.3 |
Sommaire
Dans cet article de blog, nous avons analysé une vulnérabilité de code trouvée dans Ghost 4.3.2, un CMS open source largement utilisé écrit en JavaScript. Nous avons décrit le fonctionnement de la stratégie Same-Origin Policy et la manière dont la gestion dangereuse des messages Cross-Origin peut conduire à la prise de contrôle d’une instance Ghost. Nous avons également expliqué comment prévenir les vulnérabilités de ce type.
Nous avons signalé ces vulnérabilités au fournisseur fin avril 2021. Ils ont confirmé et corrigé les vulnérabilités immédiatement et ont pris la sécurité de leur produit très au sérieux, donc un grand bravo à l’équipe de sécurité de Ghost ! Si vous utilisez Ghost, nous vous recommandons de mettre à jour au moins la version 4.3.3.