{{ sec.n }}. {{ sec.h }}
{{ sec.p }}
{{ sec.code }}
{{ arFaqT }}
{{ q.q }}
{{ q.a }}
Hier, PHP a publié en urgence les versions 8.5.12, 8.4.27, 8.3.36 et 8.2.35. Deux CVE notées 9.2, dans le moteur PHP. Pas dans WordPress, pas dans un plugin : dans l’interpréteur. Un simple Hello World sur une version touchée suffit. Les détails ont fuité la veille et l’exploitation a déjà commencé. Voilà ce que j’en retiens, et ce que je ferais aujourd’hui.
oct. 2026 · 11 min de lecture · PHP · Par Gerard Capdevila, Incursor Security.
Wiz Research a trouvé le premier bug le 19 août, en s’aidant de modèles d’IA, et l’a signalé à PHP le 24. La publication coordonnée était calée au 21 octobre, 14 h UTC. Le 20, les détails ont fuité avec un outil de preuve de concept baptisé PHP2Shell. watchTowr a confirmé dans la foulée avoir reproduit les deux failles, et voit depuis de vraies tentatives d’exploitation. Le NCSC britannique conseille même de couper les serveurs qu’on ne peut pas mettre à jour tout de suite.
Les quatre bugs décrits ont la même racine. Quand une requête meurt sur une erreur fatale, typiquement un dépassement de mémoire, PHP détruit le tas de la requête mais oublie de remettre à zéro certains pointeurs globaux. Le worker, lui, continue de tourner. La requête suivante traitée par ce worker réutilise ces pointeurs, qui visent maintenant une mémoire que l’attaquant a pu remplir.
C’est un use after free entre deux requêtes. Et c’est pour ça que la qualité de votre code ne change rien.
PHP lit les requêtes multipart très tôt, avant l’initialisation normale des modules. Le suivi de progression d’upload peut déjà créer un identifiant de session à ce stade. Si la requête plante sur un manque de mémoire, le pointeur PS(id) reste en place et vise une zone libérée.
La requête multipart suivante sur le même worker passe par le nettoyage de l’upload. PHP prend ce pointeur pour une chaîne valide et renvoie son contenu dans le cookie PHPSESSID. Vous récupérez un morceau de mémoire du worker, avec potentiellement des mots de passe, des jetons ou des clés d’API venant d’autres requêtes. Sans RCE, sans compte.
Premier chemin : le désérialiseur des sessions, utilisé pendant le suivi d’upload, laisse son état global publié après le crash. Avec la fuite mémoire pour retrouver les adresses, Wiz obtient une exécution de code sans compte sur WordPress, Drupal et Joomla, dans leurs dernières images Docker.
Deuxième chemin : PHP garde la trace de la dernière erreur fatale dans EG(last_fatal_error_backtrace). Après un crash mémoire, ce pointeur vise la mémoire de la requête précédente. Démontré sur Drupal.
Troisième chemin : OPcache. Une allocation qui échoue au mauvais moment laisse des index de mémoire partagée incohérents entre workers, d’où une confusion de types. Démontré sur WordPress.
CVE-2026-109618, surnommée « rawkey », vise la table de hachage du Zend Engine. L’attaquant envoie un POST application/x-www-form-urlencoded de plusieurs mégaoctets, avec un nom de champ énorme. PHP manque de mémoire pendant qu’il remplit $_POST, en plein milieu de l’insertion d’une clé. Le bucket reste à moitié initialisé, et le nettoyage de fin de requête le traite comme s’il était valide.
CVE-2026-109619 regroupe les cas d’état global périmé décrits plus haut : le désérialiseur des sessions, le backtrace de la dernière erreur fatale et OPcache. Dans les deux familles, le déclencheur est le même : une erreur mémoire au mauvais moment, et un PHP qui fait confiance à ce qui reste.
Il repère d’abord les cibles. Un en tête X-Powered-By, un cookie PHPSESSID ou une URL en .php suffisent. Il n’a besoin ni de compte ni de formulaire d’upload : n’importe quelle URL servie par PHP fait l’affaire.
Ensuite, il fait fuiter la mémoire. Quelques requêtes multipart qui plantent exprès, puis il lit le cookie PHPSESSID renvoyé. Il y récupère des adresses mémoire, ce qui fait tomber l’ASLR, et parfois directement des mots de passe ou des jetons d’autres visiteurs.
Il adapte alors l’exploit au binaire. Les PoC publics embarquent les décalages entre fonctions pour les builds courants, comme Debian Bookworm, Ubuntu Noble ou Ubuntu Jammy. Sur une image Docker officielle, c’est presque du copier coller.
Vient l’exécution de code. D’après Datadog, l’exploit de rawkey se joue en trois temps : atteindre l’insertion interrompue, remplir le bucket inachevé avec des données contrôlées, puis transformer le nettoyage de la requête en appel à system(). Sur mod_php, tout se passe avant que votre code ne démarre.
Enfin, il s’installe : webshell, lecture de wp-config.php ou du .env, identifiants de base de données, et sur un site e-commerce, un skimmer dans le tunnel de paiement. Sansec signale des RCE confirmées sur Magento, Shopware et WooCommerce.
Le calendrier est serré. Le réseau de honeypots MadPot d’Amazon a vu une tentative dès le 17 octobre, quatre jours avant la publication. Cloudflare a vu des attaques le 21 à 7 h 43 UTC, avant même la sortie du patch.
Tout ce qui sert des requêtes web en PHP : PHP FPM, mod_php sous Apache, php cgi, FrankenPHP, LiteSpeed. Le pire cas reste mod_php, parce que l’attaque peut réussir avant même que votre code s’exécute. Sur un hébergement mutualisé, ce n’est pas vous qui patchez : demandez à votre hébergeur quand c’est fait.
Encore en PHP 7.4, 8.0 ou 8.1 ? Il n’y a pas de version officielle corrigée. Il vous faut un backport de votre distribution ou une migration. En dessous, la réponse honnête est de sortir ces serveurs d’Internet.
Vérifiez la version réellement exécutée, pas celle du paquet. Un php -v en ligne de commande ne dit rien du PHP qui sert vos pages : regardez chaque SAPI, chaque pool FPM, chaque image Docker et chaque image de base.
Mettez à jour vers 8.5.12, 8.4.27, 8.3.36 ou 8.2.35, puis redémarrez tous les workers : un reload partiel peut laisser tourner l’ancien code. Côté conteneurs, reconstruisez l’image et redéployez, au lieu de patcher un conteneur en place. En 7.4, 8.0 ou 8.1, il reste les backports publiés dans le code source de PHP ou le paquet corrigé de votre distribution. Sinon, c’est la migration.
Si vous ne pouvez pas patcher tout de suite, réduisez le risque sans vous croire protégé. Datadog recommande de forcer memory_limit=-1 au niveau administrateur, avec des limites de taille de requête au reverse proxy et une limite mémoire sur le conteneur. Limitez aussi la taille des corps décodés, y compris ceux envoyés sans Content-Length. session.upload_progress.enabled = 0, et fatal_error_backtraces = 0 en PHP 8.5, retirent les chemins connus. Les règles WAF publiées font gagner quelques heures.
Après le patch, n’oubliez pas la fuite mémoire. Si le serveur était exposé depuis le 17 octobre, partez du principe que ce qui passait par ses workers a pu être lu. Faites tourner les clés d’API, les mots de passe de base de données et les secrets de session, et invalidez les sessions actives. Sur mod_php, la clé TLS vit dans le même processus qu’Apache : renouvelez aussi le certificat.
L’exploitation se passe sous l’application, donc vos logs applicatifs ne diront presque rien. Côté serveur, je regarde trois choses : des requêtes multipart inhabituelles suivies d’erreurs memory limit ou de rafales de 500, des cookies PHPSESSID énormes ou malformés dans les réponses, et des workers PHP qui redémarrent sans raison.
Ensuite, comme après toute RCE, on cherche les webshells, les tâches cron ajoutées et les comptes créés par l’utilisateur qui fait tourner PHP.
Le code fautif dormait là depuis plus de dix ans. Ce qui manquait, c’était le temps pour transformer ces bugs en exploit fiable, version par version. Selon Wiz, avec des modèles d’IA, un seul chercheur a fait en une semaine ce qui aurait pris des mois à une équipe. Les attaquants ont les mêmes outils. Une faille jugée trop compliquée à exploiter n’est plus une raison de la laisser dormir dans le backlog.
Non. La faille est dans PHP, pas dans WordPress. Un WordPress à jour sur un PHP non corrigé reste vulnérable.
Ça retire un chemin connu, pas les autres. PHP et watchTowr sont clairs : aucune modification du php.ini ne suffit. Faites la mise à jour.
Cloudflare, Fastly, Akamai et d’autres ont publié des règles. Elles vous font gagner quelques heures, elles ne remplacent pas le patch.
Oui. On regarde la version réellement exposée, la configuration et les traces d’exploitation, et on vous dit quoi corriger en premier.
{{ sec.p }}
{{ sec.code }}
{{ q.a }}