# LFI2RCE a través de Eternal waiting
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥 * ¿Trabajas en una **empresa de ciberseguridad**? ¿Quieres ver tu **empresa anunciada en HackTricks**? ¿O quieres tener acceso a la **última versión de PEASS o descargar HackTricks en PDF**? ¡Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)! * Descubre [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nuestra colección exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family) * Obtén el [**swag oficial de PEASS y HackTricks**](https://peass.creator-spring.com) * **Únete al** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **sígueme** en **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.** * **Comparte tus trucos de hacking enviando PRs al** [**repositorio de hacktricks**](https://github.com/carlospolop/hacktricks) **y al** [**repositorio de hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
## Información básica Por defecto, cuando se carga un archivo en PHP (incluso si no se espera), se 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 local de archivos, **si logras incluir ese archivo cargado, obtendrás RCE**. Tenga en cuenta que por defecto, **PHP solo permite cargar 20 archivos en una sola solicitud** (establecido en `/etc/php//apache2/php.ini`): ``` ; Maximum number of files that can be uploaded via a single request max_file_uploads = 20 ``` También existen otras técnicas que se basan en atacar los protocolos de PHP (no podrás hacerlo si solo controlas la última parte de la ruta), revelar la ruta del archivo, abusar de los archivos esperados o **hacer que PHP sufra una falla de segmentación para que los archivos temporales cargados 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 cargar archivos y hacer que el **LFI nunca termine**, tendremos "suficiente tiempo" para **realizar un ataque de fuerza bruta a los archivos cargados** y **encontrar** cualquiera de los archivos cargados. **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 los archivos de registro * No requiere un zero day para causar una falla de segmentación * No requiere una revelación de ruta Los **principales problemas** de esta técnica son: * Necesita que un archivo específico (pueden haber más) esté presente * La **enorme** cantidad de nombres de archivo potenciales: **56800235584** * Si el servidor **no está usando dígitos**, la cantidad total potencial es: **19770609664** * Por defecto, solo se pueden cargar **20 archivos** en una **solicitud única**. * 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 * **Tiempo de espera para una solicitud de PHP**. Idealmente, esto debería ser eterno o debería matar el proceso de PHP sin eliminar los archivos cargados temporalmente. De lo contrario, esto también será un problema. 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**). Pruébalo 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 **brute-force** archivos potenciales. * 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 DoS a otros clientes**! {% endhint %} Si el servidor Apache se mejora y pudiéramos abusar de **4000 conexiones** (a 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á 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//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 no está comentado**). Cuando una solicitud está siendo procesada por PHP durante el número indicado de segundos, es **eliminada**. Esto significa que si la solicitud estaba cargando archivos temporales, porque el **procesamiento de php se detuvo**, 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 se eliminarán, lo que **acelerará el proceso de encontrarlos** y reduce la probabilidad de un DoS en la plataforma al consumir todas las conexiones. Entonces, para **evitar DoS** supongamos que un **atacante usará solo 100 conexiones** al mismo tiempo y el tiempo máximo de procesamiento de php 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 de **25min**). Luego, el atacante podría usar esas **100 conexiones** para realizar una **búsqueda de fuerza bruta**. Suponiendo una velocidad de 300 solicitudes/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:
{% hint style="warning" %} Ten en cuenta que para activar el tiempo de espera sería **suficiente con 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).