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
- À quoi ça sert, comment ça marche ?
- Récupération passive de vulnérabilités
- Quid des impacts en performance ?
- Retours de la communauté et perspectives d’avenir
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.
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
parameterdisable_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 :
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.
Aller plus loin
- Site Web de Snuffleupagus (355 clics)
- Dépôt GitHub (134 clics)
- Notes de version (77 clics)
- L’annonce de la version 0.3.0 sur Twitter (83 clics)
- Compte Twitter du projet (84 clics)
- Billet détaillé de l’annonce de la 0.3.0 d’un des développeurs (92 clics)
# Merci
Posté par ComputingFroggy (site web personnel) . Évalué à 6. Dernière modification le 21 juillet 2018 à 21:37.
Super projet : merci pour la découverte !
# Interaction
Posté par barmic . Évalué à 5.
Comment se passe l'interaction avec le reste de la communauté ?
Par exemple :
En tout cas merci pour le partage c'est super intéressant
[^] # Re: Interaction
Posté par jvoisin (site web personnel) . Évalué à 5.
SameSite
devrait arriver bientôt.# vieux fou
Posté par KiKouN . Évalué à 6.
Il faut une raison maintenant pour parler de quelque chose sur linuxfr.org ?
# Commentaire supprimé
Posté par anissaj11 . Évalué à -1. Dernière modification le 29 juillet 2018 à 18:12.
Ce commentaire a été supprimé par l’équipe de modération.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.