En octobre 2026, une faille baptisée PHP2Shell a rappelé une vérité que l'on préfère oublier : la sécurité d'une application ne vaut jamais plus que celle du moteur qui l'exécute. PHP fait tourner une large part du web, et un défaut dans son cœur touche en même temps des milliers de serveurs qui n'ont pourtant aucun bug dans leur propre code. Cet article décrit la famille PHP2Shell, du détournement d'un paramètre jusqu'à la corruption mémoire, et montre comment chaque technique s'exploite puis se referme.
Une faille d'interpréteur, pas une faille d'application
La plupart des vulnérabilités web vivent dans le code applicatif : un contrôle d'accès oublié, une requête mal paramétrée, une entrée non validée. PHP2Shell est d'une autre nature. La faiblesse est dans l'interpréteur PHP lui-même, celui qui exécute le code de l'application. Conséquence directe : une application au code irréprochable reste vulnérable si elle tourne sur une version ou un mode d'exécution atteint.
La famille se lit sur une pente de difficulté croissante. On commence par une option de ligne de commande détournée, on passe par une fonctionnalité anodine abusée, et on finit par la mémoire du processus. Trois profondeurs, un seul moteur.
1. Injection d'arguments php-cgi (CVE-2012-1823, puis CVE-2024-4577)
Quand PHP est servi en mode CGI, le serveur web transmet la query-string à l'exécutable php-cgi. La règle CGI (RFC 3875) est fatale : une query-string qui ne contient aucun signe égal est traitée comme une requête indexée et découpée en arguments de ligne de commande. Le réseau parle alors directement à l'analyseur d'options de l'interpréteur.
On prouve l'injection en demandant la divulgation du source, puis on passe à l'exécution :
# 1. Dump du source : la query atteint les arguments de php-cgi
curl 'http://cible/index.php?-s'
# 2. Exécution : on force l'inclusion du corps de requête comme code PHP
curl 'http://cible/index.php?-d+allow_url_include%3don+-d+auto_prepend_file%3dphp://input' \
--data '<?php system("id; cat /opt/flag.txt"); ?>'Le %3d encode le signe égal interne aux directives : s'il apparaissait nu dans la query-string, celle-ci ne serait plus traitée comme indexée et l'exploit échouerait en silence.
CVE-2012-1823 a été remontée en 2012 par l'équipe Eindbazen. Douze ans plus tard, en juin 2024, Orange Tsai de DEVCORE publie CVE-2024-4577 : la même classe d'injection, cette fois sur php-cgi sous Windows, par un contournement du correctif via une conversion de jeu de caractères Best-Fit. Exploitation de masse en quelques jours, rançongiciel TellYouThePass en tête. La parade racine n'a pas changé : on ne sert jamais php-cgi en CGI exposé, on passe par php-fpm, et on tient l'interpréteur à jour.
2. Inclusion de fichier local via session.upload_progress (CWE-98)
L'étape intermédiaire ne touche pas la mémoire : elle chaîne deux faiblesses faibles pour atteindre l'exécution, sans jamais téléverser de webshell. Une visionneuse permissive inclut un fichier par son nom sans validation (inclusion de fichier local), et le suivi de téléversement de PHP écrit dans le fichier de session une valeur que l'on contrôle.
Le geste tient en deux temps. On empoisonne d'abord le fichier de session en nommant un champ PHP_SESSION_UPLOAD_PROGRESS, dont la valeur, ici le nom du fichier téléversé, est écrite telle quelle côté serveur. On inclut ensuite ce fichier de session par la LFI, avec une traversée de chemin, et on exécute :
curl -s "http://cible/viewer.php?doc=../../../../var/lib/php/sessions/sess_SID&0=cat%20/opt/flag.txt"La cause racine n'est pas session.upload_progress, c'est l'inclusion pilotée par le client. On ne laisse jamais l'utilisateur désigner le fichier que le serveur exécute : on résout la cible de l'inclusion depuis une liste blanche côté serveur. Le client choisit une clé, pas un chemin. Interdire les ../ ou désactiver allow_url_include ne suffit pas : le fichier de session est un chemin local parfaitement légitime.
3. Use-after-free cross-requête, le vrai PHP2Shell (CVE-2026-109618)
Le climax est une corruption mémoire du cœur PHP (CVE-2026-109618 et CVE-2026-109619), un use-after-free sur PHP 8.4.26, corrigé en 8.4.27. Un pointeur d'une requête est réutilisé par une requête ultérieure sur le même worker : la zone a été libérée, mais elle est relue après avoir été réallouée avec des octets choisis par l'attaquant.
L'exploitation suit trois temps. Un infoleak d'abord : une requête malformée laisse fuiter une adresse de tas lisible via le cookie de session, ce qui vainc l'ASLR. Un façonnage du tas ensuite, pour que la zone libérée soit reprise par une structure forgée. Un détournement de flot enfin : on reconstruit une fausse structure du moteur dont un pointeur de fonction, appelé au nettoyage de session, vise system. La sortie de la commande est écrite dans la racine web inscriptible, puis récupérée par une requête GET, car la sortie réseau directe est coupée.
La leçon de défense est sèche : contre un use-after-free, les mitigations ralentissent mais ne corrigent pas. Une seule fuite d'adresse les annule. Le vrai correctif est mémoire, livré par la mise à jour de l'interpréteur.
Se protéger, en synthèse
- Servir PHP par php-fpm, jamais
php-cgiexposé en CGI. - Ne jamais laisser le client désigner un fichier inclus : liste blanche côté serveur, le client choisit une clé.
- Tenir l'interpréteur PHP à jour, 8.4.27 ou supérieur pour la famille d'octobre 2026.
- Désactiver
session.upload_progresssi la fonctionnalité n'est pas utilisée, garder le nettoyage actif. - Se souvenir qu'un pare-feu applicatif filtre des motifs connus, il ne supprime pas la primitive sous-jacente.
Pour chaque vulnérabilité, la même discipline revient : on supprime la cause, on ne tamise pas le symptôme. C'est exactement le raisonnement qu'un auditeur applicatif doit tenir face à un composant partagé.
S'entraîner sur le lab PHP → shell
Lire une exploitation ne remplace pas de l'avoir faite. Le parcours gratuit PHP → shell de Zeroday Cyber Academy déploie trois cibles réelles à la demande, une par technique de cette page : l'injection d'arguments php-cgi en entrée, la LFI via session.upload_progress en intermédiaire, puis l'use-after-free d'octobre 2026 en capstone, solveur de référence fourni. Chaque cible porte une fiche qui détaille le pourquoi du comment, l'exploitation pas à pas et la remédiation avant/après. On apprend à exploiter pour apprendre à défendre : l'accès se demande par email sur la page du lab.



