php2shell-checker d’OpenAI constitue un bon premier filtre, mais il ne suffit pas à prouver qu’un serveur est sûr. L’outil compare la version de PHP exposée dans les en-têtes HTTP ou renvoyée par php -v avec des seuils de correctifs intégrés. Un en-tête masqué peut donc produire UNKNOWN, tandis qu’un backport fourni par une distribution peut faire passer un serveur corrigé pour vulnérable.
Commencez par comprendre les résultats
Le dépôt officiel d’OpenAI renvoie trois états principaux. Considérez-les comme des indicateurs de triage, pas comme un diagnostic complet de vulnérabilité.
| Résultat | Code de sortie | Ce qu’il indique | Étape suivante |
|---|---|---|---|
OK | 0 | La branche reconnue est au moins à la version minimale corrigée | Vérifier que le processus PHP qui traite le trafic web utilise bien cette version |
VULNERABLE | 1 | La version détectée est antérieure à la version minimale corrigée | Mettre à jour le runtime utilisé par le serveur, redémarrer ses workers, puis relancer les deux vérifications |
UNKNOWN | 3 | Le vérificateur n’a pas pu établir une version ou une réponse reconnue | Inspecter le serveur localement ; ne pas considérer ce résultat comme la preuve d’un correctif |
| Arguments invalides | 2 | La commande elle-même n’était pas valide | Corriger la commande et la relancer |
Ce qu’OpenAI fournit réellement
Le dépôt public php2shell-checker contient un script Node.js, des tests et deux skills Codex : phpcheck-url pour un site accessible, et phpcheck-server pour un serveur auquel vous avez accès. L’outil inventorie les éléments permettant d’identifier la version ; il n’exploite pas la cible et n’analyse pas le code de l’application.
Choisissez le bon mode de vérification
Vérifier une URL publique
Clonez ou téléchargez le dépôt, puis lancez son script Node.js sur un site :
node phpcheck.js "https://example.com"
La vérification distante envoie une requête HTTP HEAD et ne passe à GET que si le serveur renvoie 405 ou 501. Elle lit les en-têtes X-Powered-By et Server, ne suit pas les redirections et n’inspecte pas le corps de la réponse.
Un CDN, un proxy inverse, expose_php=off ou une configuration serveur personnalisée peut supprimer la version de PHP avant que la réponse n’atteigne le vérificateur. Un résultat VULNERABLE impose une mise à jour ; en revanche, l’absence d’en-tête doit être complétée par des éléments observés côté serveur.
Vérifier un binaire PHP local
Sur une machine où PHP est installé, utilisez :
node phpcheck.js --local
Cette commande exécute php -v sur le binaire disponible dans le PATH courant. Elle ne prouve pas que ce même binaire sert votre site : un même hôte peut disposer d’installations distinctes pour le CLI, PHP-FPM, CGI, le module Apache, un conteneur ou une compilation depuis les sources.
Après cette vérification locale, identifiez le runtime réellement relié au serveur web. Dans un déploiement conteneurisé, inspectez le conteneur en cours d’exécution, pas uniquement le tag de son image. Pour un service fourni par un paquet, consultez le pool PHP-FPM ou le module Apache concerné ainsi que le journal des modifications du paquet.
Installer et utiliser les skills Codex
Le README officiel installe les deux skills avec une seule commande Codex :
$skill-installer install both skills from https://github.com/openai/php2shell-checker
Choisissez ensuite l’interface correspondant à votre niveau d’accès :
$phpcheck-url check https://example.com
$phpcheck-server check the PHP version serving my site
Codex reste facultatif. La commande Node.js constitue toujours l’interface directe pour les jobs CI et les hôtes minimalistes. Pour l’automatisation, ajoutez --json : son champ patch_status renvoie ok, vulnerable ou unknown, sans obliger un script à analyser le texte affiché dans le terminal.
Vérifier le vérificateur téléchargé
Le dépôt utilise le test runner intégré à Node :
node --test phpcheck.test.js
La suite teste le CLI avec des serveurs HTTP locaux et utilise un faux exécutable PHP pour les scénarios locaux. D’après le README, elle ne nécessite ni installation réelle de PHP ni accès à un site externe.
Considérez UNKNOWN comme un résultat de diagnostic
Traitez UNKNOWN comme une information incomplète. La cible peut masquer sa version de PHP, utiliser une branche non reconnue, ne pas répondre ou exécuter une préversion plus récente. Aucun de ces cas ne permet d’établir que le correctif est bien présent.
Un utilisateur, @jvr0x, a résumé cette limite ainsi :
« C’est simplement une comparaison de versions avec leurs seuils du 20 octobre ; les en-têtes masqués renvoient donc UNKNOWN. »
La commande distante voit une réponse HTTP, pas le processus qui se trouve derrière le proxy inverse. Lorsqu’un en-tête est masqué, il faut effectuer une vérification côté serveur plutôt que multiplier les sondages sur l’URL.
Après un résultat UNKNOWN, procédez dans cet ordre :
- Exécutez
node phpcheck.js --localsur l’hôte qui sert le site. - Déterminez si la requête atteint PHP-FPM, CGI, Apache
mod_phpou un conteneur. - Consultez le journal des modifications du paquet fourni par le vendeur pour repérer d’éventuels correctifs rétroportés.
- Redémarrez les workers PHP-FPM ou Apache concernés après la mise à jour.
- Vérifiez le chemin réellement utilisé par le trafic web, et pas seulement le binaire
phppar défaut du shell.
Sans accès SSH, le mode URL est peut-être votre seul premier contrôle. Si un hébergeur mutualisé masque l’en-tête de version, il doit confirmer le runtime qui traite les requêtes, la révision du paquet et le statut du redémarrage.
La table des versions ne suffit pas à décider si le correctif est présent
Le vérificateur considère PHP 8.5.12, 8.4.27, 8.3.36 et 8.2.35 comme les versions amont minimales corrigées pour leurs branches respectives. Ses tests officiels confirment que 8.4.26 est VULNERABLE, tandis que 8.4.27 est OK. De son côté, PHP présente 8.5.12, 8.4.27, 8.3.36 et 8.2.35 comme des versions de sécurité.
| Branche | Version amont minimale corrigée | Version précédente classée comme vulnérable |
|---|---|---|
| PHP 8.5 | 8.5.12 | 8.5.11 |
| PHP 8.4 | 8.4.27 | 8.4.26 |
| PHP 8.3 | 8.3.36 | 8.3.35 |
| PHP 8.2 | 8.2.35 | 8.2.34 |
| Situation de déploiement | Pourquoi une simple comparaison de versions peut induire en erreur | Élément à vérifier |
|---|---|---|
En-tête X-Powered-By ou Server masqué | Le vérificateur distant ne peut pas identifier PHP | Inventaire du runtime local |
| Paquet de sécurité Debian ou Ubuntu | Le vendeur peut avoir rétroporté le correctif tout en conservant une ancienne version amont | Avis de sécurité du vendeur et journal des modifications du paquet |
| PHP-FPM et CLI sur un même hôte | php -v peut décrire le CLI, pas le worker HTTP | Configuration du serveur web et de FPM |
| Conteneur mis en cache ou digest épinglé | Le tag du registre peut être à jour alors que le conteneur en cours d’exécution est ancien | ID de l’image du conteneur actif et version utilisée |
| Workers Apache ou FPM non redémarrés | Les fichiers corrigés peuvent être présents sur le disque alors que d’anciens workers sont encore actifs | Heure de démarrage des processus et vérification après redémarrage |
| Branche non prise en charge ou préversion | Le vérificateur peut ne pas reconnaître l’état du correctif fourni par le vendeur | Avis de sécurité PHP ou du vendeur |
La section consacrée aux limites du dépôt précise que l’outil part du principe que les versions stables ultérieures d’une branche listée contiennent le correctif, sans pouvoir le vérifier indépendamment. Une distribution peut appliquer un correctif de sécurité rétroporté sans modifier le numéro de version amont ; son journal des modifications constitue alors un élément plus fiable que le seul numéro affiché.
Mettre à jour WordPress, Drupal, Laravel ou une autre application PHP ne corrige pas le moteur PHP. Mettez à jour le paquet ou l’image du runtime, redémarrez les workers, puis vérifiez le processus qui accepte les requêtes web.
FAQ
Quel résultat permet de clôturer un ticket de remédiation en production ?
Aucun résultat ne devrait suffire à lui seul pour clôturer un ticket. Associez OK à la vérification du SAPI utilisé, du statut des backports du vendeur, de l’ensemble des vhosts ou conteneurs concernés, ainsi qu’à la confirmation du redémarrage des workers après la mise à jour.