URL: https://linuxfr.org/news/snuffleupagus-version-0-3-0-dentalium-elephantinum Title: Snuffleupagus version 0.3.0 Dentalium elephantinum Authors: jvoisin Nils Ratusznik, k3y, LucieS, Davy Defaud, BAud et Benoît Sibaud Date: 2018年07月18日T15:30:09+02:00 License: CC By-SA Tags: sécurité, php, suhosin, snuffleupagus et php7 Score: 43 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. ---- [Site Web de Snuffleupagus](https://snuffleupagus.readthedocs.io/) [Dépôt GitHub](https://github.com/nbs-system/snuffleupagus) [Notes de version](https://github.com/nbs-system/snuffleupagus/releases/tag/v0.3.0) [L’annonce de la version 0.3.0 sur Twitter](https://twitter.com/sp_php/status/1019572407407869952) [Compte Twitter du projet](https://mobile.twitter.com/sp_php) [Billet détaillé de l’annonce de la 0.3.0 d’un des développeurs](https://dustri.org/b/snuffleupagus-030-dentalium-elephantinum.html) ---- # Naissance de Snuffleupagus Début 2017, la fin du support de PHP 5, [prévue pour fin 2018](https://secure.php.net/supported-versions.php ) 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](https://suhosin.org/stories/index.html) ne fonctionne pas sur PHP 7, et son successeur, [suhosin7]( https://github.com/sektioneins/suhosin7) semble au point mort. C’est pourquoi l’équipe sécurité de [NBS System]( https://nbs-system.com ) a retroussé ses manches en se disant que, puisque le (défunt) projet [Hardened‐PHP](http://hardened-php.net/) 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](https://twitter.com/i0n1c) et ses compères de [SektionEins](http://www.sektioneins.com/en/), 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]( https://github.com/nbs-system/snuffleupagus/releases/tag/v0.1.0 ), sous LGPL, nommée *Mighty Mammoth*. ![Logo de snuffleupagus](https://dustri.org/b/images/sp.png) Pourquoi Snuffleupagus ? Parce que les deux trublions qui ont posé les premiers jalons du projet sont tombés sur l’[article Wikipédia](https://en.wikipedia.org/wiki/Mr._Snuffleupagus) 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](https://secure.php.net/elephpant.php), 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]( https://github.com/roundcube/roundcubemail/wiki/Upgrade#update-your-existing-roundcube-installation ). 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 : ```php sp.disable_function.function("system").drop(); ``` Pour l’autoriser uniquement dans le fichier `upgrade.php` dont le SHA-256 est `1234...aaab` : ```php 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](https://github.com/nbs-system/snuffleupagus/tree/master/scripts) 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)](https://fr.wikipedia.org/wiki/Syst%C3%A8me_de_gestion_de_contenu "Système de gestion de contenu"), 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](https://fr.wikipedia.org/wiki/Adresse_IP#Agr%C3%A9gation_des_adresses) 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](https://secure.php.net/manual/fr/language.namespaces.rationale.php) à 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](https://fr.wikipedia.org/wiki/Paamayim_Nekudotayim) : `function("maClasseTropClasse::ma_methode")`. ### Et avec ça, on fait quoi ? On peut contrecarrer les injections dans `system` avec une règle comme : ```php sp.disable_function("system").param("command").value_r("[$|;&\n").drop() ``` Ainsi que dans `mail`, avec : ```php 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](https://nvd.nist.gov/vuln/detail/CVE-2018-12421) dans [_Self‐service password_](https://linuxfr.org/news/sortie-de-ldap-tool-box-self-service-password-1-3) peut être mitigée via : ```python 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](https://developer.mozilla.org/fr/docs/Glossaire/Cross-site_scripting) 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](https://suhosin.org/stories/feature-list.html) 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_](https://tools.ietf.org/html/rfc7627) à 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](https://fr.wikipedia.org/wiki/Cross-site_request_forgery "Cross‐Site Request Forgery"). ### 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](https://suhosin.org/stories/feature-list.html) via sa directive [`suhosin.upload.verification_script`](https://suhosin.org/stories/configuration.html#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](https://github.com/nbs-system/snuffleupagus/blob/master/scripts/upload_validation.py) utilisant [VLD](https://github.com/derickr/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](https://fr.wikipedia.org/wiki/Keyed-hash_message_authentication_code "hash message authentication code") à 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`](https://secure.php.net/manual/en/function.random-int.php ), qui elle est plus sûre d’un point de vue cryptographique. ### XXE Les [XXE]( https://en.wikipedia.org/wiki/XML_external_entity_attack ) 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](https://secure.php.net/manual/en/refs.xml.php) analyseurs (_parsers_) XML. ### Transtypage à la sauvage PHP possède un [système de types bien à lui]( https://secure.php.net/manual/fr/types.comparisons.php ) 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 : ```php 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](https://www.alexa.com/topsites) 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](https://github.com/nbs-system/snuffleupagus/blob/master/config/default.rules) 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](https://dustri.org/b/images/snuffleupagus_without.png) * avec Snuffleupagus : ![Graphique de performance de la suite de Joomla avec Snuffleupagus](https://dustri.org/b/images/snuffleupagus_0.3.0.png) # Retours de la communauté et perspectives d’avenir Snuffleupagus a été présenté à différentes conférences de sécurité : [BerlinSides](https://github.com/nbs-system/snuffleupagus/blob/master/slides/berlinsides_2017.pdf), [BlackAlps](https://github.com/nbs-system/snuffleupagus/blob/master/slides/blackalps_2017.pdf), la [Hack.lu]( https://github.com/nbs-system/snuffleupagus/blob/master/slides/hacklu_2017.pdf ), [_Pass the Salt_](https://github.com/nbs-system/snuffleupagus/blob/master/slides/passthesalt_2018.pdf), ainsi qu’à la [_44con_](https://44con.com/44con/44con-2018/44con-2018-talks/) en septembre prochain, et a même eu droit à un article dans [MISC](https://twitter.com/sp_php/status/983697355286298624) ! 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](https://www.reddit.com/r/PHP/comments/72e20p/security_module_for_php7_killing_bugclasses_and/) et les [équipes sécurité](https://www.reddit.com/r/netsec/comments/72e1sl/security_module_for_php7_killing_bugclasses_and/) 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]( https://github.com/nbs-system/snuffleupagus/issues ) 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.

AltStyle によって変換されたページ (->オリジナル) /