Snuffleupagus version 0.3.0 Dentalium elephantinum

Posté par (page perso) . Édité par Nils Ratusznik, k3y, LucieS, BAud, Davy Defaud et Benoît Sibaud. Modéré par Yvan Munoz. Licence CC by-sa.
43
21
juil.
2018
Sécurité

Snuffleupagus est un module pour PHP (version 7.0 et supérieures) qui a pour but d’augmenter drastiquement la difficulté des attaques contre les sites Web. Cela s’obtient, entre autres, via la désactivation de fonctions et de classes, et en fournissant un système de correctifs virtuels, permettant à l’administrateur de corriger des vulnérabilités spécifiques sans modifier le code PHP.

La version 0.3.0, disponible depuis le 18 juillet 2018, est un excellent prétexte pour parler de ce projet sur LinuxFr.org, avec des détails juteux en deuxième partie de dépêche.

Sommaire

Naissance de Snuffleupagus

Début 2017, la fin du support de PHP 5, prévue pour fin 2018 commence à pointer son nez à l’horizon, c’est l’inquiétude chez les hébergeurs Web soucieux de la sécurité : le (fabuleux) module Suhosin ne fonctionne pas sur PHP 7, et son successeur, suhosin7 semble au point mort.

C’est pourquoi l’équipe sécurité de NBS System a retroussé ses manches en se disant que, puisque le (défunt) projet Hardened‐PHP puis SektionEins ont réussi à faire un tel module, pourquoi pas elle ? Le but étant de profiter de l’occasion pour dépoussiérer quelques fonctionnalités, supprimer les redondances ou les mécanismes obsolètes, ajouter quelques bonus et corriger encore plus de bogues !

Suhosin a été créé et maintenu principalement par Stefan Esser et ses compères de SektionEins, qui sont des professionnels de la sécurité Web, mais absolument pas des hébergeurs, et ça peut se ressentir au niveau de l’industrialisation, qui peut parfois être un peu fastidieuse.

C’est pour cette raison que l’idée de contribuer à suhosin7 n’a pas été retenue : les hébergeurs ont des besoins spécifiques (industrialisation, fiabilité, souplesse…) auxquels Suhosin, créé il y a plus de dix ans, ne répond plus forcément : les menaces ont évolué, les vecteurs d’attaques également.

C’est pourquoi, un peu moins d’un an après avoir évoqué l’idée d’écrire notre propre module, le 21 décembre 2017, sortait la première mouture, sous LGPL, nommée Mighty Mammoth.

Logo de snuffleupagus

Pourquoi Snuffleupagus ? Parce que les deux trublions qui ont posé les premiers jalons du projet sont tombés sur l’article Wikipédia d’un certain Aloysius Snuffleupagus, et sont immédiatement tombés sous le charme de cet éléphant sans défenses aussi majestueux que PHP lui‐même. Et comme PHP aussi possède un éléphant en logo, l’approche semble plutôt raccord.

À quoi ça sert, comment ça marche ?

Les fonctionnalités de Snuffleupagus peuvent être découpées en deux grandes familles : les correctifs virtuels et l’extinction de classes de bogues.

Correctifs virtuels

Prenons un exemple concret, le processus de mise à jour de Roundcube. Celui‐ci explique que :

PHP function system must be NOT disabled in php.ini parameter disable_functions, so that our script can call rsync command to copy files. It’s recommended to disable system function after upgraded Roundcube.

Choix cornélien : avoir une instance de Roundcube à jour, ou interdire la fonction system pour complexifier la vie de potentiels pirates… Si seulement il était possible d’avoir les deux. Et c’est précisément ça que propose Snuffleupagus : du filtrage granulaire.

Pour interdire la fonction system sur tout un site :

sp.disable_function.function("system").drop();

Pour l’autoriser uniquement dans le fichier upgrade.php dont le SHA-256 est 1234…aaab :

sp.disable_function.function("system").filename("/var/www/monsite/moncms/upgrade.php").hash("1234…aaab").allow();
sp.disable_function.function("system").drop();

Un script de génération de règles est même fourni pour générer ce genre de configuration pour les fonctions dangereuses.

En tant qu’hébergeur, cette fonctionnalité est formidable : en un coup de Salt, Puppet, Chef, Ansible, etc., il est possible d’appliquer un correctif virtuel sur l’ensemble d’un parc, sans avoir à toucher à l’applicatif, connaître sa version, son SGC (CMS), sa configuration… Pour peu que le correctif soit suffisamment spécifique, il n’aura pas d’effet de bord sur les applications non concernées.

Filtres

Il y a une bonne vingtaine de filtres et d’actions :

  • alias(description) : description de la règle ;
  • cidr(ip/masque) : filtre sur le CIDR du client ;
  • filename(nom) : filtre sur le nom du fichier ;
  • filename_r(regexp) : filtre sur le nom du fichier correspondant à l’expression rationnelle ;
  • function(nom) : filtre sur le nom de la fonction ;
  • function_r(regexp) : filtre sur le nom de la fonction correspondant à l’expression rationnelle ;
  • hash(sha256) : filtre sur le hash du fichier ;
  • line(numéro_de_ligne) : filtre sur le numéro de ligne ;
  • param(nom) : filtre sur le nom du paramètre de la fonction ;
  • param_r(regexp) : filtre sur le nom du paramètre de la fonction correspondant à l’expression rationnelle ;
  • param_type(type) : filtre sur le type du paramètre de la fonction ;
  • ret(valeur) : filtre sur la valeur de retour de la fonction ;
  • ret_r(regexp) : filtre sur la valeur de retour de la fonction correspondant à l’expression rationnelle ;
  • ret_type(nom_du_type) : filtre sur le type de retour de la fonction ;
  • value(valeur) : filtre sur une valeur littérale ;
  • value_r(regexp) : filtre sur une valeur littérale correspondant à l’expression rationnelle ;
  • var(nom) : filtre sur un nom de variable ;
  • key(nom) : filtre sur la présence d’une clef dans une table de hash ;
  • key_r(regexp) : filtre sur la présence d’une clef dans une table de hash correspondant à l’expression rationnelle ;
  • allow() : autorise la requête si la règle correspond ;
  • drop() : interdit la requête si la règle correspond ;
  • dump(dossier) : fait un dump de la requête dans le dossier indiqué sur la règle correspondante ;
  • simulation() : active le mode simulation : l’événement est journalisé et la requête autorisée.

Il est également possible de déréférencer des espaces de noms à l’aide de l’opérateur \\, comme par exemple function("AwesomeNamespace\\\\my_function") : \ étant un caractère d’échappement, il faut lui‐même l’échapper pour l’utiliser. On peut faire de même pour des classes avec l’opérateur de portée :: (aussi appelé Paamayim Nekudotayim : function("maClasseTropClasse::ma_methode").

Et avec ça, on fait quoi ?

On peut contrecarrer les injections dans system avec une règle comme :

sp.disable_function("system").param("command").value_r("[$|;&\n").drop()

Ainsi que dans mail, avec :

sp.disable_function("mail").param("additional_parameters").value_r("-").drop()

On peut aussi écrire des règles moins générales, pour corriger des vulnérabilités spécifiques. Par exemple, la récente vulnérabilité CVE-2018-12421 dans Self‐service password peut être mitigée via :

sp.disable_function.filename("change.php").param("confirmpassword").param_type("array").drop();
sp.disable_function.filename("change.php").param("newpassword").param_type("array").drop();
sp.disable_function.filename("change.php").param("oldpassword").param_type("array").drop();
sp.disable_function.filename("change.php").param("login").param_type("array").drop();
sp.disable_function.function("ldap_bind").ret("false").drop();

Mais écrire des règles à la main, c’est pénible ; on le fait quand on n’a pas le choix, mais ce serait chouette de pouvoir se prémunir de classes entières de vulnérabilités, de manière passive.

Extinction de classes de bogues

XSS

Le vecteur post‐exploitation le plus courant pour les XSS consiste à voler les cookies de session des utilisateurs, afin de pouvoir se faire passer pour eux auprès de l’application.

Pour compliquer un peu la vie des attaquants, Snuffleupagus a récupéré l’idée de Suhosin consistant à chiffrer les cookies avec une clef spécifique à chaque client : en cas de vol de cookie, ce dernier ne sera pas réutilisable par quelqu’un d’autre. Historiquement, le chiffrement se faisait avec le user‐agent et l’adresse IP du client, mais en 2018 tout le monde fait de l’itinérance à outrance, invalidant donc le cookie à chaque changement d’adresse IP. C’est pourquoi il est maintenant recommandé de dériver le matériel cryptographique de la TLS extended master key à la place, qui ne change pas lors de l’itinérance.

Durcissement des cookies

Si le client utilise le site à travers une connexion sécurisée (HTTPS), l’attribut secure sera automatiquement ajouté sur les cookies, afin d’interdire leur transmission sur des connexions non sécurisées. Les cookies chiffrés, comme indiqué dans le paragraphe précédent, sont également marqués de l’attribut httpOnly, interdisant d’y accéder via du JavaScript. En effet, comme ils sont chiffrés, ils seront illisibles par le client. Et enfin, il est possible d’ajouter l’attribut samesite sur les cookies afin de lutter contre les CSRF.

Exécution de code arbitraire via l’envoi de fichiers

Sur bon nombre de sites, il est possible d’envoyer des fichiers, par exemple des avatars sur un forum, des images sur une galerie photo, etc. Et, parfois, il est possible d’envoyer un fichier contenant du code PHP et de pousser le site à l’exécuter.

Là aussi, Suhosin avait prévu le coup via sa directive suhosin.upload.verification_script permettant d’appeler un script sur les fichiers reçus par PHP, en vue de détecter si ces derniers sont malveillants ou non.

Snuffleupagus reprend l’idée, et propose de brancher un script Python utilisant VLD dessus, pour détecter la présence de code PHP. En effet, VLD est un compilateur pour PHP, transformant un fichier PHP en bytecode. Il suffit donc de lancer les fichiers envoyés dans VLD et de regarder si ce dernier produit du bytecode. Cette méthode permet de déceler du code PHP dans n’importe quel fichier : exit donc les portes dérobées via du code PHP embarqué dans les métadonnées d’images ou dans des vidéos !

Exécution de code arbitraire via dé‐sérialisation

PHP permet de sérialiser et dé‐sérialiser des données via serialize et unserialize. Malheureusement, ce processus n’est pas sûr et, si un attaquant venait à pouvoir contrôler des données transmises à unserialize, il lui serait souvent possible d’obtenir une exécution de code arbitraire.

C’est pourquoi Snuffleupagus ajoute un HMAC à la fin des données produites par un appel à serialize, afin d’interdire leur modification.

Utilisation d’entropie de faible qualité

Les fonctions rand et mt_rand génèrent de l’entropie de faible qualité qu’il n’est pas souhaitable d’utiliser pour la génération de matériel cryptographique. Malheureusement, on peut croiser régulièrement des générateurs de jetons ou de mots de passe basés dessus. Snuffleupagus remplace les appels à ces fonctions par des appels à random_int, qui elle est plus sûre d’un point de vue cryptographique.

XXE

Les XXE sont une classe de vulnérabilités peut‐être moins connue que les classiques injections SQL et XSS, mais elles permettent souvent à un attaquant d’obtenir une lecture arbitraire de fichiers et, parfois, une exécution de code arbitraire.

Pour empêcher son exploitation, Snuffleupagus se contente de désactiver la fonctionnalité dans les analyseurs XML de PHP. Oui, PHP possède plusieurs analyseurs (parsers) XML.

Transtypage à la sauvage

PHP possède un système de types bien à lui avec des résultats parfois « étonnants », comme par exemple le fait que md5('240610708') == md5('QNKCDZO'), ou que TRUE == strcmp('a', ['b']);. Snuffleupagus peut forcer l’utilisation de la comparaison stricte afin de rendre les résultats de comparaisons moins « surprenants ».

Récupération passive de vulnérabilités

Grâce au mode .simulation(), il est possible de poser des filtres sur un large ensemble de fonctions et de faire le tri ensuite. Par exemple :

sp.disable_function("system").param("command").regexp("[;`&$|\n]").simulation().dump(/var/dump/sp/)

Ceci permet d’attraper pas mal de tentatives d’injection de commandes dans la fonction system et de récupérer le contenu des requêtes.

Comme Snuffleupagus a été écrit en gardant à l’esprit que bon nombre de développeurs allait vouloir l’épingler sur les performances, il a été écrit en prenant bien garde à ne pas avoir d’impact dessus, ce qui permet d’utiliser un bon nombre de règles en « simulation » sur des systèmes en production afin de récupérer des vulnérabilités.

Il est également possible d’utiliser ce système de manière conjointe avec un scanner de vulnérabilités ainsi qu’un robot (crawler) avec des marqueurs, afin de déclencher un maximum de chemins possibles dans l’application, et donc de maximiser les chances de déclencher une règles sur une fonction « intéressante ».

Quid des impacts en performance ?

Snuffleupagus est actuellement déployé sur au moins deux sites du Top 8 k Alexa et sur une partie des clients de NBS System, sans impact notable au niveau des performances. En effet, les fonctionnalités d’extinction de classes de bogues ne s’appliquant que sur certaines fonctionnalités bien précises de PHP, tant que ces dernières ne sont pas invoquées, Snuffleupagus n’intervient pas. Quant à la partie de correctifs virtuels, la configuration fournie par défaut n’a pas d’impact visible lors de tests en utilisant la suite de tests de Joomla :

  • sans Snuffleupagus :
    Graphique de performance de la suite de Joomla sans Snuffleupagus

  • avec Snuffleupagus :
    Graphique de performance de la suite de Joomla avec Snuffleupagus

Retours de la communauté et perspectives d’avenir

Snuffleupagus a été présenté à différentes conférences de sécurité : BerlinSides, BlackAlps, la Hack.lu, Pass the Salt, ainsi qu’à la 44con en septembre prochain, et a même eu droit à un article dans MISC !

Les retours de la communauté ont été extrêmement positifs, avec de nouvelles idées ainsi que des déploiements toujours plus nombreux.

Malheureusement, la dichotomie entre développeurs et les équipes sécurité subsiste parfois, alors que les uns ne vont pas sans les autres et inversement.

Pour ce qui est de la suite du programme, le gros des fonctionnalités a été implémenté, il ne reste plus que des soucis mineurs et les inévitables bogues remontés par la communauté. Snuffleupagus étant utilisé en interne par NBS System, il est plus que probable qu’il continue à être maintenu pour les années à venir, avec entrain et bonne humeur.

  • # Merci

    Posté par (page perso) . Évalué à 6 (+5/-0). Dernière modification le 21/07/18 à 21:37.

    Super projet : merci pour la découverte !

  • # Interaction

    Posté par . Évalué à 5 (+4/-0).

    Comment se passe l'interaction avec le reste de la communauté ?
    Par exemple :

    • est-ce-qu'il existe un document simple regroupant la description des règles pour ne pas avoir besoin de cet outil ou pour en simplifier son déploiement ? Par exemple sous la forme d'un linter
    • est-ce-qu'il est envisageable de voir certaines fonctionnalités arriver directement dans le PHP standard ?
    • php n'est plus vraiment tout seul est-ce que cet outil adresse aussi hip-hop ou hack ?

    En tout cas merci pour le partage c'est super intéressant

    • [^] # Re: Interaction

      Posté par (page perso) . Évalué à 5 (+4/-0).

      • Il y a la documentation pour ce qui est de l'écriture de règles. Comme leur syntaxe est plutôt simple, on n'a pas pris le temps de coder un linter; et quand bien même une règle malformée se glisserait dans la configuration, Snuffleupagus en parlerait dans ses logs.
      • Pas vraiment: les modifications effectuées par Snuffleupagus sont pas mal invasives, et je doute que les développeurs de php aient envie de les intégrer telles quelles, et quand bien même se serait le cas, nous n'avons pas prévu de prendre le temps de faire ça. Par contre, si des gens sont motivés pour tenter d'upstreamer les fonctionnalités les plus simples, on serait ravi de les aider : par exemple, le support de SameSite devrait arriver bientôt.
      • Uniquement PHP: Hip-Hop a une architecture trop différente, et Hack n'est plus compatible avec PHP.
  • # vieux fou

    Posté par . Évalué à 6 (+4/-0).

    La version 0.3.0, disponible depuis le 18 juillet 2018, est un excellent prétexte pour parler de ce projet sur LinuxFr.org, avec des détails juteux en deuxième partie de dépêche.

    Il faut une raison maintenant pour parler de quelque chose sur linuxfr.org ?

  • # Commentaire supprimé

    Posté par . Évalué à -1 (+0/-1). Dernière modification le 29/07/18 à 18:12.

    Ce commentaire a été supprimé par l'équipe de modération.

Envoyer un commentaire

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.