
Detector de PoC y validador seguro para la cadena de vulnerabilidades de WordPress WP2Shell: CVE-2026-63030 (confusión de rutas por lotes REST) + CVE-2026-60137 (inyección SQL author__not_in). Solo para pruebas de seguridad autorizadas.
Cobertura de CVEs: CVE-2026-63030 y CVE-2026-60137 Uso previsto: Pruebas de seguridad autorizadas, validación defensiva y laboratorios locales desechables únicamente
WP2Shell es una cadena de vulnerabilidades del núcleo de WordPress que combina un error de confusión de rutas por lotes en la API REST previo a la autenticación (CVE-2026-63030) con una primitiva de inyección SQL en WP_Query mediante author__not_in (CVE-2026-60137). Este repositorio proporciona un escáner de prueba de concepto en Python y un validador seguro para que los defensores puedan identificar instalaciones de WordPress afectadas, confirmar el comportamiento vulnerable en un laboratorio aislado y verificar la remediación, sin necesidad de extraer datos o lograr ejecución de código.
Este proyecto identifica instalaciones de WordPress y valida las dos primitivas de vulnerabilidad asociadas con la cadena de vulnerabilidades WP2Shell del núcleo de WordPress:
WP_Query::author__not_in, que puede resultar en inyección SQL cuando entradas controladas por el atacante alcanzan el parámetro.Cuando ambas condiciones están presentes, una solicitud no autenticada puede llegar a la construcción SQL vulnerable a través del endpoint por lotes de la API REST de WordPress. Los avisos públicos describen el impacto combinado como potencialmente conducente a la ejecución remota de código.
Este repositorio debe utilizarse únicamente en sistemas que usted posea o para los que tenga autorización explícita de prueba. Se recomienda preferir un laboratorio aislado con Docker o una máquina virtual vinculada a 127.0.0.1.
El archivo fuente actual contiene funcionalidad que cambia el estado del sistema, incluidos intentos de extracción de datos de bases de datos, intentos de escritura de archivos, flujos de autenticación, creación de administradores, carga de complementos y ejecución de comandos.
Las versiones afectadas de WordPress pueden perder la alineación entre los arreglos internos utilizados para rastrear:
Cuando un miembro de lote malformado es aceptado en un arreglo interno pero no en otro, las solicitudes posteriores pueden asociarse con el manejador incorrecto. Por lo tanto, una solicitud puede ser validada como una ruta pero ejecutada utilizando el callback de otra ruta.
Impacto de seguridad:
author__not_inLa implementación afectada de WP_Query no normaliza de manera consistente author__not_in antes de utilizarlo para construir una condición SQL NOT IN (...).
El parámetro normalmente espera una lista de ID de autor enteros. Si una cadena escalar llega a la construcción de consulta vulnerable sin la validación de esquema REST prevista, la estructura SQL insegura puede sobrevivir hasta la consulta a la base de datos.
Impacto de seguridad:
WordPress publicó correcciones el 17 de julio de 2026 y habilitó actualizaciones automáticas forzadas para las instalaciones afectadas debido a la gravedad.
Unauthenticated client | v WordPress REST batch endpoint | v Malformed batch member creates request/handler misalignment | v Later request is validated against one route but dispatched using another route's handler | v Scalar author_exclude reaches WP_Query as author__not_in | v Unsafe value reaches SQL NOT IN (...) construction | v Blind SQL timing or Boolean oracle | v Potential database compromise | v Potential application-level compromise and RCE
El detector debe detenerse después de confirmar las primitivas de confusión de rutas e inyección SQL. No necesita extraer datos ni ejecutar comandos para establecer que una instalación afectada es vulnerable.
---
## Flujo de detección
### Fase 1 — Normalizar el objetivo
La herramienta:
1. Agrega un esquema `http` o `https` predeterminado si falta.
2. Normaliza la ruta de instalación de WordPress.
3. Rechaza esquemas de URL no compatibles y credenciales incrustadas.
4. Aplica políticas de redirección, proxy, TLS y tiempo de espera.
### Fase 2 — Identificar WordPress
El escáner busca:
- Referencias a `wp-content/`.
- Referencias a `wp-includes/`.
- Metadatos del generador de WordPress.
- Enlaces de descubrimiento de la API REST.
- Estructura del índice REST de WordPress.
- El espacio de nombres `wp/v2`.
- Huellas opcionales de feed y `readme.html`.
### Fase 3 — Determinar la versión
La evidencia de la versión puede provenir de:
- Metadatos del generador HTML.
- Metadatos del generador de feed.
- Cadenas de consulta de activos del núcleo de WordPress.
- Cabeceras HTTP del generador.
- `readme.html`.
- Un archivo local `wp-includes/version.php`.
La evidencia se puntúa y se concilia. Los indicadores de versión remota contradictorios reducen la confianza.
### Fase 4 — Comprobar la exposición de la ruta batch
El escáner intenta descubrir `/batch/v1` mediante:```text
/?rest_route=/
/wp-json/
La ruta se puede abordar utilizando cualquiera de las siguientes opciones:```text /?rest_route=/batch/v1 /wp-json/batch/v1
### Fase 5 — Sonda segura de confusión de rutas
La sonda segura contiene:
1. Una ruta interna deliberadamente malformada.
2. Una solicitud a un ID de publicación no válido con un `GET` público anidado e inofensivo.
3. Una solicitud `/batch/v1` posterior.
Un servidor vulnerable devuelve una respuesta externa `207 Multi-Status` en la que la solicitud de publicación no válida se procesa como una solicitud de lote anidada.
El detector informa:```text
route-confusion-observed
cuando ve:
parse_path_failed esperado.207.responses anidada que muestre que la solicitud interna inofensiva se ejecutó.Un validador de SQLi no destructivo debería enviar solicitudes emparejadas que difieran solo por una condición booleana constante:```text False control -> no deliberate database delay True test -> deliberate database delay
El validador debe:
- Aceptar el HTTP externo esperado `207`.
- Analizar tanto los sobres de lote externos como los anidados.
- Verificar los marcadores de solicitudes malformadas.
- Asegurar que la solicitud anidada con SQLi devolvió una respuesta válida.
- Recopilar múltiples muestras verdaderas y falsas.
- Aleatorizar o intercalar el orden de las muestras.
- Comparar medianas en lugar de una sola solicitud.
- Reportar mediciones insuficientes como `inconclusive`.
Una brecha repetible entre las muestras verdaderas y falsas confirma que la entrada controlada por el atacante llegó a la evaluación SQL. No es necesario seleccionar ni extraer contenidos de la base de datos.
---
## Requisitos
- Python 3.9 o posterior.
- No se requieren paquetes de Python de terceros para el script proporcionado.
- Acceso de red a la instalación de WordPress autorizada.
- Para pruebas locales:
- Un laboratorio desechable de WordPress 7.0.1 o 6.9.4.
- Un contenedor de base de datos o una base de datos de pruebas dedicada.
- El servicio web enlazado a `127.0.0.1`.
- Sin credenciales ni datos de producción.
Comprueba Python:```bash
python3 --version
Validación opcional de sintaxis:```bash python3 -m py_compile WP2Shell_CVE-2026-63030_POC.py
---
## Instalación
Cambia el nombre del script proporcionado a un nombre de archivo predecible:```bash
mv 'poc(1).py' WP2Shell_CVE-2026-63030_POC.py
chmod +x WP2Shell_CVE-2026-63030_POC.py
Mostrar ayuda global:```bash python3 WP2Shell_CVE-2026-63030_POC.py --help
Mostrar la versión:```bash
python3 WP2Shell_CVE-2026-63030_POC.py --version
El script define tres comandos:```text remote Fingerprint and scan HTTP(S) WordPress targets. local Read the installed WordPress version from a source tree. exploit State-changing proof-of-concept path.
### Estado Actual de la Compilación
| Comando | Estado |
|---|---|
| `local` | Implementado |
| `remote` | La CLI está definida, pero `run_remote()` actualmente es un stub y devuelve un error |
| `exploit` | Contiene funcionalidad que cambia el estado; restríngelo a un laboratorio local desechable y sepáralo del escaneo defensivo |
La fuente actualmente imprime lo siguiente para `remote`:```text
Remote scanning not fully implemented in this snippet. Use 'local' or 'exploit'.
Restaura una implementación completa de run_remote() antes de anunciar el escaneo remoto masivo como funcional.
El comando local lee:```text
/wp-includes/version.php
y extrae `$wp_version`.
## Uso básico```bash
python3 WP2Shell_CVE-2026-63030_POC.py local \
--wordpress-root /var/www/html
python3 WP2Shell_CVE-2026-63030_POC.py local
--wordpress-root /var/www/html
--format json
--output local-result.json
## Instalación de WordPress basada en Docker
Cuando el contenedor de WordPress se llama `wordpress`, copie o monte el árbol de fuentes en el host, o ejecute la comprobación de versión dentro del contenedor:```bash
docker compose exec wordpress php -r \
'require "/var/www/html/wp-includes/version.php"; echo $wp_version, PHP_EOL;'
Usa el compose.yaml proporcionado para ejecutar un laboratorio local desechable vinculado a 127.0.0.1:8080:```bash
docker compose up -d
Una vez que la configuración inicial de WordPress se complete en el navegador en `http://127.0.0.1:8080`, puedes ejecutar:```bash
python3 WP2Shell_CVE-2026-63030_POC.py remote \
--authorized \
--target http://127.0.0.1:8080 \
--active-probe \
--format json
Para detener y eliminar el laboratorio:```bash docker compose down -v
## Opciones de comando locales
| Opción | Descripción |
|---|---|
| `--wordpress-root PATH` | Directorio obligatorio que contiene `wp-includes/version.php` |
| `-f, --format` | `table`, `json`, `jsonl` o `csv` |
| `-o, --output FILE` | Escribe el informe en un archivo |
| `--fail-on` | Política de código de salida: `never`, `vulnerable` o `unknown` |
## Ejemplo de salida de vulnerable-version```json
[
{
"selected_version": "7.0.1",
"version_assessment": "affected-wp2shell",
"verdict": "CONFIRMED_AFFECTED_VERSION",
"severity": "critical"
}
]
Un resultado de versión local confirma que la versión instalada se encuentra dentro del rango afectado publicado. Por sí solo, no demuestra la explotabilidad en tiempo de ejecución ni el efecto de un parche retroportado.
El analizador remote admite los siguientes argumentos, pero la implementación proporcionada de run_remote() está actualmente incompleta.
Interfaz esperada tras restaurar run_remote():```bash
python3 WP2Shell_CVE-2026-63030_POC.py remote
--authorized
--target https://wordpress.example
--active-probe
## Múltiples objetivos explícitos```bash
python3 WP2Shell_CVE-2026-63030_POC.py remote \
--authorized \
--target https://site-one.example \
--target https://site-two.example \
--active-probe
Crea targets.txt:```text
https://site-one.example/
https://site-two.example/blog/
Interfaz esperada:```bash
python3 WP2Shell_CVE-2026-63030_POC.py remote \
--authorized \
--targets-file targets.txt \
--active-probe \
--format jsonl \
--output results.jsonl
cat targets.txt | python3 WP2Shell_CVE-2026-63030_POC.py remote
--authorized
--stdin
## Uso del proxy```bash
python3 WP2Shell_CVE-2026-63030_POC.py remote \
--authorized \
--target https://wordpress.example \
--active-probe \
--proxy http://127.0.0.1:8081
python3 WP2Shell_CVE-2026-63030_POC.py remote
--authorized
--target https://wordpress.example
--header 'Authorization: Bearer TEST_TOKEN'
## Remote options
| Option | Propósito |
|---|---|
| `-u, --target URL` | URL objetivo; repetible |
| `-l, --targets-file FILE` | Un objetivo por línea; repetible |
| `--stdin` | Leer objetivos desde stdin |
| `--authorized` | Confirmación de autorización requerida |
| `--default-scheme` | Esquema aplicado cuando se omite |
| `-c, --concurrency` | Trabajadores de objetivos concurrentes |
| `--rate` | Tasa de solicitudes agregada |
| `--timeout` | Tiempo de espera por solicitud |
| `--retries` | Número de reintentos |
| `--max-targets` | Número máximo de objetivos aceptados |
| `--max-body-bytes` | Cuerpo de respuesta máximo retenido |
| `-k, --insecure` | Deshabilitar verificación TLS |
| `--no-redirects` | Deshabilitar redirecciones |
| `--allow-cross-host-redirects` | Permitir redirecciones a otro host |
| `--proxy` | Proxy HTTP/HTTPS |
| `-H, --header` | Cabecera personalizada; repetible |
| `--user-agent` | Anular User-Agent |
| `--fingerprint-level` | `quick`, `standard` o `extended` |
| `--active-probe` | Enviar la sonda segura de confusión de ruta |
| `--rest-endpoint` | `query`, `pretty` o `both` |
| `--include-request-log` | Agregar metadatos de URL, estado y tiempo |
| `-f, --format` | `table`, `json`, `jsonl` o `csv` |
| `-o, --output` | Escribir la salida en un archivo |
| `--fail-on` | Política de código de salida |
---
# Validación de tiempo de ejecución segura
Para una validación local no destructiva de ambas primitivas, utilice un validador dedicado que:
- Rechaza hosts que no sean loopback.
- Confirma primero la confusión de ruta.
- Ejecuta muestras de tiempo de condición constante solo después de que la confusión de ruta tenga éxito.
- No extrae datos ni ejecuta comandos.
Ejemplo de flujo de trabajo:```bash
python3 wp2shell_local_validator.py check \
--authorized \
--target http://127.0.0.1:8080 \
--sqli \
--delay 2 \
--samples 4 \
--warmups 2 \
--debug \
--dump-dir evidence \
--output result.json
Patrón de temporización esperado del laboratorio vulnerable:```text False controls: approximately 0.03–0.10 seconds True tests: consistently delayed
Veredicto esperado:```text
FULL_VULNERABILITY_PRIMITIVES_CONFIRMED
Una prueba de temporización puede ejecutar la expresión de retardo más de una vez, por lo que un retardo configurado de dos segundos puede producir un retardo observado cercano a los cuatro segundos. La señal importante es la separación repetible entre las condiciones verdaderas y falsas.
Mejor para uso en terminal interactiva:```bash --format table
### JSON
Ideal para evidencia e integración:```bash
--format json --output result.json
Mejor para grandes conjuntos de objetivos:```bash --format jsonl --output results.jsonl
### CSV
Mejor para hojas de cálculo e informes:```bash
--format csv --output results.csv
El escáner utiliza códigos de salida basados en políticas.
Por lo tanto, un hallazgo de vulnerabilidad puede devolver intencionalmente un estado distinto de cero.
Ejemplo:```bash
python3 WP2Shell_CVE-2026-63030_POC.py local
--wordpress-root /var/www/html
--fail-on vulnerable
echo $?
---
## Prueba diferencial entre vulnerable y corregido
Una validación sólida compara dos entornos limpios.
### Entorno vulnerable```text
WordPress 7.0.1
Esperado:```text route-confusion-observed repeatable true/false SQL timing difference
### Entorno fijo```text
WordPress 7.0.2
I'm ready to translate chunk 77 of 85. Please provide the source text for the chunk (the Markdown content that appears after "INPUT:"). The input appears to be empty in your message, so I need the actual content to translate it into Spanish.
Once you paste the chunk text, I'll translate it following all the chunk-specific rules:
Always recreate the WordPress volume when changing versions. Reusing a volume can preserve old or automatically updated core files.```bash
docker compose down -v
docker compose pull
docker compose up -d
Actualice inmediatamente a una de las versiones corregidas o a una versión soportada posterior:
Los controles temporales deben cubrir ambas formas de endpoints por lotes:
---```text /wp-json/batch/v1 /?rest_route=/batch/v1
Acciones defensivas adicionales:
1. Revise los registros en busca de solicitudes anónimas por lotes, URL internas malformadas, estructuras de lote anidadas y valores inusuales de `author_exclude`.
2. Revise las cuentas de administrador, los cambios de plugins, los archivos PHP inesperados y el acceso a la base de datos después de cualquier período de exposición.
3. Verifique las sumas de verificación del núcleo de WordPress y restaure desde una copia de seguridad de confianza si se sospecha un compromiso.
4. Rote los secretos y credenciales almacenados en la base de datos de WordPress cuando pueda haberse producido una explotación por inyección SQL.
Bloquear el endpoint es una mitigación temporal, no un sustituto de la actualización del núcleo de WordPress.
---
## Ideas de detección
Los indicadores potenciales incluyen:
- Solicitudes `POST` anónimas a cualquiera de las dos formas de endpoint por lotes.
- Respuestas HTTP `207` que contienen arrays `responses` anidados.
- URL internas malformadas en los cuerpos de las solicitudes por lotes.
- Objetos `requests` anidados dentro de otro miembro del lote.
- Valores `author_exclude` escalares o con forma SQL.
- Solicitudes pareadas repetidas con respuestas rápidas y retrasadas alternadas.
- Creación inesperada de administradores de WordPress.
- Instalación o activación inesperada de plugins.
- Nuevos archivos PHP en directorios de WordPress con permisos de escritura.
- Consultas a la base de datos que contengan expresiones inusuales `author__not_in`.
---
## Limitaciones conocidas del script proporcionado
- El manejo de cookies no es equivalente a una sesión de navegador persistente.
- Los prefijos de las tablas de la base de datos se asumen en algunas rutas de código.
- El privilegio `FILE` de la base de datos y las rutas del sistema de archivos varían según el despliegue.
- `INTO OUTFILE` normalmente está restringido y no puede sobrescribir archivos existentes.
- WordPress puede deshabilitar la instalación de plugins mediante `DISALLOW_FILE_MODS`.
- Los umbrales de tiempo pueden verse afectados por proxies, WAF, tiempos de espera de PHP, tiempos de espera de la base de datos y la carga.
- Las cadenas de versión pueden estar ocultas, falsificadas, almacenadas en caché o ser inconsistentes.
- Una versión afectada observada no demuestra la ausencia de un backport de seguridad.
- La falta de una señal de tiempo no demuestra que el servidor esté parcheado.
---
## Referencias
- WordPress 7.0.2 Security Release:
https://wordpress.org/news/2026/07/wordpress-7-0-2-release/
- Documentación de WordPress 7.0.2 y archivos modificados:
https://wordpress.org/documentation/wordpress-version/version-7-0-2/
- NVD — CVE-2026-63030:
https://nvd.nist.gov/vuln/detail/CVE-2026-63030
- NVD — CVE-2026-60137:
https://nvd.nist.gov/vuln/detail/CVE-2026-60137
- Archivo de versiones de WordPress:
https://wordpress.org/download/releases/
---
## Uso legal y ético
Utilice este proyecto únicamente cuando:
- Usted sea el propietario del sistema, o
- Cuente con autorización explícita por escrito, y
- La actividad de prueba solicitada esté dentro del alcance acordado.
No exponga instalaciones de WordPress deliberadamente vulnerables a Internet público. Utilice credenciales desechables, datos sintéticos, redes aisladas y snapshots limpios. Destruya o restablezca el laboratorio después de las pruebas.
La prueba de vulnerabilidad más segura es la evidencia mínima necesaria para demostrar el problema:```text
Affected version
+
Route-confusion behavior
+
Repeatable constant-condition SQL timing oracle
El robo de credenciales, la persistencia, la instalación de webshells y la ejecución de comandos no son necesarios para confirmar que la vulnerabilidad existe.
| Rama de WordPress | Afectada | Versión corregida |
|---|
| 6.8.x | Solo CVE-2026-60137: 6.8.0–6.8.5 | 6.8.6 |
| 6.9.x | Ambos problemas: 6.9.0–6.9.4 | 6.9.5 |
| 7.0.x | Ambos problemas: 7.0.0–7.0.1 | 7.0.2 |
| 7.1 prerelease | Beta 1 afectada | Beta 2 |
| Anteriores a 6.8 | No afectadas por estos dos CVEs | N/A |
| Veredicto | Significado |
|---|
CONFIRMED_VULNERABLE_BEHAVIOR | Se observó un comportamiento de confusión de rutas en tiempo de ejecución |
CONFIRMED_AFFECTED_VERSION | La versión del código fuente local está en un rango afectado |
LIKELY_VULNERABLE | La evidencia de la versión remota indica una versión afectada |
VULNERABLE_SQLI_ONLY | La versión está afectada por CVE-2026-60137, pero fuera del rango completo de confusión de rutas |
AFFECTED_VERSION_BUT_BEHAVIOR_NOT_OBSERVED | Se detectó una versión afectada, pero el comportamiento seguro en tiempo de ejecución estuvo ausente |
PATCHED_VERSION | La versión cumple con el umbral de corrección publicado |
NOT_AFFECTED | La versión está fuera de la rama afectada |
POTENTIALLY_EXPOSED_VERSION_UNKNOWN | Se encontraron WordPress y la ruta de lote, pero la versión está oculta |
WORDPRESS_VERSION_UNKNOWN | WordPress detectado sin evidencia confiable de versión |
ERROR | No se pudo evaluar el objetivo |
NOT_WORDPRESS_OR_NOT_DETECTED | Sin evidencia confiable de WordPress |
| Código | Significado |
|---|
0 | Sin resultados que activen políticas, o --fail-on never |
2 | Resultado vulnerable o afectado según la política predeterminada |
3 | Resultado desconocido o no concluyente cuando se selecciona --fail-on unknown |
1 | Error de argumento, entrada o comando incompleto |