mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
98 lines
6.7 KiB
Markdown
98 lines
6.7 KiB
Markdown
# LFI2RCE via Eternal waiting
|
|
|
|
{{#include ../../banners/hacktricks-training.md}}
|
|
|
|
## Información Básica
|
|
|
|
Por defecto, cuando se sube un archivo a PHP (incluso si no lo está esperando), 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 subido, obtendrás RCE**.
|
|
|
|
Ten en cuenta que por defecto **PHP solo permite subir 20 archivos en una sola solicitud** (configurado en `/etc/php/<version>/apache2/php.ini`):
|
|
```
|
|
; Maximum number of files that can be uploaded via a single request
|
|
max_file_uploads = 20
|
|
```
|
|
También, el **número de nombres de archivos potenciales es 62\*62\*62\*62\*62\*62 = 56800235584**
|
|
|
|
### Otras técnicas
|
|
|
|
Otras técnicas se basan en atacar protocolos de PHP (no podrás hacerlo si solo controlas la última parte de la ruta), divulgar la ruta del archivo, abusar de archivos esperados, o **hacer que PHP sufra un fallo de segmentación para que los archivos temporales subidos no sean eliminados**.\
|
|
Esta técnica es **muy similar a la anterior pero sin necesidad de encontrar un zero day**.
|
|
|
|
### Técnica de espera eterna
|
|
|
|
En esta técnica **solo necesitamos controlar una ruta relativa**. Si logramos subir archivos y hacer que el **LFI nunca termine**, tendremos "suficiente tiempo" para **realizar un ataque de fuerza bruta a los archivos subidos** y **encontrar** cualquiera de los que se hayan subido.
|
|
|
|
**Pros de esta técnica**:
|
|
|
|
- Solo necesitas controlar una ruta relativa dentro de un include
|
|
- No requiere nginx ni un nivel inesperado de acceso a archivos de registro
|
|
- No requiere un 0 day para causar un fallo de segmentación
|
|
- No requiere divulgación de ruta
|
|
|
|
Los **principales problemas** de esta técnica son:
|
|
|
|
- Necesita que un archivo(s) específico(s) esté(n) presente(s) (puede haber más)
|
|
- La **cantidad insana** de nombres de archivos potenciales: **56800235584**
|
|
- Si el servidor **no está usando dígitos**, la cantidad total potencial es: **19770609664**
|
|
- Por defecto, **solo se pueden subir 20 archivos** en una **solicitud única**.
|
|
- El **número máximo de trabajadores paralelos** del servidor utilizado.
|
|
- Este límite junto con los anteriores puede hacer que este ataque dure demasiado
|
|
- **Tiempo de espera para una solicitud PHP**. Idealmente, esto debería ser eterno o debería matar el proceso PHP sin eliminar los archivos temporales subidos, si no, esto también será un problema
|
|
|
|
Entonces, ¿cómo puedes **hacer que un include de PHP nunca termine**? Simplemente incluyendo el archivo **`/sys/kernel/security/apparmor/revision`** (**no disponible en contenedores Docker** desafortunadamente...).
|
|
|
|
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 nuestro webshell.
|
|
- Luego, usar la **última conexión** para **fuerza bruta** de archivos potenciales.
|
|
- A una velocidad de **10 solicitudes/s** los tiempos son:
|
|
- 56800235584 / 2980 / 10 / 3600 \~= **530 horas** (50% de probabilidad en 265h)
|
|
- (sin dígitos) 19770609664 / 2980 / 10 / 3600 \~= 185h (50% de probabilidad en 93h)
|
|
|
|
> [!WARNING]
|
|
> ¡Ten en cuenta que en el ejemplo anterior estamos **completamente DoSing a otros clientes**!
|
|
|
|
Si el servidor Apache se mejora y pudiéramos abusar de **4000 conexiones** (a medio camino 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á usando** **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/<php-version>/fpm/pool.d/www.conf`**.\
|
|
Este parámetro indica la cantidad máxima de segundos **cuando** **la solicitud a PHP debe terminar** (infinito por defecto, pero **30s si el parámetro está descomentado**). Cuando una solicitud está siendo procesada por PHP el número de segundos indicado, es **terminada**. Esto significa que, si la solicitud estaba subiendo archivos temporales, porque el **procesamiento de PHP fue detenido**, esos **archivos no se van a eliminar**. Por lo tanto, si puedes hacer que una solicitud dure ese tiempo, puedes **generar miles de archivos temporales** que no serán eliminados, lo que **acelerará el proceso de encontrarlos** y reduce la probabilidad de un DoS a la plataforma al consumir todas las conexiones.
|
|
|
|
Entonces, para **evitar DoS** supongamos que un **atacante estará usando solo 100 conexiones** al mismo tiempo y el tiempo máximo de procesamiento por **php-fmp** (`request_terminate_timeout`**)** es **30s**. Por lo tanto, el número 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 una **búsqueda de fuerza bruta**. 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 medio de EC2:
|
|
|
|
<figure><img src="../../images/image (240).png" alt=""><figcaption></figcaption></figure>
|
|
|
|
> [!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.
|
|
|
|
## Nginx
|
|
|
|
Parece que por defecto Nginx soporta **512 conexiones paralelas** al mismo tiempo (y este número se puede mejorar).
|
|
|
|
{{#include ../../banners/hacktricks-training.md}}
|