theopaid/CVE-2026-67183-Unauthenticated-Memory-Leak-Leads-To-Memory-Exhaustion-TinyWeb-
GitHub: theopaid/CVE-2026-67183-Unauthenticated-Memory-Leak-Leads-To-Memory-Exhaustion-TinyWeb-
该仓库披露了 TinyWeb HTTP 服务器因请求对象缺少析构函数而导致的未授权内存耗尽漏洞(CVE-2026-67183),包含完整的技术分析、PoC 和修复建议。
Stars: 0 | Forks: 0
# 安全公告:未授权内存泄漏导致内存耗尽 (TinyWeb)
**分配的 CVE ID:** CVE-2026-67183
## 摘要
TinyWeb 在解析每个请求时会分配多个对象,且从不释放它们。请求和 header 结构没有析构函数,在发送响应后也没有任何代码删除它们。Worker 的内存随着每个请求不断增长且从不下降,因此稳定的普通请求流会导致 Worker 内存耗尽。
## 受影响软件
- 项目:TinyWeb (https://github.com/GeneralSandman/TinyWeb)
- 构建报告的版本:`TnyWeb/0.0.8`
- 受影响的提交:`e48f15d` (2018-11-20),即引入这些结构和解析器的提交,到 `a381da2` (2023-11-22,`master` 分支上的最新提交)。
- 修复版本:无。
## 分类
- CWE-401:有效生命周期结束后未释放内存
- CVSS 4.0 基础分数:8.7 (高)
- 向量:`CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N`
## 威胁模型
未经身份验证的远程攻击者能够访问服务器的监听 TCP 端口(在默认配置中为 9090)并以适中的持续速率发送请求。不需要任何凭证或用户交互。请求可以是格式良好的;不需要特殊的 payload。
## 技术细节
对于每个请求,`HttpParser::execute()` 都会分配一个 `Url`、一个 `HttpHeaders` 以及每个 header 行对应的一个 `HttpHeader`:
```
// src/tiny_http/http_parser.cc:1692
request->url = new Url;
// src/tiny_http/http_parser.cc:1709
request->headers = new HttpHeaders;
// src/tiny_http/http_parser.cc:1033-1040
HttpHeader* header = new HttpHeader;
return_val = parseHeader(stream, offset, len, header);
...
result->generals.push_back(header); // stored in a raw-pointer list
```
`HttpRequest` 和 `HttpHeaders` 是没有析构函数的普通结构体,因此销毁 `HttpRequest` 时不会释放其中任何内容:
```
// src/tiny_http/http_parser.h:442
typedef struct HttpRequest {
...
Url* url;
HttpHeaders* headers;
HttpBody* body;
} HttpRequest;
// src/tiny_http/http_parser.h:279-304
typedef struct HttpHeaders {
...
std::list generals; // raw pointers, never deleted
...
} HttpHeaders;
```
`WebProtocol` 使用 `std::shared_ptr` 来持有请求 (`src/tiny_http/http_protocol.h:49`)。当下一个请求替换它时,默认的 `~HttpRequest` 会运行,并泄漏 `url`、`headers`、`body` 以及 `generals` 中的每个 `HttpHeader`。代码中唯一的 `delete request` 位于 `getDataFromProxy()` (`src/tiny_http/http_protocol.cc:194`) 中,但请求路径从未调用过该函数。来自内存池的每请求响应缓冲区进一步加剧了内存的增长。
## 概念验证
1. 使用默认配置启动服务器(监听 9090 端口)。记录某个 worker 的进程 ID。
2. 记录该 worker 的常驻内存:
```
grep VmRSS /proc//status
```
3. 发送一批普通请求:
```
for i in $(seq 1 2000); do
curl -s -o /dev/null http://TARGET:9090/
done
```
4. 再次读取 `VmRSS`。它已经增长并且之后不会下降。一次典型的运行结果:
```
VmRSS before: 3704 kB
after 500 requests: 4788 kB
after 1000 requests: 22068 kB
after 1500 requests: 41652 kB
after 2000 requests: 59956 kB
```
这种增长是单调的,每个请求大约增长 20 到 28 kB,没有停滞期。重复发送该批次会继续增加内存,直到 Worker 因内存耗尽而被杀掉。
## 影响
未经身份验证的攻击者可以通过持续的请求流耗尽 Worker 的内存,并迫使系统出现内存不足的情况,从而导致拒绝服务。随着时间的推移,普通流量也会发生泄漏,因此即使没有攻击者,这种情况也可能发生。
## 修复建议
为 `HttpRequest` 和 `HttpHeaders` 提供析构函数,以释放 `url`、`headers`、`body` 以及 `generals` 中的每个 `HttpHeader`,或者使用智能指针来持有它们以便自动释放。此外,一旦响应发送完毕,也应释放每个请求对应的内存池缓冲区。
标签:C++, CVE, Web服务器, 内存泄漏, 拒绝服务, 数字签名, 数据擦除, 漏洞分析, 路径探测, 配置错误