php2shell-checker de OpenAI resulta útil como primera comprobación, pero no demuestra por sí solo que un servidor sea seguro. El script compara la versión de PHP expuesta en las cabeceras HTTP o mediante php -v con unos umbrales de parche integrados. Por eso, una cabecera oculta puede devolver UNKNOWN, mientras que un backport de la distribución puede hacer que un servidor corregido parezca vulnerable.
Empieza por entender los estados del resultado
El repositorio oficial de OpenAI contempla tres estados principales. Úsalos como señales para orientar el diagnóstico, no como una evaluación completa de la vulnerabilidad.
| Resultado | Código de salida | Qué indica | Siguiente paso |
|---|---|---|---|
OK | 0 | La rama reconocida está en la versión mínima corregida o por encima de ella | Comprueba que el proceso de PHP que atiende el tráfico web utiliza esa versión |
VULNERABLE | 1 | La versión detectada es anterior a la versión mínima corregida | Actualiza el runtime que atiende las peticiones, reinicia sus workers y repite ambas comprobaciones |
UNKNOWN | 3 | El comprobador no ha podido identificar una versión o respuesta reconocida | Inspecciona el servidor localmente; no lo des por corregido |
| Argumentos no válidos | 2 | El comando utilizado no era válido | Corrige el comando y vuelve a ejecutarlo |
Qué incluye la herramienta de OpenAI
El repositorio público de php2shell-checker incluye un script de Node.js, tests y dos skills de Codex: phpcheck-url, para sitios accesibles desde Internet, y phpcheck-server, para servidores a los que tienes acceso. La herramienta recopila indicios sobre la versión; no explota el objetivo ni analiza el código de la aplicación.
Elige el modo de comprobación adecuado
Comprueba una URL pública
Clona o descarga el repositorio y ejecuta el script de Node.js contra el sitio:
node phpcheck.js "https://example.com"
La comprobación remota envía una petición HTTP HEAD y solo recurre a GET cuando el servidor responde con 405 o 501. Lee las cabeceras X-Powered-By y Server, no sigue redirecciones y tampoco inspecciona el cuerpo de la respuesta.
Una CDN, un proxy inverso, expose_php=off o una configuración personalizada del servidor pueden eliminar la versión de PHP antes de que la respuesta llegue al comprobador. Un resultado VULNERABLE exige aplicar el parche; si falta la cabecera, necesitas pruebas obtenidas en el propio servidor.
Comprueba el binario local de PHP
En un equipo con PHP instalado, ejecuta:
node phpcheck.js --local
El comando ejecuta php -v sobre el binario disponible en el PATH actual. Eso no demuestra que ese mismo binario sirva tu web: un único host puede tener instalaciones independientes para CLI, PHP-FPM, CGI, el módulo de Apache, un contenedor o una compilación desde código fuente.
Después de la comprobación local, identifica el runtime conectado al servidor web. En un despliegue basado en contenedores, inspecciona el contenedor que está ejecutándose y no solo la etiqueta de su imagen. Si utilizas un servicio empaquetado, revisa el pool de PHP-FPM o el módulo de Apache correspondiente, además del changelog del paquete del proveedor.
Instala y utiliza las skills de Codex
El README oficial instala ambas skills con un único comando de Codex:
$skill-installer install both skills from https://github.com/openai/php2shell-checker
Después, elige la interfaz que corresponda a tu nivel de acceso:
$phpcheck-url check https://example.com
$phpcheck-server check the PHP version serving my site
Codex es opcional. El comando de Node.js sigue siendo la interfaz directa para trabajos de CI y hosts mínimos. Si quieres automatizar el proceso, añade --json: su campo patch_status devuelve ok, vulnerable o unknown, de modo que no necesitas escribir un script que interprete texto de la terminal.
Verifica el comprobador descargado
El repositorio utiliza el ejecutor de tests integrado en Node:
node --test phpcheck.test.js
La suite prueba la CLI contra servidores HTTP locales y utiliza un ejecutable PHP falso para los escenarios locales. Según el README, no requiere ni una instalación real de PHP ni acceso a un sitio web externo.
Trata UNKNOWN como un resultado de diagnóstico
Considera UNKNOWN una evidencia incompleta. El objetivo puede ocultar su versión de PHP, utilizar una rama que el comprobador no reconoce, no responder o ejecutar una versión preliminar más reciente. Ninguna de esas situaciones demuestra que el parche esté instalado.
El usuario @jvr0x resumió así esta limitación:
“Solo compara la versión con sus umbrales del 20 de octubre, así que las cabeceras ocultas devuelven UNKNOWN.”
El comando remoto ve una respuesta HTTP, no el proceso que hay detrás del proxy inverso. Si la cabecera está oculta, necesitas comprobar el servidor, no repetir las consultas a la URL.
Después de obtener UNKNOWN, sigue esta secuencia:
- Ejecuta
node phpcheck.js --localen el host que sirve el sitio. - Determina si la petición llega a PHP-FPM, CGI, Apache
mod_phpo un contenedor. - Consulta el changelog del paquete del proveedor para comprobar si incluye backports.
- Reinicia los workers de PHP-FPM o Apache correspondientes después de actualizar.
- Verifica el runtime a través de la ruta que atiende las peticiones, no solo mediante el binario
phppredeterminado del shell.
Sin acceso SSH, el modo URL puede ser la única primera comprobación disponible. Si un hosting compartido oculta la cabecera de versión, el proveedor debe confirmar el runtime que atiende el tráfico, la revisión del paquete y el estado del reinicio.
La tabla de versiones no decide por sí sola si el parche está aplicado
El comprobador considera PHP 8.5.12, 8.4.27, 8.3.36 y 8.2.35 como las versiones upstream mínimas corregidas para sus respectivas ramas. Sus tests oficiales confirman que 8.4.26 es VULNERABLE, mientras que 8.4.27 devuelve OK; PHP identifica 8.5.12, 8.4.27, 8.3.36 y 8.2.35 como versiones de seguridad.
| Rama | Versión upstream mínima corregida | Versión anterior clasificada como vulnerable |
|---|---|---|
| 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 |
| Situación del despliegue | Por qué puede engañar una simple comparación de versiones | Evidencia que debes utilizar |
|---|---|---|
Cabecera X-Powered-By o Server oculta | El comprobador remoto no puede identificar PHP | Inventario del runtime local |
| Paquete de seguridad de Debian o Ubuntu | El proveedor puede aplicar el parche bajo una versión upstream antigua | Aviso de seguridad del proveedor y changelog del paquete |
| PHP-FPM y CLI en el mismo host | php -v puede describir la CLI y no el worker HTTP | Configuración del servidor web y de FPM |
| Contenedor en caché o digest fijado | La etiqueta del registro puede estar actualizada mientras el contenedor que se ejecuta sigue siendo antiguo | ID de la imagen y versión del contenedor en ejecución |
| Workers de Apache o FPM sin reiniciar | Los archivos corregidos pueden estar en disco mientras siguen activos workers antiguos | Hora de inicio del proceso y comprobación posterior al reinicio |
| Rama no compatible o versión preliminar | El comprobador puede no reconocer el estado del parche específico del proveedor | Aviso de seguridad de PHP o del proveedor |
La sección de limitaciones del repositorio explica que la herramienta asume que las versiones estables posteriores de una rama incluida contienen el parche y que no puede verificarlo de forma independiente. Una distribución puede aplicar un backport de seguridad sin cambiar el número de versión upstream, por lo que su changelog puede ser una prueba más sólida que el número mostrado por sí solo.
Actualizar WordPress, Drupal, Laravel u otra aplicación PHP no corrige el motor de PHP. Actualiza el paquete o la imagen del runtime, reinicia los workers y verifica el proceso que acepta las peticiones web.
Preguntas frecuentes
¿Qué resultado permite cerrar un ticket de corrección en producción?
Ningún resultado debería cerrar un ticket por sí solo. Combina OK con la identificación del SAPI que atiende el tráfico, el estado de los backports del proveedor, todos los vhosts o contenedores relevantes y la confirmación de que los workers se reiniciaron después de aplicar el parche.