Explotaci贸n de vulnerabilidades en PHP-FPM Nginx

Explotaci贸n de vulnerabilidades en PHP-FPM Nginx
Estimado de lectura : 14 minutes

Contenido

  • 1 soporte
  • 2 Detalles de vulnerabilidad
  • 3 Conclusi贸n

Recientemente, se descubri贸 una vulnerabilidad peligrosa en un paquete de Nginx y PHP-FPM, que a menudo se encuentra en los servidores web. El exploit resultante le permite cambiar la configuraci贸n de PHP mediante la introducci贸n de variables de entorno, y una cadena de tales configuraciones conducir谩 a la ejecuci贸n remota de c贸digo. Comprendamos las vulnerabilidades en PHP-FPM Nginx y descubramos d贸nde se equivocaron los desarrolladores de PHP.

Andrei @ d90pwn Danau detect贸 el primer comportamiento anormal durante la calificaci贸n del Real World CTF 2019. El servidor reaccion贸 de manera extra帽a al car谩cter de avance de l铆nea (% 0a) enviado a la URL. Omar @beched Ganiev y Emil @neex Lerner se interesaron en esta idea. Emil descubri贸 por qu茅 sucede esto, encontr贸 una forma de explotaci贸n y escribi贸 un exploit funcional, y Omar llev贸 este error a RCE.

La esencia del problema se reduce al hecho de que en algunas configuraciones de FPM, un pirata inform谩tico puede realizar un ataque de desbordamiento de b煤fer y escribir en el espacio de direcciones reservado para los datos del protocolo FastCGI. Esto permitir谩 que se ejecuten comandos arbitrarios en el sistema remoto.

Identificador de vulnerabilidad recibido CVE-2019-11043 y el nombre provocativo para una persona de habla rusa PHuiP-FPizdaM. Para la explotaci贸n, el atacante no necesita ning煤n derecho, por lo tanto, la vulnerabilidad PHP-FPM Nginx tiene un estado cr铆tico. El problema est谩 presente en ambas ramas PHP: 5 y 7, sin embargo, debido a las peculiaridades de la optimizaci贸n, la operaci贸n solo es posible en la s茅ptima versi贸n de PHP.



La vulnerabilidad afecta a las versiones:

  • Ramas PHP 7.1.x: todas las versiones anteriores a 7.1.33
  • PHP ramas 7.2.x – todas las versiones debajo de 7.2.24
  • PHP ramas 7.3.x – todas las versiones debajo de 7.3.11

Pararse

Primero necesitamos un puesto. En mi caso, se utilizar谩n los ya queridos contenedores Docker. Si no desea entrar en la depuraci贸n, puede comenzar el entorno terminado con vulhub .

docker-compose.yml


Comienza con un comando simple: docker-compose up -d.

Quiero ver la vulnerabilidad m谩s de cerca, as铆 que construyamos PHP desde la fuente. Para comenzar, inicie Debian.

Ahora debemos encargarnos de instalar los paquetes necesarios.

Saque la 煤ltima versi贸n vulnerable de php – 7.3.10.

Configure PHP con soporte php-fpm.

Ahora hagamos la compilaci贸n e instalaci贸n. Aqu铆 todo es trivial.

Cambiamos los nombres de los archivos de configuraci贸n est谩ndar.

Despu茅s de eso, cambiamos la ruta a la carpeta donde se encuentran las configuraciones.

En la configuraci贸n de php-fpm (/usr/local/etc/php-fpm.d/www.conf) configuramos el n煤mero de procesos secundarios. Para facilitar la depuraci贸n, recomiendo poner 1.

Ahora depende de los archivos de configuraci贸n de Nginx.

/ etc / nginx / sites-enabled / default

Fastcgi_pass contiene la direcci贸n de nuestro PHP-FPM, por defecto se cuelga en el puerto 9000. Explicar茅 algunas partes de la configuraci贸n en el proceso de an谩lisis de la vulnerabilidad.

Luego debe crear el archivo PHP en la ra铆z del servidor web (/ var / www / html /). Incluso un script vac铆o es adecuado aqu铆, lo principal es que tiene la extensi贸n .php y Nginx lo env铆a a PHP. Cre茅 index.php que muestra un saludo.

/var/www/html/index.php

Ahora todo est谩 listo, puedes ejecutar Nginx.

Y luego PHP-FPM a trav茅s del depurador.

Para GDB, habilitamos la capacidad de depurar procesos secundarios e iniciar el servicio.

Stand listo para trabajar con PHP-FPM y Nginx
Stand listo para trabajar con PHP-FPM y Nginx

Detalles de vulnerabilidad

Primero, eche un vistazo al commit que parchea la vulnerabilidad .

Una confirmaci贸n que parchea la vulnerabilidad CVE-2019-11043 en PHP 7.3.10 
Una confirmaci贸n que parchea la vulnerabilidad CVE-2019-11043 en PHP 7.3.10
/php-src-php-7.3.10/sapi/fpm/fpm/fpm_main.c
/php-src-php-7.3.11/sapi/fpm/fpm/fpm_main.c

Como puede ver, se agregan comprobaciones adicionales para las variables path_info y tflag. En esta parte del c贸digo, se procesan las rutas del formulario /info.php/test.

Coloque el punto de interrupci贸n justo encima de las l铆neas parcheadas, en la l铆nea 1143, e intente enviar una solicitud GET con un byte de salto de l铆nea (% 0a).

/php-src-php-7.3.10/sapi/fpm/fpm/fpm_main.c
El punto de interrupci贸n funcion贸 en la funci贸n init_request_info despu茅s de enviar el byte 0x0a 
El punto de interrupci贸n funcion贸 en la funci贸n init_request_info despu茅s de enviar el byte 0x0a

Por supuesto, primero la URL ingresa a Nginx. D茅jame recordarte una l铆nea de la configuraci贸n.

por defecto

El byte de salto de l铆nea pasado rompe la l贸gica de la expresi贸n regular en la directiva fastcgi_split_path_info . Como resultado, la variable env_path_info toma un valor vac铆o y el pilen se vuelve igual a 0. Luego, path_info se calcula en funci贸n de estos valores.

/php-src-php-7.3.10/sapi/fpm/fpm/fpm_main.c

Cuando no se encuentra el archivo solicitado, PHP-FPM sube m谩s en el URI e intenta volver a enviar la solicitud de un script m谩s alto, si lo hay. Determinado por signos /. Por lo tanto, si solicito http: //phprce.vh/index.php/info.php, entonces el script index.php funcionar谩, ya que no tengo info.php.

PHP-FPM transfiere el control al script principal si no se encuentra el pedido 
PHP-FPM transfiere el control al script principal si no se encuentra el pedido
/php-src-php-7.3.10/sapi/fpm/fpm/fpm_main.c

Por lo tanto, hay dos variables: script_path_translated es el URI completo y pt es la ruta al script anterior. En nuestro caso, tienen una longitud de 37 (0x25) y 23 (0x17) bytes, respectivamente.

  • script_path_translated – /var/www/html/index.php/path\ninfo.php
  • pt – /var/www/html/index.php
Rutas variables a los scripts y su longitud. 
Rutas variables a los scripts y su longitud.

En base a estas variables, se considera slen.

/php-src-php-7.3.10/sapi/fpm/fpm/fpm_main.c

Y luego se calcula path_info.

Variables en funci贸n de las cuales se calcula path_info 
Variables en funci贸n de las cuales se calcula path_info
/php-src-php-7.3.10/sapi/fpm/fpm/fpm_main.c

Ahora en la expresi贸n env_path_info + pilen – slen, solo slen es distinto de cero (0xe). Por lo tanto, path_info no se帽alar谩 d贸nde lo necesita, sino a la direcci贸n que se encuentra arriba. En mi caso, esta es la l铆nea 200 en la direcci贸n 0x555556618672. Esta vulnerabilidad se llama desbordamiento de b煤fer.

La direcci贸n original del valor de path_info y la direcci贸n despu茅s del desbordamiento del b煤fer 
La direcci贸n original del valor de path_info y la direcci贸n despu茅s del desbordamiento del b煤fer

Si observa m谩s el c贸digo de funci贸n init_request_info, ver谩 una pieza curiosa.

/php-src-php-7.3.10/sapi/fpm/fpm/fpm_main.c

Como controlamos la longitud de slen, podemos escribir bytes nulos en cualquier posici贸n por encima de PATH_INFO. Para comprender lo que se puede aprender de esto, debe comprender c贸mo funciona PHP-FPM con las variables de entorno. Si observa el c贸digo un poco m谩s, veremos que uno de ellos est谩 instalado all铆: ORIG_SCRIPT_NAME.

/php-src-php-7.3.10/sapi/fpm/fpm/fpm_main.c

La funci贸n FCGI_PUTENV se inicializa como fcgi_quick_putenv.

/php-src-php-7.3.10/main/fastcgi.h

Si observa su c贸digo, ver谩 que ella modifica directamente req-> env.

/php-src-php-7.3.10/main/fastcgi.c

Esta construcci贸n se inicializa al comienzo de la consulta con la funci贸n fcgi_hash_init.

/php-src-php-7.3.10/main/fastcgi.c
/php-src-php-7.3.10/main/fastcgi.c

Aqu铆 vemos que req-> env es la estructura fcgi_data_seg .

/php-src-php-7.3.10/main/fastcgi.c

Esta estructura almacena las variables globales necesarias para la comunicaci贸n entre el proceso PHP-FPM y el servidor web (en mi caso, Nginx). Aqu铆 pos apunta a la direcci贸n del b煤fer actual, finaliza a la direcci贸n donde termina y los datos al lugar donde desea escribir los datos. Cuando el bloque de memoria asignado para la estructura finaliza (pos es mayor que final), se crea uno nuevo y la direcci贸n del actual se escribe a continuaci贸n.

Por ejemplo, as铆 es como esta estructura busca la solicitud actual y los datos almacenados en ella.

La estructura fcgi_data_seg de la solicitud y los datos actuales 
La estructura fcgi_data_seg de la solicitud y los datos actuales

Nuestro PATH_INFO tambi茅n se encuentra all铆. Preste atenci贸n a la direcci贸n pos, se encuentra arriba, por lo que puede establecer un puntero y escribir bytes nulos all铆.

La esencia del problema se reduce al hecho de que en algunas configuraciones de FPM, un pirata inform谩tico puede realizar un ataque de desbordamiento de b煤fer y escribir en el espacio de direcciones reservado para los datos del protocolo FastCGI. Esto permitir谩 que se ejecuten comandos arbitrarios en el sistema remoto.

Identificador de vulnerabilidad recibido CVE-2019-11043 y el nombre provocativo para una persona de habla rusa PHuiP-FPizdaM. Para la explotaci贸n, el atacante no necesita ning煤n derecho, por lo tanto, la vulnerabilidad PHP-FPM Nginx tiene un estado cr铆tico. El problema est谩 presente en ambas ramas PHP: 5 y 7, sin embargo, debido a las peculiaridades de la optimizaci贸n, la operaci贸n solo es posible en la s茅ptima versi贸n de PHP.

La vulnerabilidad afecta a las versiones:

  • Ramas PHP 7.1.x: todas las versiones anteriores a 7.1.33
  • PHP ramas 7.2.x – todas las versiones debajo de 7.2.24
  • PHP ramas 7.3.x – todas las versiones debajo de 7.3.11

Pararse

Primero necesitamos un puesto. En mi caso, se utilizar谩n los ya queridos contenedores Docker. Si no desea entrar en la depuraci贸n, puede comenzar el entorno terminado con vulhub .

docker-compose.yml

Comienza con un comando simple: docker-compose up -d.

Quiero ver la vulnerabilidad m谩s de cerca, as铆 que construyamos PHP desde la fuente. Para comenzar, inicie Debian.

Ahora debemos encargarnos de instalar los paquetes necesarios.

Saque la 煤ltima versi贸n vulnerable de php – 7.3.10.

Configure PHP con soporte php-fpm.

Ahora hagamos la compilaci贸n e instalaci贸n. Aqu铆 todo es trivial.

Cambiamos los nombres de los archivos de configuraci贸n est谩ndar.

Despu茅s de eso, cambiamos la ruta a la carpeta donde se encuentran las configuraciones.

En la configuraci贸n de php-fpm (/usr/local/etc/php-fpm.d/www.conf) configuramos el n煤mero de procesos secundarios. Para facilitar la depuraci贸n, recomiendo poner 1.

Ahora depende de los archivos de configuraci贸n de Nginx.

/ etc / nginx / sites-enabled / default

Fastcgi_pass contiene la direcci贸n de nuestro PHP-FPM, por defecto se cuelga en el puerto 9000. Explicar茅 algunas partes de la configuraci贸n en el proceso de an谩lisis de la vulnerabilidad.

Luego debe crear el archivo PHP en la ra铆z del servidor web (/ var / www / html /). Incluso un script vac铆o es adecuado aqu铆, lo principal es que tiene la extensi贸n .php y Nginx lo env铆a a PHP. Cre茅 index.php que muestra un saludo.

/var/www/html/index.php

Ahora todo est谩 listo, puedes ejecutar Nginx.

Y luego PHP-FPM a trav茅s del depurador.

Para GDB, habilitamos la capacidad de depurar procesos secundarios e iniciar el servicio.

Stand listo para trabajar con PHP-FPM y Nginx 
Stand listo para trabajar con PHP-FPM y Nginx

Detalles de vulnerabilidad

Primero, eche un vistazo al commit que parchea la vulnerabilidad .

Una confirmaci贸n que parchea la vulnerabilidad CVE-2019-11043 en PHP 7.3.10 
Una confirmaci贸n que parchea la vulnerabilidad CVE-2019-11043 en PHP 7.3.10
/php-src-php-7.3.10/sapi/fpm/fpm/fpm_main.c
/php-src-php-7.3.11/sapi/fpm/fpm/fpm_main.c

Como puede ver, se agregan comprobaciones adicionales para las variables path_info y tflag. En esta parte del c贸digo, se procesan las rutas del formulario /info.php/test.

Coloque el punto de interrupci贸n justo encima de las l铆neas parcheadas, en la l铆nea 1143, e intente enviar una solicitud GET con un byte de salto de l铆nea (% 0a).

/php-src-php-7.3.10/sapi/fpm/fpm/fpm_main.c
El punto de interrupci贸n funcion贸 en la funci贸n init_request_info despu茅s de enviar el byte 0x0a 
El punto de interrupci贸n funcion贸 en la funci贸n init_request_info despu茅s de enviar el byte 0x0a

Por supuesto, primero la URL ingresa a Nginx. D茅jame recordarte una l铆nea de la configuraci贸n.

por defecto

El byte de salto de l铆nea pasado rompe la l贸gica de la expresi贸n regular en la directiva fastcgi_split_path_info . Como resultado, la variable env_path_info toma un valor vac铆o y el pilen se vuelve igual a 0. Luego, path_info se calcula en funci贸n de estos valores.

/php-src-php-7.3.10/sapi/fpm/fpm/fpm_main.c

Cuando no se encuentra el archivo solicitado, PHP-FPM sube m谩s en el URI e intenta volver a enviar la solicitud de un script m谩s alto, si lo hay. Determinado por signos /. Por lo tanto, si solicito http: //phprce.vh/index.php/info.php, entonces el script index.php funcionar谩, ya que no tengo info.php.

PHP-FPM transfiere el control al script principal si no se encuentra el pedido 
PHP-FPM transfiere el control al script principal si no se encuentra el pedido
/php-src-php-7.3.10/sapi/fpm/fpm/fpm_main.c

Por lo tanto, hay dos variables: script_path_translated es el URI completo y pt es la ruta al script anterior. En nuestro caso, tienen una longitud de 37 (0x25) y 23 (0x17) bytes, respectivamente.

  • script_path_translated – /var/www/html/index.php/path\ninfo.php
  • pt – /var/www/html/index.php
Rutas variables a los scripts y su longitud. 
Rutas variables a los scripts y su longitud.

En base a estas variables, se considera slen.

/php-src-php-7.3.10/sapi/fpm/fpm/fpm_main.c

Y luego se calcula path_info.

Variables en funci贸n de las cuales se calcula path_info 
Variables en funci贸n de las cuales se calcula path_info
/php-src-php-7.3.10/sapi/fpm/fpm/fpm_main.c

Ahora en la expresi贸n env_path_info + pilen – slen, solo slen es distinto de cero (0xe). Por lo tanto, path_info no se帽alar谩 d贸nde lo necesita, sino a la direcci贸n que se encuentra arriba. En mi caso, esta es la l铆nea 200 en la direcci贸n 0x555556618672. Esta vulnerabilidad se llama desbordamiento de b煤fer.

La direcci贸n original del valor de path_info y la direcci贸n despu茅s del desbordamiento del b煤fer 
La direcci贸n original del valor de path_info y la direcci贸n despu茅s del desbordamiento del b煤fer

Si observa m谩s el c贸digo de funci贸n init_request_info, ver谩 una pieza curiosa.

/php-src-php-7.3.10/sapi/fpm/fpm/fpm_main.c

Como controlamos la longitud de slen, podemos escribir bytes nulos en cualquier posici贸n por encima de PATH_INFO. Para comprender lo que se puede aprender de esto, debe comprender c贸mo funciona PHP-FPM con las variables de entorno. Si observa el c贸digo un poco m谩s, veremos que uno de ellos est谩 instalado all铆: ORIG_SCRIPT_NAME.

/php-src-php-7.3.10/sapi/fpm/fpm/fpm_main.c

La funci贸n FCGI_PUTENV se inicializa como fcgi_quick_putenv.

/php-src-php-7.3.10/main/fastcgi.h

Si observa su c贸digo, ver谩 que ella modifica directamente req-> env.

/php-src-php-7.3.10/main/fastcgi.c

Esta construcci贸n se inicializa al comienzo de la consulta con la funci贸n fcgi_hash_init.

/php-src-php-7.3.10/main/fastcgi.c
/php-src-php-7.3.10/main/fastcgi.c

Aqu铆 vemos que req-> env es la estructura fcgi_data_seg .

/php-src-php-7.3.10/main/fastcgi.c

Esta estructura almacena las variables globales necesarias para la comunicaci贸n entre el proceso PHP-FPM y el servidor web (en mi caso, Nginx). Aqu铆 pos apunta a la direcci贸n del b煤fer actual, finaliza a la direcci贸n donde termina y los datos al lugar donde desea escribir los datos. Cuando el bloque de memoria asignado para la estructura finaliza (pos es mayor que final), se crea uno nuevo y la direcci贸n del actual se escribe a continuaci贸n.

Por ejemplo, as铆 es como esta estructura busca la solicitud actual y los datos almacenados en ella.

La estructura fcgi_data_seg de la solicitud y los datos actuales 
La estructura fcgi_data_seg de la solicitud y los datos actuales

Nuestro PATH_INFO tambi茅n se encuentra all铆. Preste atenci贸n a la direcci贸n pos, se encuentra arriba, por lo que puede establecer un puntero y escribir bytes nulos all铆.

AndresTorres

Deja un comentario o una pregunta, gracias por visitarme.

Este sitio usa Akismet para reducir el spam. Aprende c贸mo se procesan los datos de tus comentarios.

A %d blogueros les gusta esto: