Aller au contenu
  • sécurité
  • php
  • infrastructure

PHP2Shell (CVE-2026-109618, CVE-2026-109619) : le guide technique

PHP2Shell (CVE-2026-109618 et CVE-2026-109619) : versions corrigées, configurations exposées, mitigations et commandes pour chercher des traces.
Écran d’ordinateur affichant un terminal sur un bureau ensoleillé, carnet de notes et tasse bleue

PHP2Shell désigne deux failles du moteur PHP, CVE-2026-109618 et CVE-2026-109619, corrigées le 21 octobre 2026 dans PHP 8.5.12, 8.4.27, 8.3.36 et 8.2.35. Toutes deux sont notées 9,2 en CVSS v4 et mènent à une exécution de code à distance sans authentification. Elles ne demandent aucune erreur dans le code applicatif : un WordPress, un PrestaShop ou une application Laravel parfaitement entretenus sont exposés tant que le binaire PHP n'est pas à jour.

Cet article s'adresse aux développeurs, administrateurs système et responsables techniques qui doivent agir sur leur parc. Il couvre ce que l'on sait du mécanisme, les configurations exposées, l'inventaire, les mitigations et leurs limites, puis la recherche de traces d'exploitation.

Le contexte impose d'aller vite : les détails ont fuité le 20 octobre, et Cloudflare a observé des tentatives d'exploitation le 21 octobre à 07 UTC, environ six heures avant la sortie des correctifs.

Prérequis avant de commencer

  • Un accès SSH (ou un accès au panneau d'hébergement) à chaque serveur qui exécute PHP
  • La liste des sites et applications PHP, y compris les outils internes (phpMyAdmin, Roundcube, Nextcloud, intranet)
  • La possibilité de redémarrer PHP-FPM ou Apache, avec une fenêtre de maintenance si nécessaire
  • Un environnement de test pour vérifier la compatibilité des applications avec la nouvelle version
  • L'accès aux journaux d'accès et d'erreurs du serveur web, idéalement depuis le 20 octobre
  • Le nom de la personne qui décide en cas de coupure d'un service exposé

Le mécanisme des deux failles PHP2Shell

L'avis de sécurité publié sur php.net décrit deux problèmes de cycle de vie mémoire dans le traitement des requêtes.

CVE-2026-109618, corruption sur dépassement mémoire. Selon l'avis, une gestion de l'épuisement mémoire peut interrompre PHP alors que des données internes de la requête ne sont que partiellement initialisées ; le nettoyage de fin de requête peut ensuite traiter ces données invalides comme valides. Sansec rattache ce chemin au suivi de progression d'upload de session (session.upload_progress) et le qualifie de use-after-free permettant divulgation mémoire puis exécution de code.

CVE-2026-109619, état global périmé. Un état interne propre à une requête peut survivre après la libération de la mémoire qui le porte. Une requête suivante traitée par le même worker peut utiliser cet état avant que l'initialisation normale ne le réinitialise. Sansec décrit une confusion de type liée à OPcache via les backtraces d'erreurs fatales.

Le point commun, et ce qui rend la faille si large : le déclenchement se fait pendant la lecture de la requête, avant que le code de l'application ne s'exécute. Le vecteur cité par les chercheurs passe par des requêtes multipart/form-data, le format des envois de fichiers.

sequenceDiagram
    participant A as Attaquant
    participant W as Worker PHP (FPM ou mod_php)
    participant App as Application (WordPress, Laravel...)
    A->>W: POST multipart/form-data forgé
    Note over W: Parsing de la requête, état interne partiellement initialisé
    W--xW: Épuisement mémoire ou erreur fatale
    Note over W: Le nettoyage traite des données invalides ou laisse un état périmé
    A->>W: Requête suivante sur le même worker
    W->>W: Réutilisation de l'état libéré, exécution de code
    Note over App: Le code applicatif n'a jamais été atteint

Configurations exposées

L'avis officiel liste « all PHP installations serving web requests, including PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed ». Le risque est jugé le plus élevé pour mod_php, avec un exploit démontré dans lequel une requête non authentifiée déclenche l'attaque avant tout code applicatif. Le CLI seul (scripts cron, workers de file sans serveur HTTP) n'est pas dans le périmètre décrit, mais un serveur où tourne aussi un PHP web l'est.

Branche PHPStatutVersion corrigéeAction
8.5Maintenue8.5.12Mettre à jour
8.4Maintenue8.4.27Mettre à jour
8.3Maintenue8.3.36Mettre à jour
8.2Maintenue (sécurité)8.2.35Mettre à jour
8.1, 8.0, 7.4Fin de vieBackport source minimal uniquementPaquet LTS d'un vendeur, compilation, ou isolement
7.3 et antérieuresFin de vieAucuneIsoler, puis migrer

Le CERT-FR liste aussi les branches 5.x à 8.1 comme affectées dans son alerte CERTFR-2026-ALE-014, et recommande d'isoler les équipements concernés avant de passer sur une version maintenue.

Inventorier les versions réellement exécutées

# Version du CLI (peut différer de celle qui sert le web)
php -v

# Versions des démons FPM installés (Debian/Ubuntu)
ls /usr/sbin/php-fpm* 2>/dev/null && for b in /usr/sbin/php-fpm*; do "$b" -v | head -1; done

# Apache charge-t-il mod_php ?
apachectl -M 2>/dev/null | grep -i php

# Pools FPM actifs et leurs processus
ps -eo pid,ppid,user,cmd | grep -E "php-fpm|php-cgi|lsphp|frankenphp" | grep -v grep

Pour connaître la version vue par le serveur web, la méthode la plus fiable reste une page temporaire qui affiche PHP_VERSION, servie depuis le vhost concerné, puis supprimée aussitôt. Ne laissez jamais traîner un phpinfo() en production.

Le piège qu'on voit régulièrement : le CLI à jour, le web non

Symptôme. L'équipe met à jour PHP, php -v affiche la bonne version, le ticket est fermé. Le site, lui, tourne toujours sur l'ancienne version.

Diagnostic. Le serveur héberge plusieurs versions de PHP côte à côte. Le paquet mis à jour correspond au CLI ou à une autre branche que celle du pool FPM du site, ou PHP-FPM n'a pas été redémarré et les workers en mémoire exécutent toujours l'ancien binaire. Avec mod_php, c'est Apache qu'il faut redémarrer.

Correctif. Vérifier la version depuis le vhost lui-même, redémarrer explicitement chaque service (systemctl restart php8.3-fpm, systemctl restart apache2), et contrôler qu'aucun processus ne date d'avant la mise à jour (ps -o lstart,cmd -C php-fpm8.3). Comptez ce contrôle dans la procédure, pas en option.

Mitigations : ce qu'elles valent vraiment

L'avis php.net le dit sans détour : « There are no complete mitigations, updating is the only safe choice. » Les mesures ci-dessous réduisent la surface d'attaque en attendant la mise à jour, elles ne la remplacent pas.

; CVE-2026-109619 : désactive le suivi de progression d'upload
session.upload_progress.enabled = 0

; CVE-2026-109619, PHP 8.5 uniquement
fatal_error_backtraces = 0

; CVE-2026-109618 : réduit la taille des corps de requête acceptés
; à ajuster selon la taille de vos envois de fichiers (médias, imports)
post_max_size = 2M

L'avis cite aussi memory_limit=-1 et des limites mémoire au niveau du conteneur ou du cgroup contre CVE-2026-109618. Nous déconseillons memory_limit=-1 sur un serveur mutualisé ou à ressources serrées : supprimer la limite par requête ouvre la porte à l'épuisement de toute la machine. Si vous l'appliquez, faites-le avec une limite cgroup en dessous.

Côté réseau, le CERT-FR propose de bloquer au WAF les requêtes Content-Type: multipart. C'est la mesure la plus efficace à court terme, et la plus coûteuse fonctionnellement : tous les envois de fichiers et une partie des formulaires cessent de fonctionner. Sur un back-office qui n'en a pas besoin, c'est un bon compromis.

Les éditeurs de WAF ont publié des règles pour les vecteurs connus. Elles protègent contre les exploits publiés, pas contre une variante.

Chercher des traces d'exploitation

Huntress indiquait ne pas disposer d'indicateurs de compromission confirmés au jour de la publication. Les signaux à surveiller découlent donc du mécanisme et du comportement habituel après une prise de contrôle.

# Shells ou outils réseau lancés par un worker PHP
ps -eo pid,ppid,user,lstart,cmd --forest | grep -B1 -A3 -E "php-fpm|apache2|httpd" | grep -E "sh -c|bash|python|perl|curl|wget|nc "

# Fichiers PHP créés ou modifiés depuis la fuite, dans les racines web
find /var/www -type f -name "*.php" -newermt "2026-10-20" -printf "%TY-%Tm-%Td %TH:%TM %p\n" | sort

# Tâches planifiées ajoutées
for u in $(cut -d: -f1 /etc/passwd); do crontab -l -u "$u" 2>/dev/null | sed "s/^/$u: /"; done
ls -la /etc/cron.d /etc/cron.daily

# POST suivis d'erreurs 500, à croiser avec les erreurs mémoire du journal PHP
grep -E '"POST [^"]+" 500 ' /var/log/nginx/access.log* /var/log/apache2/access.log* 2>/dev/null | tail -50
grep -iE "Allowed memory size|Out of memory" /var/log/php*-fpm.log /var/log/apache2/error.log* 2>/dev/null | tail -50

Sansec ajoute deux signaux propres à cette faille : des cookies PHPSESSID anormalement longs ou malformés dans les réponses, et des redémarrages inexpliqués de workers PHP. Côté application, contrôlez les comptes administrateurs créés récemment dans le CMS.

Si vous trouvez une trace, ne nettoyez pas en place. Isolez le serveur, conservez une copie des fichiers et des journaux, et traitez l'incident comme une compromission complète : rotation de tous les secrets accessibles depuis le serveur (base de données, clés d'API, identifiants SMTP), puis reconstruction à partir d'une source saine.

Pourquoi on ne garderait jamais un PHP en fin de vie exposé, même derrière un WAF

Le WAF achète du temps sur les vecteurs connus. Un PHP 7.4 exposé à Internet derrière un WAF reste un serveur dont la prochaine faille ne sera jamais corrigée par le projet PHP. PHP2Shell n'est pas la dernière.

Pour un parc avec des versions en fin de vie, trois voies sont tenables : un support LTS commercial qui livre des paquets corrigés, une montée de version avec mise en conformité du code, ou une migration de l'application hors de PHP. Garder le statu quo derrière un pare-feu n'en fait pas partie. Pour les sites vitrines et les boutiques, nous avons détaillé l'arbitrage dans notre article patcher, isoler ou migrer.

Checklist d'intervention PHP2Shell

  1. Inventorier chaque serveur et chaque version de PHP réellement servie par le web.
  2. Mettre à jour vers 8.5.12, 8.4.27, 8.3.36 ou 8.2.35, redémarrer FPM ou Apache, vérifier depuis le vhost.
  3. Pour les versions en fin de vie : isoler, appliquer les mesures transitoires, planifier la sortie.
  4. Chercher des traces d'exploitation depuis le 20 octobre.
  5. En cas de trace : isoler, conserver, tourner les secrets, reconstruire.
  6. Documenter la procédure pour la prochaine faille.

L'agence Platane (https://platane.io) intervient auprès de TPE et PME pour l'inventaire et la mise à jour de leurs serveurs PHP, la recherche de traces après PHP2Shell et la migration d'applications vers une architecture sans PHP hébergée en France. Notre démarche est décrite sur la page Migration PHP.

Sources

  1. CERT-FR, alerte CERTFR-2026-ALE-014, 21 octobre 2026
  2. Sansec, « PHP2Shell: Critical PHP RCE »
  3. Tenable, « php2shell : Frequently Asked Questions »
  4. Huntress, « Rapid Response: php2shell »
Revenir au journal

Parlons de ce que vous aimeriez améliorer ou créer.

Une idée précise, un fonctionnement à revoir ou simplement l’envie d’explorer les possibilités : racontez-nous où vous en êtes.

Prenons rendez-vous Un premier échange, sans engagement.

Écrivez-nous.

* Champs obligatoires

Facultatif
Facultatif