# LFI2RCE via Eternal waiting {{#include ../../banners/hacktricks-training.md}} ## Informations de base Par défaut, lorsqu'un fichier est téléchargé sur PHP (même s'il ne s'y attend pas), il générera un fichier temporaire dans `/tmp` avec un nom tel que **`php[a-zA-Z0-9]{6}`**, bien que j'aie vu certaines images docker où les fichiers générés ne contiennent pas de chiffres. Dans une inclusion de fichier local, **si vous parvenez à inclure ce fichier téléchargé, vous obtiendrez RCE**. Notez qu'en règle générale, **PHP n'autorise que le téléchargement de 20 fichiers dans une seule requête** (défini dans `/etc/php//apache2/php.ini`): ``` ; Maximum number of files that can be uploaded via a single request max_file_uploads = 20 ``` Aussi, le **nombre de noms de fichiers potentiels est 62\*62\*62\*62\*62\*62 = 56800235584** ### Autres techniques D'autres techniques reposent sur l'attaque des protocoles PHP (vous ne pourrez pas le faire si vous ne contrôlez que la dernière partie du chemin), la divulgation du chemin du fichier, l'abus de fichiers attendus, ou **faire souffrir PHP d'un défaut de segmentation afin que les fichiers temporaires téléchargés ne soient pas supprimés**.\ Cette technique est **très similaire à la dernière mais sans avoir besoin de trouver un zero day**. ### Technique de l'attente éternelle Dans cette technique, **nous n'avons besoin de contrôler qu'un chemin relatif**. Si nous parvenons à télécharger des fichiers et à faire en sorte que **LFI ne se termine jamais**, nous aurons "assez de temps" pour **brute-forcer les fichiers téléchargés** et **trouver** l'un des fichiers téléchargés. **Avantages de cette technique** : - Vous devez juste contrôler un chemin relatif à l'intérieur d'un include - Ne nécessite pas nginx ou un niveau d'accès inattendu aux fichiers journaux - Ne nécessite pas un 0 day pour provoquer un défaut de segmentation - Ne nécessite pas de divulgation de chemin Les **principaux problèmes** de cette technique sont : - Besoin d'un fichier spécifique (il peut y en avoir d'autres) - L'**énorme** quantité de noms de fichiers potentiels : **56800235584** - Si le serveur **n'utilise pas de chiffres**, le nombre total potentiel est : **19770609664** - Par défaut, **seulement 20 fichiers** peuvent être téléchargés dans une **unique requête**. - Le **nombre max de travailleurs parallèles** du serveur utilisé. - Cette limite avec les précédentes peut faire durer cette attaque trop longtemps - **Délai d'attente pour une requête PHP**. Idéalement, cela devrait être éternel ou devrait tuer le processus PHP sans supprimer les fichiers temporaires téléchargés, sinon, cela sera également un problème Alors, comment pouvez-vous **faire en sorte qu'un include PHP ne se termine jamais** ? Juste en incluant le fichier **`/sys/kernel/security/apparmor/revision`** (**non disponible dans les conteneurs Docker** malheureusement...). Essayez-le simplement en appelant : ```bash php -a # open php cli include("/sys/kernel/security/apparmor/revision"); ``` ## Apache2 Par défaut, Apache supporte **150 connexions simultanées**, suivant [https://ubiq.co/tech-blog/increase-max-connections-apache/](https://ubiq.co/tech-blog/increase-max-connections-apache/), il est possible d'augmenter ce nombre jusqu'à 8000. Suivez cela pour utiliser PHP avec ce module : [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). Par défaut, (comme je peux le voir dans mes tests), un **processus PHP peut durer éternellement**. Faisons quelques calculs : - Nous pouvons utiliser **149 connexions** pour générer **149 \* 20 = 2980 fichiers temporaires** avec notre webshell. - Ensuite, utilisez la **dernière connexion** pour **brute-forcer** des fichiers potentiels. - À une vitesse de **10 requêtes/s**, les temps sont : - 56800235584 / 2980 / 10 / 3600 \~= **530 heures** (50% de chance en 265h) - (sans chiffres) 19770609664 / 2980 / 10 / 3600 \~= 185h (50% de chance en 93h) > [!WARNING] > Notez que dans l'exemple précédent, nous **DoSons complètement d'autres clients** ! Si le serveur Apache est amélioré et que nous pouvions abuser de **4000 connexions** (à mi-chemin du nombre maximum). Nous pourrions créer `3999*20 = 79980` **fichiers** et le **nombre** serait **réduit** à environ **19.7h** ou **6.9h** (10h, 3.5h 50% de chance). ## PHP-FMP Si au lieu d'utiliser le mod php régulier pour apache pour exécuter des scripts PHP, la **page web utilise** **PHP-FMP** (ce qui améliore l'efficacité de la page web, donc il est courant de le trouver), il y a autre chose qui peut être fait pour améliorer la technique. PHP-FMP permet de **configurer** le **paramètre** **`request_terminate_timeout`** dans **`/etc/php//fpm/pool.d/www.conf`**.\ Ce paramètre indique le nombre maximum de secondes **quand** **la requête à PHP doit se terminer** (infini par défaut, mais **30s si le param est décommenté**). Lorsqu'une requête est traitée par PHP pendant le nombre de secondes indiqué, elle est **tuée**. Cela signifie que si la requête téléchargeait des fichiers temporaires, parce que le **traitement PHP a été arrêté**, ces **fichiers ne seront pas supprimés**. Par conséquent, si vous pouvez faire durer une requête ce temps, vous pouvez **générer des milliers de fichiers temporaires** qui ne seront pas supprimés, ce qui **accélérera le processus de les trouver** et réduit la probabilité d'un DoS à la plateforme en consommant toutes les connexions. Donc, pour **éviter le DoS**, supposons qu'un **attaquant n'utilisera que 100 connexions** en même temps et que le temps de traitement maximum par **php-fmp** (`request_terminate_timeout`**)** est **30s**. Par conséquent, le nombre de **fichiers temporaires** qui peuvent être générés **par seconde** est `100*20/30 = 66.67`. Ensuite, pour générer **10000 fichiers**, un attaquant aurait besoin de : **`10000/66.67 = 150s`** (pour générer **100000 fichiers**, le temps serait de **25min**). Ensuite, l'attaquant pourrait utiliser ces **100 connexions** pour effectuer une **recherche brute-force**. Supposant une vitesse de 300 req/s, le temps nécessaire pour exploiter cela est le suivant : - 56800235584 / 10000 / 300 / 3600 \~= **5.25 heures** (50% de chance en 2.63h) - (avec 100000 fichiers) 56800235584 / 100000 / 300 / 3600 \~= **0.525 heures** (50% de chance en 0.263h) Oui, il est possible de générer 100000 fichiers temporaires dans une instance EC2 de taille moyenne :
> [!WARNING] > Notez que pour déclencher le timeout, il suffirait d'inclure la page LFI vulnérable, afin qu'elle entre dans une boucle d'inclusion éternelle. ## Nginx Il semble qu'en par défaut, Nginx supporte **512 connexions parallèles** en même temps (et ce nombre peut être amélioré). {{#include ../../banners/hacktricks-training.md}}