19 avril 2010

Comment obtenir un accès root en exploitant une faille XSS, le cas Apache

Contexte : L'infrastructure technique de la fondation Apache a été victime d'une attaque XSS suivie d'une intrusion dans les systèmes. Les administrateurs ont reporté cet incident en détail et avec transparence.

Ils ont fait état des erreurs qu’ils ont commises et ont établi des recommandations afin d'améliorer la sécurisation des infrastructures. Ce billet tente d'expliquer la partie XSS de l'attaque et d'offrir une analyse du point de vue du développeur, il livre enfin des recommandations pour vous aider à renforcer la sécurité de vos applications Web.

Tout a commencé par une simple déclaration d'anomalie (issue INFRA-2591) dans le JIRA de la fondation Apache, un message aussi bref qu'énigmatique contenant un lien masqué par Tinyurl :

«ive got this error while browsing some projects in jira http://tinyurl.com/XXXXXXXXX» (le Tinyurl a été brouillé intentionnellement).

Le lien recelait des intentions peu amicales : l'URL d'une page contenant une faille XSS complétée par un code JavaScript hostile. Le code JavaScript sous forme de paramètres HTTP fait deux choses : voler le cookie de session des administrateurs en l'envoyant à un serveur externe, puis, pour ne pas éveiller les soupçons, affiche une une stack trace Java dans pastie.org (site communautaire d'échange et de partage de texte) faisant croire qu'il y a eu vraiment un problème.

Ce lien a été créé sur mesure pour une JSP contenant une faille XSS. Cette JSP quelconque ne contient pas de code spécialement sensible, elle affiche seulement une boite de dialogue pour choisir des couleurs (colorPicker.jsp) :



Dans cette page, on récupère deux paramètres : element et defaultColor, ces deux paramètres sont directement recopiés dans la page sans aucun contrôle d'assainissement !



Pour exploiter cette faille, des valeurs pour element et defaultColor ont été judicieusement choisies, de façon à ce que le code ait un comportement spéciale. Si l'on observe bien les valeurs dans l'URL, elles sont presque inintelligibles, mais dès qu'on les injecte dans le code, celui-là change bizarrement de structure, on se rend compte rapidement de la supercherie : à la ligne 26 lorsque le moteur JavaScript exécute opener.document.jiraform.name, cela génère une erreur, le flux d'exécution entre dans le bloc catch dans lequel le navigateur envoie innocemment le cookie de l'utilisateur à un serveur, outrepassant carrément le
principe du Same Origin policy (SOP).

Le serveur en question n'est qu'un site Web hébergé gratuitement sur une banale plateforme d'hébergement : PHP, Mysql, etc. Aucun risque pour le pirate.




L'attaque ne s'arrête pas là, puisque le pirate a attaqué la mire de connexion par « recherche exhaustive » (brute force attack). Cette attaque n'a pas été détectée faute de présence d'outil adéquat (sa présence aurait aidé à détecter rapidement l'attaque).

Une fois introduit dans le système, le pirate a remplacé l’écran d’authentification par un autre lui permettant de collecter des mots de passe grâce à une archive JAR injectée, cela m’a tout de suite rappelé l'excellente étude de Philippe PRADOS qui démontre avec force détails la façon avec laquelle il est possible de compromettre une application Web en posant juste un fichier JAR. Les techniques sont nombreuses : injection d'une valve Tomcat, utilisation de l'AOP, de filtres J2EE, corruption de la configuration Spring ou la surcharge des parseurs XML du JDK (Un projet Google code consacré à cette étude http://code.google.com/p/macaron/ a été mis en place, on y trouve notamment un PDF d'une soixantaine de pages, rédigé en français : surprenant, didactique et très riche en informations).

Comment prévenir ce genre d'attaques ?

En tant que développeurs

Heureusement, il est possible de se prémunir contre ce genre d'attaque et de manière efficace. Il suffit d'observer quelques règles de programmation simples à mettre en œuvre :


Utilisez un filtre J2EE contre le XSS : il s'agit d'un filtre, qui se base sur des expressions rationnelles, et qui va analyser la requête afin d'y déceler des combinaisons de caractères non autorisées dans le corps de la requête (par exemple ?clientId=<script>...) et de prendre les mesures adéquates : traçage de la requête, envoi d'un mail à l'administrateur, assainissement des valeurs (déspécialisation des caractères spéciaux, etc.).

Validez votre filtre, en écrivant des tests unitaires basés sur les préventions XSS et sur les patterns XSS qu'il est facile de trouver sur la Toile.

Utilisez le flag httpOnly : httpOnly est un flag qui indique qu'un cookie ne peut être utilisé que pour les échanges HTTP. Aucun script ne pourra y accéder, même en présence de faille XSS, il sera impossible de subtiliser le cookie. Le flag httpOnly fonctionne sur tous les navigateurs récents (y compris la famille IE puisqu'il a été inventé en 2002 par Microsoft).

Le flag est concaténé à l'entête HTTP Set-Cookie de la façon suivante :

Set-Cookie: SESSIONID=XXXXX; path=/;HttpOnly

Pour activer ce flag dans Tomcat, il suffit d'ajouter useHttpOnly=True dans l'élément <Context> du fichier context.xml de l'application Web.

<Context useHttpOnly="true" docBase="...">

...

</Context>

Utilisez un Firewall applicatif ou WAF (Web Application Firewall) : bien que cela intéresse surtout les opérateurs de production. Il est important de connaitre cette famille d'outils.
Un WAF intervient au niveau Application du modèle OSI (différemment des firewalls qui analysent quant à eux le niveau réseau), il connait les protocoles et est capable de détecter des attaques en analysant le contenu des échanges (injection SQL, XSS, etc). Il se présente sous forme d'alliance ou sous forme de programme tel que mod_security (s'installe comme plugin dans le serveur Web Apache).


Utilisez un outil d'analyseur statique de code : un outil tel que Findbugs, permet de détecter des faiblesses dans le code (par exemple, récrire directement un paramètre de la requête HTTP dans la réponse, ou inclure directement ce paramètre dans un statement SQL).




En tant qu’utilisateurs

Ne cliquez jamais sur un lien rétréci (tinyurl, bitly, etc). Si vous utilisez Twitter, l'utilisation de réducteur d'URL est inévitable. Il existe, toutefois, des plugins pour les navigateurs qui décodent à la volée les liens raccourcis (http://longurl.org/tools ou http://www.longurlplease.com/ par
exemple).



Ne cliquez jamais sur un lien envoyé par une personne inconnue (en plus du risque de XSS, s'ajoute le risque d'attaque XSRF), même si vous connaissez la personne, il se peut que son identité soit usurpée.


Armez-vous d'un plugin de sécurité dans votre navigateur. Depuis que j'utilise NoScript, je ne peux plus m'en passer. À l'occasion de cet article, j'ai éprouvé l'efficacité de ce plugin sur la page piégée, le résultat ne m'a pas déçu (voir capture d'écran suivante).





Limitez la durée de vie de vos cookies : ne pas cocher «Se souvenir de moi» lorsque vous connectez.

Conclusion

Cette affaire nous a montré qu'il suffit d'une faille, d'un relâchement de la vigilance des utilisateurs pour que la sécurité d'un système informatique s'effondre comme un château de cartes. Les espaces collaboratifs d'entreprise se multipliant (l'explosion des offres SaaS et l'émergence des réseaux sociaux pour entreprises en témoignent), la compromission d'un seul compte utilisateur peut potentiellement affecter la sécurité du système d'informations : vol de documents confidentiels, accès aux dossiers clients (CRM), dégradation, etc.. Cela est lié à la sophistication grandissante des technologies qui peut déstabiliser les utilisateurs et fléchir leur attention. Il est donc primordial, de les sensibiliser ainsi que les développeurs aux problèmes de sécurité et de former ces derniers aux parades aux techniques d'attaque Web 2.0. Enfin, rendre les audits de sécurité systématiques et ne plus les sacrifier sur l’autel des « deadlines » nos assurera des livrables plus fiables et qui, à long terme, rentabiliseront largement l'investissement dans la sécurité.

1 commentaire:

Voronetskyy Yevgen a dit…

Merci pour cette article intéressant!