目录

漏洞概述

2026 年 5 月 14 日,安全研究团队 DepthFirst 公布了代号为 "NGINX Rift" 的严重漏洞 CVE-2026-42945。这个隐蔽了 18 年的堆缓冲区溢出漏洞位于 NGINX 核心的 ngx_http_rewrite_module 中,CVSS 评分为 9.2(Critical)

该漏洞影响 NGINX 从 0.6.27(2008 年发布)到 1.30.0 的所有版本。只要使用 rewriteset 指令的配置即可触发,攻击者可实现未经授权的远程代码执行

更令人震惊的是——这个漏洞是 DepthFirst 的 自动安全分析系统发现的。只需一键接入 NGINX 源码,系统在 6 小时内自动扫描出 4 个内存损坏漏洞,CVE-2026-42945 只是其中最严重的一个。

根因分析:is_args 状态未正确传播

NGINX 脚本引擎的双遍处理机制

要理解这个漏洞,先要知道 NGINX 脚本引擎的工作方式。对于 rewriteset 指令的表达式,NGINX 使用两遍(two-pass)处理:

  1. 第一遍(长度计算):计算最终字符串需要的总内存大小
  2. 第二遍(数据拷贝):将实际数据写入之前分配的缓冲区

这种设计避免了多次小内存分配,但前提是两遍之间的引擎状态必须完全一致。正是这个假设被打破了。

is_args 标志的传播错误

rewrite 指令的替换字符串包含问号 ? 时,NGINX 会调用 ngx_http_script_start_args_code 函数,将脚本引擎的 e->is_args 标志设为 1:

void ngx_http_script_start_args_code(ngx_http_script_engine_t *e) { e->is_args = 1; e->args = e->pos; e->ip += sizeof(uintptr_t); }

这个标志在后续的脚本代码求值中永远不会被重置。问题出现在后续 set 指令引用正则捕获组时——它触发了 ngx_http_script_complex_value_code 函数。

关键漏洞点:在长度计算阶段,该函数使用一个完全清零的子引擎 le。因为 le.is_args = 0,长度计算函数进入 else 分支,返回未转义的原始长度。而在第二遍拷贝阶段,主引擎的 e->is_args = 1,进入 if 分支,调用 ngx_escape_uri 将每个可转义字符扩展为 3 个字节写入缓冲区。结果:分配的缓冲区太小,写入数据溢出

具体来说,长度计算函数 ngx_http_script_copy_capture_len_code

if ((e->is_args || e->quote) && (e->request->quoted_uri || e->request->plus_in_uri)) { // 返回转义后长度:raw_len + 2 * N (N = 需转义字符数) return cap[n + 1] - cap[n] + 2 * ngx_escape_uri(NULL, ..., NGX_ESCAPE_ARGS); } else { // 返回原始长度(未考虑转义后膨胀) return cap[n + 1] - cap[n]; }

子引擎中 le.is_args = 0 走 else,返回原始长度。但主引擎中 e->is_args = 1 走 if,实际写入的是转义后膨胀的数据。这个差值就是堆溢出。

利用路径:堆风水 + 伪造 cleanup 指针

DepthFirst 团队开发了一套完整的 PoC,原理如下:

  1. 跨请求堆风水:通过 POST 请求体(body)在堆上布置特定的数据结构。因为 URI 中不能包含空字节,所以利用 body 来注入伪造的 ngx_pool_cleanup_s 结构
  2. 溢出劫持 cleanup 指针:触发 rewrite+set 组合,利用堆溢出破坏相邻的 ngx_pool_t 对象的 cleanup 链表指针
  3. 函数指针重定向:将 cleanup 处理函数指向 system(),参数指向攻击者控制的命令字符串
  4. 池销毁时触发 RCE:当 NGINX 销毁内存池时,执行伪造的 cleanup handler,调用 system() 执行任意命令

PoC 在 ASLR 关闭的 Ubuntu 24.04 上测试通过。ASLR 开启时复杂度显著增加,但理论可行。

受影响版本与修复

产品受影响版本修复版本
NGINX Open Source 0.6.27 – 1.30.0 1.31.0, 1.30.1
NGINX Plus R32 – R36 R36 P4, R35 P2, R32 P6

受影响的版本跨度从 2008 年发布 0.6.27 到 2026 年的 1.30.0,覆盖了 18 年间几乎所有的主流 NGINX 部署。

紧急建议:立即升级到 NGINX 1.30.1 或 1.31.0,或确定你的配置中不使用 rewrite + set 组合(带问号的 rewrite 替换串)。详情参阅 F5 官方安全公告 K000160932

同时发现的其他三个漏洞

DepthFirst 自动系统在同一次扫描中发现了 4 个被确认的内存损坏漏洞,除了 CVE-2026-42945 外还有:

CVE严重级别CVSS模块问题类型
CVE-2026-42945 Critical 9.2 ngx_http_rewrite_module 堆缓冲区溢出 → RCE
CVE-2026-42946 High 8.3 ngx_http_scgi_module / uwsgi_module 超大内存分配(~1TB)→ 崩溃
CVE-2026-40701 Medium 6.3 ngx_http_ssl_module OCSP DNS 解析完成前连接关闭 → UAF
CVE-2026-42934 Medium 6.3 ngx_http_charset_module UTF-8 序列越界读取

防御与缓解措施

立即升级(首选)

升级到 NGINX 1.30.1 或 1.31.0(或 NGINX Plus 对应修复版本)。这是最彻底的解决方案。

# Ubuntu/Debian sudo apt update && sudo apt upgrade nginx # 验证版本 nginx -V 2>&1 | grep -oP 'nginx/\K[0-9.]+'

临时缓解措施

如果无法立即升级,检查你的 NGINX 配置中是否使用 rewriteset 指令。如果使用:

  • 确认 rewrite 替换字符串中不包含 ?(问号导致 is_args 标志置位)
  • 考虑用 return + map 替代 rewrite 组合
  • try_files 替代简单的 rewrite 逻辑
深度安全启示:CVE-2026-42945 的核心教训是两遍(two-pass)设计的固有风险——当中间状态在两个执行阶段间不一致时,就可能出现严重漏洞。使用自动安全分析工具扫描源码,是发现这类隐蔽问题的有效手段。