hacktricks/pentesting-web/file-inclusion/lfi2rce-via-eternal-waiting.md

102 lines
7.4 KiB
Markdown

# LFI2RCE a través de la espera eterna
<details>
<summary><strong>Aprende hacking en AWS de cero a héroe con</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (Experto en Equipos Rojos de AWS de HackTricks)</strong></a><strong>!</strong></summary>
Otras formas de apoyar a HackTricks:
* Si deseas ver tu **empresa anunciada en HackTricks** o **descargar HackTricks en PDF** Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)!
* Obtén el [**swag oficial de PEASS & HackTricks**](https://peass.creator-spring.com)
* Descubre [**La Familia PEASS**](https://opensea.io/collection/the-peass-family), nuestra colección exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
* **Únete al** 💬 [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **síguenos** en **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
* **Comparte tus trucos de hacking enviando PRs a los** [**HackTricks**](https://github.com/carlospolop/hacktricks) y [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositorios de github.
</details>
## Información Básica
Por defecto, cuando se carga un archivo en PHP (incluso si no se espera), generará un archivo temporal en `/tmp` con un nombre como **`php[a-zA-Z0-9]{6}`**, aunque he visto algunas imágenes de docker donde los archivos generados no contienen dígitos.
En una inclusión de archivo local, **si logras incluir ese archivo cargado, obtendrás RCE**.
Ten en cuenta que por defecto **PHP solo permite cargar 20 archivos en una única solicitud** (configurado en `/etc/php/<versión>/apache2/php.ini`):
```
; Maximum number of files that can be uploaded via a single request
max_file_uploads = 20
```
### Técnica de espera eterna
En esta técnica **solo necesitamos controlar una ruta relativa**. Si logramos cargar archivos y hacer que la **LFI nunca termine**, tendremos "suficiente tiempo" para **realizar fuerza bruta en los archivos cargados** y **encontrar** cualquiera de los que se hayan subido.
**Ventajas de esta técnica**:
- Solo necesitas controlar una ruta relativa dentro de una inclusión
- No requiere nginx ni un nivel inesperado de acceso a archivos de registro
- No requiere un zero day para causar una falla de segmentación
- No requiere una divulgación de ruta
Los **principales problemas** de esta técnica son:
- Necesidad de que un archivo específico (o archivos) esté presente (puede haber más)
- La **enorme** cantidad de nombres de archivo potenciales: **56800235584**
- Si el servidor **no está utilizando dígitos**, la cantidad total potencial es: **19770609664**
- Por defecto, **solo se pueden cargar 20 archivos** en una **sola solicitud**.
- El **número máximo de trabajadores en paralelo** del servidor utilizado.
- Esta limitación junto con las anteriores puede hacer que este ataque dure demasiado
- **Tiempo de espera para una solicitud de PHP**. Idealmente, esto debería ser eterno o debería finalizar el proceso de PHP sin eliminar los archivos temporales cargados; de lo contrario, también será un dolor
Entonces, ¿cómo puedes **hacer que una inclusión de PHP nunca termine**? Simplemente incluyendo el archivo **`/sys/kernel/security/apparmor/revision`** (**desafortunadamente no disponible en contenedores Docker**).
Inténtalo simplemente llamando:
```bash
php -a # open php cli
include("/sys/kernel/security/apparmor/revision");
```
## Apache2
Por defecto, Apache soporta **150 conexiones concurrentes**, siguiendo [https://ubiq.co/tech-blog/increase-max-connections-apache/](https://ubiq.co/tech-blog/increase-max-connections-apache/) es posible aumentar este número hasta 8000. Sigue esto para usar PHP con ese módulo: [https://www.digitalocean.com/community/tutorials/how-to-configure-apache-http-with-mpm-event-and-php-fpm-on-ubuntu-18-04](https://www.digitalocean.com/community/tutorials/how-to-configure-apache-http-with-mpm-event-and-php-fpm-on-ubuntu-18-04).
Por defecto, (como puedo ver en mis pruebas), un **proceso PHP puede durar eternamente**.
Hagamos algunos cálculos:
* Podemos usar **149 conexiones** para generar **149 \* 20 = 2980 archivos temporales** con nuestra webshell.
* Luego, usar la **última conexión** para **bruteforce** posibles archivos.
* A una velocidad de **10 solicitudes/s** los tiempos son:
* 56800235584 / 2980 / 10 / 3600 \~= **530 horas** (50% de probabilidad en 265h)
* (sin decimales) 19770609664 / 2980 / 10 / 3600 \~= 185h (50% de probabilidad en 93h)
{% hint style="warning" %}
¡Ten en cuenta que en el ejemplo anterior estamos **haciendo un DoS completo a otros clientes**!
{% endhint %}
Si el servidor Apache se mejora y pudiéramos abusar de **4000 conexiones** (la mitad del número máximo). Podríamos crear `3999*20 = 79980` **archivos** y el **número** se reduciría a alrededor de **19.7h** o **6.9h** (10h, 3.5h 50% de probabilidad).
## PHP-FMP
Si en lugar de usar el módulo php regular para apache para ejecutar scripts PHP la **página web está utilizando** **PHP-FMP** (esto mejora la eficiencia de la página web, por lo que es común encontrarlo), hay algo más que se puede hacer para mejorar la técnica.
PHP-FMP permite **configurar** el **parámetro** **`request_terminate_timeout`** en **`/etc/php/<versión-php>/fpm/pool.d/www.conf`**.\
Este parámetro indica la cantidad máxima de segundos **cuando** **la solicitud a PHP debe terminar** (infinito de forma predeterminada, pero **30s si el parámetro está descomentado**). Cuando una solicitud está siendo procesada por PHP durante el número indicado de segundos, es **eliminada**. Esto significa que si la solicitud estaba subiendo archivos temporales, porque el **procesamiento de php se detuvo**, esos **archivos no se eliminarán**. Por lo tanto, si puedes hacer que una solicitud dure ese tiempo, puedes **generar miles de archivos temporales** que no se eliminarán, lo que **acelerará el proceso de encontrarlos** y reducirá la probabilidad de un DoS a la plataforma al consumir todas las conexiones.
Entonces, para **evitar un DoS** supongamos que un **atacante solo usará 100 conexiones** al mismo tiempo y el tiempo máximo de procesamiento por PHP-FMP (`request_terminate_timeout`**)** es **30s**. Por lo tanto, la cantidad de **archivos temporales** que se pueden generar **por segundo** es `100*20/30 = 66.67`.
Luego, para generar **10000 archivos** un atacante necesitaría: **`10000/66.67 = 150s`** (para generar **100000 archivos** el tiempo sería **25min**).
Luego, el atacante podría usar esas **100 conexiones** para realizar un **bruteforce de búsqueda**. Suponiendo una velocidad de 300 req/s, el tiempo necesario para explotar esto es el siguiente:
* 56800235584 / 10000 / 300 / 3600 \~= **5.25 horas** (50% de probabilidad en 2.63h)
* (con 100000 archivos) 56800235584 / 100000 / 300 / 3600 \~= **0.525 horas** (50% de probabilidad en 0.263h)
Sí, es posible generar 100000 archivos temporales en una instancia de tamaño mediano de EC2:
<figure><img src="../../.gitbook/assets/image (240).png" alt=""><figcaption></figcaption></figure>
{% hint style="warning" %}
Ten en cuenta que para activar el tiempo de espera sería **suficiente incluir la página LFI vulnerable**, para que entre en un bucle de inclusión eterno.
{% endhint %}
## Nginx
Parece que por defecto Nginx soporta **512 conexiones paralelas** al mismo tiempo (y este número puede mejorarse).