发现存在 CVE-2026-42945 漏洞的配置,该漏洞是 nginx 的 ngx_http_rewrite_module 中的堆缓冲区溢出。
仅运行受影响的 nginx 版本(0.6.27 到 1.30.0)并不足以被利用。配置必须包含一对特定的指令,而这对指令很罕见:两次对真实世界配置的独立扫描分别在 1465 个配置中发现 0 个可利用配置、在 35633 个中发现 1 个。本脚本会告诉你,你处于这条线的哪一侧。
一个 rewrite,其替换内容包含一个 ? 且后面带有参数,随后在同一个 location 中读取一个未命名捕获组($1 到 $9):
location / {
rewrite ^(.*) /new?c=1; # the ? here raises the internal is_args flag
set $myvar $1; # ...which was never cleared, and leaks into this
return 200 $myvar;
}
第一遍根据原始字符串确定缓冲区大小,第二遍将转义后的版本复制进去。这两半各自看起来都是正确的。
以下每条规则都是在 nginx 1.30.0 上实测得出的,而非推断而来,因为公开的描述中有两条是错的。
| 单个 location 内的配置 | 是否崩溃 |
|---|---|
rewrite ^(.*) /new?c=1; + set $x $1; | 是 |
rewrite ^/old/(.*)$ /new?x=1; + set $x $1; | 是 |
rewrite ^/old/(.*)$ /new/$1?; + set $x $1; | 否 |
rewrite ... /mid?c=1; 然后 rewrite ... /new; 然后 set $x $1; | 否 |
rewrite ^(.*) /new?c=1 break; + set $x $1; | 否 |
rewrite ^(?<tail>.*) /new?c=1; + set $x $1; | 是 |
rewrite ^(?<tail>.*) /new?c=1; + set $x $tail; | 否 |
有两个后果值得明确说明:
结尾的 ? 并不危险。 /new/$1? 是去掉继承查询字符串的写法,它出现在大量迁移配置中。如果对每个 ? 都发出警告,那相当于对着半个互联网大喊。
“命名捕获是安全的”这种说法是错误的。 重要的是捕获如何被读取,而不是它如何被声明。一个命名组如果以 $1 方式读取,其崩溃方式与未命名捕获完全一样。
出于同样的实测原因,以下情况也会被忽略:正则本身内部的 ?(作为量词),以及 redirect / permanent / break,它们会在消费者运行之前结束处理。
nginx -T | python3 check_rewrite.py
python3 check_rewrite.py /path/to/dump.txt
python3 check_rewrite.py --json /path/to/dump.txt
仅需 Python 3,且只用标准库。
退出码:0 表示无问题,1 表示发现了一对指令,2 表示配置无法读取或解析。 第三个退出码是关键:未闭合的引号或不成对的花括号会截断分析,而对一个无法读取的文件返回“未发现”的检查器,比直接崩溃更糟糕。发生这种情况时,它会明确说明并返回 2。
请向它传入 nginx -T 的输出,而不是单独的文件:include 可以位于任何地方,且生成的配置只有在运行中的服务器上才是真实有效的。发现项会报告指令实际所在的文件和行号,而不是转储文件中的偏移量。
$ python3 check_rewrite.py samples/vuln-nginx-T.txt
[HIGH] находка #1
location: location / (/etc/nginx/nginx.conf:14)
rewrite: rewrite ^(.*) /new?c=1 (/etc/nginx/nginx.conf:15)
захват $N: set -> set $myvar $1 (/etc/nginx/nginx.conf:16)
почему: обработка продолжается в этом же location без редиректа
Итого находок: 1
这些也会打印在每份报告的末尾,以免有人把这工具当成保证:
location 只报告第一对指令;server 中而非 location 内的 rewrite 和 set 不会被追踪;set $tmp $1; 之后再使用 $tmp);try_files、error_page 和命名 location 的跳转;if 内的一对指令仍然会被报告。升级比任何配置检查都更可靠。请从 nginx.org 获取当前稳定版或主线版本。
python3 -m unittest test_check_rewrite -v
共 29 个测试。其中大多数是负面用例,因为此类工具的风险在于对没有问题的配置发出告警。它还曾在包含十一个 include 文件、总计 250 行的生产配置上运行,该配置含有一个 map 正则和一个引号内充满分号的 CSP 头:零发现、零解析报错,而一旦向其中注入一个真实指令对,则恰好得到一个发现。
MIT