Algunas configuraciones de mod_proxy en Apache HTTP Server desde la versión 2.4.0 hasta 2.4.55 permiten ataques de HTTP Request Smuggling (técnica de ataque que interfiere en el proceso de manejo de las secuencias de solicitudes HTTP recibidas de uno o más usuarios).
Estas configuraciones se ven afectadas cuando mod_proxy está habilitado junto con ciertas formas de RewireRule o ProxyPassMatch, donde un atacante remoto puede explotar esta vulnerabilidad para evadir los controles de acceso en el servidor proxy, autorizando así URLs no deseadas al servidor de origen.
Esta vulnerabilidad permite a un atacante apuntar y acceder a aplicaciones internas ocultas por el proxy, lo que potencialmente puede conducir a acceso no autorizado, fuga de datos o una mayor explotación del sistema.
Experimentación de CVE-2023-25690
Se utiliza una máquina Windows como máquina atacante.
Los componentes backend-server y proxy-server se despliegan mediante Docker en una máquina Kali Linux.
Estructura de archivos del laboratorio:
Modelo experimental
Dirección IP de la máquina Windows 10: 192.168.1.177
Dirección IP de la máquina Kali Linux: 192.168.27.139
Dirección IP del Backend-Server: 172.18.0.2
Dirección IP del Proxy-Server: 172.18.0.3
Cuando la máquina Windows 10 accede al Apache HTTP Server alojado en la máquina Kali en el puerto 80, el tráfico se reenvía al puerto 80 del Proxy-Server y luego se transmite al Backend-Server a través del puerto 8080.
Requisitos del sistema
Máquina atacante:
Sistema operativo Windows 10
Instalar las herramientas: Pycharm, BurpSuite, VScode
Usar el navegador FireFox e instalar la extensión FoxyProxy para configurar el proxy
Máquina víctima:
Instalar las herramientas y servicios: Docker, Tcpdum
Configurar Docker File (ver la sección de apéndice)
Objetivo de explotación: aprovechar la vulnerabilidad de HTTP Request Smuggling para evadir las restricciones del proxy server y acceder a la función oculta en la página admin.php
Implementación experimental:
Usar BurpSuite Community configurado como proxy para interceptar y modificar las requests.
En el navegador, descargar la extensión FoxyProxy y añadir la información del proxy:
Activar FoxyProxy en la barra de herramientas (en la sección de extensiones del navegador), cambiando de Turn Off a BurpSuite Commu:
En BurpSuite, poner el intercept en on para interceptar paquetes:
En la máquina Kali, usar el comando cd para moverse a la carpeta del laboratorio donde se encuentra el archivo docker-composer.yml y ejecutar docker composer con el comando: docker-composer up --build
Prueba de inyección CRLF:
Primero, enviamos una Request que contiene caracteres de control (CRLF) al sistema como sigue: HTTP/1.1\r\nFoo:
baarr\r\r\n\n y codificamos la URL como: %20HTTP/1.1%0d%0aFoo:%20baarr
=> Se puede observar que, al insertar los caracteres CRLF (%0d%0a), el servidor procesa nuestra request sin devolver ningún error o restricción, lo que indica que podemos insertar caracteres CRLF.
Prueba de HTTP Request Smuggling:
A continuación, tenemos una URI como la siguiente:
/categories/1 HTTP/1.1\r\nHost: Localhost\r\n\r\nGET /SMUGGLED, y al codificar la URL obtenemos: /categories/1%20HTTP/1.1%0d%0aHost:%20localhost%0d%0a%0d%0aGET%20/SMUGGLED/
Después de aplicar RewriteRule, se puede ver que la URL se analiza y la request que enviamos, tras pasar por el proxy, se convierte en el siguiente formato:
Se puede observar que, con una sola request enviada, el servidor recibe y devuelve hasta 2 responses: una de GET /categories y otra de GET /SMUGGLED
Explotación de HTTP Request Smuggling:
Supongamos que en el archivo httpd.conf configuramos el Proxy-Server para bloquear el acceso a la página /admin/
Podemos aprovechar HTTP Request Smuggling para evadir el mecanismo de comprobación de apache-proxy con la siguiente request:
Al revisar el log, observamos que conseguimos evadir apache-proxy, la request a /admin se envió correctamente y el backend devolvió el status code 200 para GET /admin
Supongamos que en el archivo admin.php hay una función que ejecuta el comando del sistema nslookup para consultar cualquier dominio, como se muestra a continuación; nuestro objetivo es evadir el mecanismo del proxy y acceder a esta función oculta para enviar una consulta DNS
a cualquier dominio; aquí consultamos a nuestra propia máquina Kali.
Tenemos el código de explotación (archivo CVE-2023-25690.py) y el archivo pre.txt (que contiene la request smuggled que queremos hacer pasar por Proxy-Server para enviar la solicitud al sistema, en este caso a /admin.php). Este código crea un request smuggling con la request que queremos, contenida en el archivo pre.txt, y la envía al servidor. Al mismo tiempo, guarda los resultados de la request y la response en los dos archivos correspondientes: req.txt y res.txt
Al mismo tiempo, en la máquina Kali usamos TCPDUMP para capturar los paquetes DNS en el puerto 53
Se puede observar que nuestra request consiguió pasar el proxy; el proxy cree que es una request válida. Pero en backend-server, la request se analiza incluyendo los caracteres de control, por lo que a partir de una sola request el backend-server la divide en 3 requests: una es GET /categories.php?id=1, la segunda es GET /admin.php?secret=192.168.1.194 y la última es GET /abc
Apéndice
Configuración del archivo DockerFile en la carpeta Backend
Este archivo de configuración especifica que Backend-Server utiliza la imagen PHP 7.4-apache, una imagen que contiene PHP 7.4 junto con el servidor web Apache.
El segundo comando copia todo el contenido de la carpeta src/ a la carpeta /var/www/html. Esta es la carpeta predeterminada que Apache usa para construir el contenido web, también conocida como web root.
El tercer comando usa sed para reemplazar todos los campos 80 por 8080. Esto permite cambiar el puerto predeterminado de Apache en Backend-Server de 80 a 8080.
El último comando se ejecuta cuando se inicia el contenedor; es el comando que utiliza apache para ejecutar Apache Web Server.
Configuración del archivo DockerFile en la carpeta Frontend
Este archivo copia el archivo httpd.conf de la carpeta Frontend al archivo /tmp/httd.conf y, finalmente, coloca el contenido de ese httpd.conf en el archivo /usr/local/apache2/conf/httpd.conf.
El archivo httpd.conf es el archivo de configuración principal del servidor Apache HTTP; este archivo define los ajustes de configuración y las operaciones del servidor (aquí, Proxy-Server).
El archivo httpd.conf normalmente se instala en la ruta /usr/local/apache2/conf/httpd.conf, por lo que tenemos que colocar el contenido en esa ruta; y creamos un archivo httpd.conf en la carpeta Frontend para poder configurar Apache de forma más flexible (sin necesidad de hacer cd hasta esa ruta para reescribir el archivo httpd.conf).
Configuración del archivo docker-compose.yml:
Aquí se definen los services, network, etc. necesarios para ejecutar la aplicación.
Aquí declaramos 2 services principales: apache-proxy y backend-server:
Apache-Proxy: se construye a partir del archivo ./frontend/DockerFile y su network es backend-network (bridge). Además, tiene la configuración depends_on: backend-server para especificar que Apache-Proxy solo se inicia después de que Backend-Server haya terminado de iniciarse. Por último, ports: "80:80" especifica el port forward: el tráfico que llega al puerto 80 del host se reenvía al puerto 80 del contenedor.
Backend-Server: se construye a partir del archivo ./backend/DockerFile, con el network backend-network, junto con Proxy, para que puedan comunicarse entre sí. La configuración expose abre el puerto 8080 para que Apache-Proxy reenvíe el tráfico a Backend-Server a través de este puerto. Por último, se incluyen algunas características de seguridad, como no permitir que el usuario obtenga nuevos privilegios (añadir, modificar o eliminar archivos, agregar privilegios sobre procesos o redes, etc.) y filtrar las system calls realizadas por un programa.
Configuración del archivo httpd.conf
Primero, se configura el almacenamiento de logs en dos rutas: /use/local/apache2/logs/error.log y /use/local/apache2/logs/access.log.
A continuación, se cargan los módulos necesarios para poder aplicar Rewrite Rule (regla de reescritura).
Después, se especifica DocumentRoot; este es el parámetro en el archivo de configuración de Apache que permite determinar dónde se encuentran los archivos de datos del servidor.
Luego, se aplica la regla de reescritura para las rutas /categories/ y /admin/.
Y, por último, se bloquea el envío de requests a /admin/ -> El propósito es hacer el laboratorio para hacer bypass al proxy y acceder a esta página.
Así hemos enviado correctamente la request a /admin.php, a la que el proxy no permitía enviar solicitudes.
=> Al revisar TCPDUMP vemos que TCPDUMP capturó los paquetes DNS enviados -> ejecutamos correctamente la función oculta en /admin.php