needhelp
← 返回博客

NGINX Rift(CVE-2026-42945):重写模块中潜伏 18 年的堆溢出漏洞

作者 xingwangzhe
NGINX
CVE
安全
RCE
堆溢出
Web 服务器

NGINX Rift(CVE-2026-42945, CVSS 9.2):NGINX 重写模块中的严重堆缓冲区溢出漏洞,由 depthfirst 的 AI 分析系统自主发现。自 2008 年引入以来潜伏了 18 年,未认证攻击者只需一个特制 HTTP 请求即可实现远程代码执行。


隐匿在眼皮底下的漏洞

2026 年 5 月 13 日,F5 与 depthfirst 联合披露了 CVE-2026-42945——NGINX ngx_http_rewrite_module 中的一个严重堆缓冲区溢出漏洞。该漏洞自 2008 年 起就存在于代码库中,随 NGINX 0.6.27 引入,影响此后直到 1.30.0 的每一个版本。

这一发现的特别之处在于它的发现方式:不是由人类研究员手动审计代码,而是由 depthfirst 的自主漏洞分析系统 完成的。AI 系统被指向 NGINX 源代码,在 六小时内 就标记出了这个躲过了人类 18 年检查的堆溢出问题。

指标
CVECVE-2026-42945
CVSS v4.09.2(严重)
发现者depthfirst(自主 AI 分析)
引入时间2008 年(NGINX 0.6.27)
潜伏时间18 年
漏洞类型堆缓冲区溢出(两遍长度计算不一致)
需要认证不需要
影响远程代码执行(RCE)或工作进程崩溃(DoS)
修复版本NGINX 1.31.0 / 1.30.1

受影响版本

漏洞影响几乎所有的 NGINX 产品线:

产品受影响版本
NGINX 开源版0.6.27 至 1.30.0
NGINX PlusR32 至 R36
NGINX Instance Manager2.16.0 至 2.21.1
F5 NGINX App Protect WAF4.9.0–4.16.0, 5.1.0–5.8.0
NGINX Ingress Controller3.5.0–3.7.2, 4.0.0–4.0.1, 5.0.0–5.4.1
NGINX Gateway Fabric1.3.0–1.6.2, 2.0.0–2.5.1

鉴于 NGINX 驱动着全球约 三分之一的网站,此漏洞的爆炸半径极为巨大。


技术深入分析

两遍设计

要理解这个 bug,你需要了解 NGINX 的脚本引擎。当 NGINX 评估 rewriteset 指令时,它分 两遍 操作:

  1. 长度计算遍ngx_http_script_len_code):计算容纳最终输出所需的缓冲区总大小
  2. 拷贝遍ngx_http_script_run / ngx_http_script_copy_code):分配该大小的缓冲区并写入实际数据

契约很简单:第一遍告诉你需要分配多少字节,第二遍写入正好那么多字节。如果两者不一致——就会发生堆溢出。

根本原因:无人清理的 is_args 标志

漏洞位于 src/http/ngx_http_script.c。当 rewrite 指令的替换字符串包含 问号?)时,函数 ngx_http_script_start_args_code 会在脚本引擎上设置一个标志:

e->is_args = 1;

这个标志表明后续的 URI 组件应被视为查询参数并进行 URI 转义(例如 +%2B&%26)。

问题在于:这个标志从未被重置。它在请求处理的剩余时间内一直保持在主脚本引擎(e)上。

长度不匹配

当后续的 set 指令引用一个正则捕获组(例如 $1)时,脚本引擎会评估它。在 长度计算遍 中,ngx_http_script_complex_value_code 创建了一个 全新清零的子引擎le):

ngx_http_script_len_code_ctx_t  le;
ngx_memzero(&le, sizeof(ngx_http_script_len_code_ctx_t));

由于 le.iple.is_args 都为零,长度计算函数 ngx_http_script_copy_capture_len_code 进入了 else 分支——它返回原始的、未经转义的捕获长度。

拷贝遍 中,代码在主引擎(e)上运行,此时 e->is_args 仍为 1。拷贝函数 ngx_http_script_copy_capture_code 进入了 不同的分支

if (e->is_args) {
    // 转义 URI:将 + % & 从 1 字节扩展为 3 字节
    n = ngx_escape_uri(NULL, src, len, NGX_ESCAPE_ARGS);
    // ...分配并写入转义版本
}

攻击者控制的 URI 中每个可转义字符(+%&)从 1 字节扩展为 3 字节。缓冲区是按原始(未经转义)长度分配的——写入超出了分配边界

// 长度计算遍测得:raw_len 字节
// 拷贝遍写入:   raw_len + 2*N 字节(N = 可转义字符数)
//                  ↑↑↑  堆溢出

这是经典的 两遍契约违反,因为 is_args 状态是由一个完全不相关的 rewrite 指令设置的,且从未被清理。

利用

depthfirst 的研究人员开发了一个工作概念验证,演示了在禁用 ASLR 的情况下针对 NGINX 的 未认证 RCE。使利用变得可行的关键特性:

特性详情
溢出大小完全由攻击者控制(URI 中 +&% 的数量)
溢出数据由攻击者控制(转义后的 URI 内容)
可复现性确定性——同一请求总是以相同方式溢出
重试预算无限——崩溃的工作进程会以相同的堆布局重新生成
认证不需要——从公共互联网即可到达

无限重试预算对绕过 ASLR 特别重要。现代针对 ASLR 的利用通常需要信息泄露或暴力破解。由于 NGINX 在每次崩溃后都会以相同的堆布局生成替代工作进程,攻击者可以 无成本地尝试无限次

研究人员描述了一种理论技术:通过跨多次请求逐步覆盖指针字节,攻击者可以将执行流重定向到受控的 payload,从而在无需显式信息泄露步骤的情况下击败 ASLR。


触发条件:你受影响了吗?

只有当你的 NGINX 配置包含特定模式时,漏洞才可被触发:

# 脆弱模式:
# 1. rewrite 含有 ? 在替换中且使用未命名捕获组
# 2. 后跟同一个作用域中的另一个 rewrite、if 或 set

rewrite ^/users/([0-9]+)/profile/(.*)$ /profile.php?id=$1&tab=$2 last;

/profile.php?id=$1&tab=$2 中的 ? 设置了 is_args = 1。当后续指令评估时,未命名捕获 $1$2 会触发脆弱的代码路径。

检查你的配置

grep -rn 'rewrite.*\?.*\$[0-9]' /etc/nginx/

如果有任何匹配,你的配置就受影响。


缓解措施

立即升级

版本操作
NGINX 开源版升级至 1.31.01.30.1
NGINX Plus R36应用 R36 P4
NGINX Plus R32应用 R32 P6

临时方案:命名捕获组

如果无法立即升级,将每个受影响 rewrite 指令中的 未命名捕获 替换为 命名捕获

# 脆弱——未命名捕获与 ? 在替换中结合
rewrite ^/users/([0-9]+)/profile/(.*)$ /profile.php?id=$1&tab=$2 last;

# 缓解——命名捕获绕过脆弱的代码路径
rewrite ^/users/(?<user_id>[0-9]+)/profile/(?<section>.*)$ /profile.php?id=$user_id&tab=$section last;

命名捕获((?<name>...)不会 经过脆弱的转义逻辑,因为 ngx_http_script_copy_capture_code 函数仅对未命名捕获应用 URI 转义。这个配置更改无需二进制升级即可消除攻击面。

验证修复

# 检查版本
nginx -v

# 升级后验证:应为 1.31.0 或 1.30.1+
nginx -v 2>&1 | grep -E '1\.31\.0|1\.30\.[1-9]'

时间线

日期事件
2008 年漏洞在 NGINX 0.6.27 中引入(重写模块初始化提交)
2026 年 4 月depthfirst 自主系统扫描 NGINX 源代码,6 小时内标记堆溢出
2026-04-24F5 确认问题并协调披露
2026-05-13F5 发布 NGINX 1.31.0 / 1.30.1 修复版本;CVE-2026-42945 发布
2026-05-14本文发布

更广泛的影响:AI 发现的漏洞

CVE-2026-42945 值得关注不仅因为其严重性,还在于 它的发现方式。一个自主 AI 系统在一个被数千名工程师、安全研究员和开源贡献者在 18 年间审计过的代码库中找到了一个 bug——只用了六小时。

这延续了我们 2026 年看到的加速趋势:

漏洞发现者发现时间
Copy Fail(Linux 内核 LPE)Xint Code(AI)~1 小时
Dirty Frag(Linux 内核 LPE)人类(Hyunwoo Kim)人工审计
CVE-2026-42945(NGINX Rift)depthfirst(自主 AI)6 小时
CVE-2026-42946(NGINX 越界读)depthfirst(自主 AI)同一次扫描

一个坚定的 AI 系统能发现什么与人类审查员历史上能捕获什么之间的差距正在迅速扩大。对于关键基础设施的维护者来说,这意味着:

  1. 假设你的依赖中还有更多未发现的 bug——目前找到的那些只是当前一代 AI 工具能捕捉到的
  2. 最小化攻击面——移除未使用的模块,禁用不必要功能,使用最小功能原则
  3. 纵深防御——即使某个组件被攻破,其他层也应能限制爆炸半径

NGINX 本身是一个有趣的案例:它以代码库干净和安全记录良好而闻名。然而,一个潜伏了 18 年的严重 RCE 就藏在眼皮底下。如果 NGINX 都不能免于这类 bug,那没有 C 代码库是安全的。


结论

CVE-2026-42945(NGINX Rift)是互联网上部署最广泛的项目之一中的严重堆溢出漏洞。它不需要认证,可以从公共互联网触发,并使攻击者在 NGINX 工作进程中获得完整的代码执行能力。

如果你运行 NGINX,假设你受影响——除非你已经验证了你的配置不包含脆弱的 rewrite 模式,或者你已经升级到了 1.31.0 / 1.30.1。

这个 bug 长达 18 年的生命周期是一个鲜活的提醒:我们的基础设施是由那些从未被现代工具全面审计过的代码维系着的。AI 时代的漏洞发现才刚刚开始,我们应该期待更多——而不是更少——这样的揭露。


参考链接


信息图

NGINX Rift 堆溢出示意图

图 1:NGINX Rift——两遍缓冲区长度不匹配如何产生堆溢出

分享本页