Skip to content
KitploitKITPLOIT
HerramientasBlog
Log in
Enviar
HerramientasBlog
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.

FeedsContactoPrivacidad© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
wp2shell — CVE-2026-63030 + CVE-2026-60137 - “wp2shell”: RCE no autenticado en el núcleo de WordPress | Kitploit
Herramientas/GitHubGitHub/0xsha/wp2shell
Descifrado de ContraseñasAnálisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebPruebas de PenetraciónComando y ControlAprendizaje y EducaciónRed TeamingDesarrollo de PayloadsLabs y Práctica
GitHub
963037hace 2 mesesRevisado por Kitploit

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
0xsha/wp2shell

wp2shell

CVE-2026-63030 + CVE-2026-60137 - “wp2shell”: RCE no autenticado en el núcleo de WordPress

Ver Repositorio

CVE-2026-63030 + CVE-2026-60137 - "wp2shell": RCE no autenticado en el núcleo de WordPress

Confusión de rutas del lote de la API REST (CVE-2026-63030) encadenada con una inyección SQL en WP_Query author__not_in (CVE-2026-60137) → ejecución remota de código pre-autenticación contra una instalación predeterminada de WordPress.

Descubierto por Adam Kues (Assetnote / Searchlight Cyber), divulgado el 2026-07-17. Avisos: GHSA-ff9f-jf42-662q, GHSA-fpp7-x2x2-2mjf.

Cadena (RCE sin autenticación)WordPress 6.9.0 - 6.9.4 y 7.0.0 - 7.0.1
Solo SQLi (necesita un plugin/tema facilitador)6.8.0 - 6.8.5
No afectado≤ 6.8 para la confusión del lote; 6.9.5 / 7.0.2 / 7.1-beta2 (parcheado)
PrecondicionesAPI REST accesible; sin caché de objetos persistente (Redis/Memcached); ≥1 entrada publicada
Autenticación requeridaninguna
Impactosin autenticación → crear un nuevo administrador → ejecución de código (la SQLi también extrae el hash del administrador)

Demo

https://github.com/user-attachments/assets/7f9cc52c-3f31-4339-9192-e31e506684f6

Qué añade este repositorio

  • Una herramienta original que usa solo la biblioteca estándar (wp2shell.py) que unifica lo mejor de seis PoCs públicos en un solo archivo, sin dependencia de requests y sin funciones rotas.
  • El RCE completo sin crackeo, verificado de extremo a extremo en laboratorio: shell sin credenciales forja un WP_Post falso mediante la confusión UNION de una sola entrada, tiende un puente hacia el personalizador para crear un administrador nuevo (POST /wp/v2/users), inicia sesión y despliega un webshell protegido por token. El volcado del hash del administrador por SQLi (read --preset users) se mantiene como segunda vía verificada.
  • Un detector de confusión independiente de la versión (block_cannot_read) usado como check principal no destructivo.
  • Transporte de producción en cada comando: TLS autofirmado, cabeceras personalizadas, User-Agent personalizado, proxy, reintentos, retardo de peticiones.
  • Una vía verificada de SQLi facilitada en 6.8.x (sqli) que los demás PoCs no tienen.
  • Laboratorios Docker reproducibles además de una matriz de fiabilidad por versión y BD, con cada resultado verificado en laboratorio.
  • El modo de hashcat para el nuevo hash de contraseña $wp$2y$ (-m 35500).
wp2shell/
├── README.md              ← you are here
├── wp2shell.py            ← the unified PoC (single file, stdlib only, by 0xsha)
└── lab/                   ← reproducible Docker labs + reliability matrix
    ├── docker-compose.yml         (default 6.9.4 lab)
    ├── docker-compose.matrix.yml  (parameterised: any version × MySQL/MariaDB)
    ├── docker-compose.sqli.yml    (6.8.3 "SQLi only" lab)
    ├── matrix.sh                  (runs the whole reliability matrix)
    └── sqli-only/facilitator.php  (mu-plugin: the 6.8.x facilitating sink)

Los seis PoCs públicos de los que se nutre esta herramienta no se incluyen aquí; están enlazados en Créditos.

Todo lo que sigue fue verificado en el laboratorio Docker local (consulta §4); las afirmaciones que no se ejecutaron en el laboratorio están etiquetadas como tales.


1. Detalles de la vulnerabilidad - inmersión profunda en el código

La cadena suelda dos errores independientes. Los números de línea provienen del código fuente real de WordPress 6.9.4 (extraído de wordpress:6.9.4-apache).

Error A - inyección SQL en author__not_in (CVE-2026-60137)

wp-includes/class-wp-query.php, WP_Query::get_posts():

2403  if ( ! empty( $query_vars['author__not_in'] ) ) {
2404      if ( is_array( $query_vars['author__not_in'] ) ) {                 // ← guard only fires for ARRAYS
2405          $query_vars['author__not_in'] = array_unique( array_map( 'absint', $query_vars['author__not_in'] ) );
2406          sort( $query_vars['author__not_in'] );
2407      }
2408      $author__not_in = implode( ',', (array) $query_vars['author__not_in'] );   // ← string passes straight through
2409      $where         .= " AND {$wpdb->posts}.post_author NOT IN ($author__not_in) ";  // ← raw interpolation
2410  } elseif ( ! empty( $query_vars['author__in'] ) ) {
...
2415      $author__in = implode( ',', array_map( 'absint', array_unique( (array) $query_vars['author__in'] ) ) );  // ← absint INSIDE implode

Un author__not_in de tipo cadena se salta la protección is_array() (2404); implode(',', (array)"…") lo devuelve sin cambios (2408) y se concatena en bruto al SQL (2409). El hermano author__in (2415) vuelve a aplicar array_map('absint', …) dentro del implode y es seguro: ese array_map que falta es el error. El valor acaba como ... post_author NOT IN (<valor>) ..., por lo que 0) <sql>-- - cierra la lista y añade SQL.

Conseguir que llegue una cadena hasta ahí es la parte difícil: el endpoint REST de entradas asigna author_exclude → author__not_in (class-wp-rest-posts-controller.php:247) pero lo declara como 'type' => 'array' de enteros, por lo que el núcleo fuerza/rechaza una cadena:

GET /wp-json/wp/v2/posts?author_exclude=1) OR SLEEP(3)-- -
→ 400 "author_exclude[0] is not of type integer."      (verified on 6.8.3)

Por eso el error A por sí solo es únicamente "facilitado". El error B introduce de contrabando la cadena sorteando la validación en 6.9+.

Error B - confusión de rutas del lote de la API REST (CVE-2026-63030)

wp-includes/rest-api/class-wp-rest-server.php, serve_batch_request_v1():

1720  if ( false === $parsed_url ) {
1721      $requests[] = new WP_Error( 'parse_path_failed', … );   // a bad path becomes a WP_Error IN $requests

1749  foreach ( $requests as $single_request ) {
1750      if ( is_wp_error( $single_request ) ) {
1752          $validation[] = $single_request;     // ← pushed to $validation …
1753          continue;                            // ← … but $matches is SKIPPED
1754      }
1757      $matches[] = $match;                     // ← $matches only grows for VALID requests

1825  foreach ( $requests as $i => $single_request ) {   // indexed by position in $requests
1841      $match = $matches[ $i ];                        // ← $matches is SHORTER → +1 shift
1861      $result = $this->respond_to_request( $single_request, $route, $handler, $error );

Una sub-petición WP_Error se inserta en $validation[] (1752) pero no en $matches[] (el continue en 1753 se salta la línea 1757), por lo que $matches se queda corto y $matches[$i] (1841) contiene el handler de la siguiente petición. La petición i se despacha con el handler de la petición i+1, llevando sus propios parámetros y su propio veredicto de validación (superada).

Origen de la regresión (verificado en el diff 6.8.3 → 6.9.4): en 6.8.3, el bucle inserta $matches[] = $match para todas las peticiones y las rutas incorrectas se descartan en el primer bucle: los arrays permanecen alineados, sin desincronización. La refactorización de 6.9.0 introdujo el desplazamiento. Es exactamente por eso que 6.8.x es "solo SQLi" y la cadena de RCE comienza en 6.9.0.

El parche documentado (6.9.5 / 7.0.2)

El parche añade $matches[] también para las entradas de error, refuerza la reentrada y analiza author__not_in con un auxiliar de listas de ID. (6.9.5 no estaba en Docker Hub cuando se hicieron las pruebas, así que esto proviene de los avisos, no de un diff de laboratorio.)


2. Método de explotación

2.1 La doble confusión de rutas

Descargar herramienta