CVE-2026-42945(NGINX Rift):潜伏18年的NGINX远程代码执行漏洞分析与防御指南
披露时间:2026-05-13
危害等级:🔴 Critical(严重)
CVSS 评分:9.2(CVSS 4.0)/ 8.1(CVSS 3.1)
漏洞类型:堆缓冲区溢出(CWE-122)
影响历史:18 年(自 2008 年 NGINX 0.6.27 起)
一、漏洞概述
2026 年 5 月 13 日,F5 与 NGINX 官方发布了一则令全球运维人员警醒的安全通告:CVE-2026-42945,被安全社区命名为 “NGINX Rift”。这是一个潜伏在 ngx_http_rewrite_module(重写模块)中长达 18 年 的堆缓冲区溢出漏洞。
该漏洞由 AI 安全分析系统(depthfirst)在代码审计中自主发现,并于 2026 年 4 月报告给 F5 官方。经确认,这是一个无需认证即可远程触发的内存破坏漏洞,攻击者仅需发送一个精心构造的 HTTP 请求,就能导致 NGINX worker 进程崩溃,甚至在特定条件下实现远程代码执行(RCE)。
二、触发条件:你的配置中招了吗?
这个漏洞并非”有 NGINX 就必中招”,而是需要满足四个特定配置条件的组合:
| 条件 | 说明 |
|---|---|
1. rewrite 指令 | 使用了正则重写 |
| 2. 未命名捕获 | 替换字符串中包含 $1、$2 等未命名 PCRE 捕获组 |
3. 问号 ? | 替换字符串中包含问号(用于拼接 query string) |
| 4. 后续指令 | 同一上下文中紧随其后存在 rewrite、if 或 set 指令 |
典型 vulnerable 配置示例
location /api/ {
# ❌ 危险模式:$1 + ? + 后续 set/rewrite/if
rewrite ^/api/(.+)$ /index.php?route=$1 last;
set $var $1; # ← 触发点:后续的 set 指令
# 或者 if/rewrite 也会触发
}
这种配置在基于 NGINX + PHP 的框架(如 Laravel、Symfony、WordPress 的伪静态规则)中极为常见,使得大量存量服务器面临风险。
三、技术原理:为什么一个”?”能导致 RCE?
NGINX 的脚本引擎在处理 rewrite 指令时采用两阶段(Two-Pass)架构:
- 长度计算阶段:先遍历所有变量和字面量,计算最终字符串需要的缓冲区大小。
- 数据复制阶段:分配内存后,将实际数据写入缓冲区。
根因:is_args 标志的状态不一致
当 rewrite 替换字符串包含 ? 时,NGINX 会调用 ngx_http_script_start_args_code() 函数,将主引擎的 e->is_args 标志置为 1。这个标志的作用是告诉引擎:“当前正在构造 query string,需要对特殊字符进行 URL 转义。”
然而,在长度计算阶段,引擎使用的是一个全新初始化的子引擎(le),其 is_args 被初始化为 0。这导致:
- 长度计算:看到
is_args = 0,认为不需要转义,按原始字节长度分配缓冲区。 - 数据复制:主引擎的
is_args = 1,实际写入时调用ngx_escape_uri()进行NGX_ESCAPE_ARGS转义,将+、%、&等特殊字符从 1 字节扩展为 3 字节(百分号编码)。
结果就是:分配了更小的缓冲区,却写入了更多的数据——经典的堆缓冲区溢出。
攻击者可控的内存破坏
更危险的是,溢出的数据来源于攻击者可控的 URI。攻击者可以通过构造包含大量需转义字符的 URL,精确控制溢出内容。在 ASLR(地址空间布局随机化)关闭的系统上,这可以直接转化为远程代码执行;即使在 ASLR 开启的现代系统上,也能通过堆风水(Heap Feng Shui)技术实现利用。
四、影响范围
开源版 NGINX
| 受影响版本 | 修复版本 |
|---|---|
| 0.6.27 ~ 1.30.0 | 1.31.0(主线版)< 1.30.1(稳定版) |
商业版 NGINX Plus
| 受影响版本 | 修复版本 |
|---|---|
| R32 ~ R36 | R36 P4 / R35 P2 / R32 P6 |
关联组件
- NGINX Instance Manager(2.16.0 ~ 2.21.1)
- F5 WAF for NGINX(5.9.0 ~ 5.12.1)
- NGINX Ingress Controller、Gateway Fabric 等基于 NGINX 内核的产品
五、利用与风险
攻击门槛
- 无需认证:攻击者无需任何账号或权限。
- 远程触发:仅需发送一个特制 HTTP 请求。
- PoC 已公开:GitHub 上已有完整的利用代码(
DepthFirstDisclosures/Nginx-Rift),包含 Docker 测试环境和一键弹 Shell 脚本。
攻击后果
| 场景 | 结果 |
|---|---|
| 常规情况(ASLR 开启) | Worker 进程崩溃,主进程自动重启,造成拒绝服务(DoS)。多 worker 环境下表现为间歇性服务中断,单 worker 环境下服务完全离线。 |
| ASLR 关闭/弱化环境 | 可实现远程代码执行,以 NGINX worker 进程权限(通常为 nginx/www-data)运行任意命令。 |
| 容器/Docker 环境 | 若容器以 root 运行,RCE 后果更为严重。 |
六、紧急自查:5 分钟快速检测
如果你无法立即升级,请先用以下方法自查是否存在 vulnerable 配置:
方法一:grep 快速扫描
# 扫描所有 nginx 配置文件,查找危险模式
sudo grep -RnE 'rewrite[[:space:]].*\$[0-9].*\?' /etc/nginx/
这条命令会匹配包含未命名捕获($1/$2)且包含 ? 的 rewrite 行。命中结果需要人工复核是否后续有 rewrite/if/set 指令。
方法二:审计配置模式
重点检查以下高危配置模板:
# ❌ 高危模式 1:PHP 框架常见伪静态
rewrite ^/users/([0-9]+)/profile/(.*)$ /profile.php?id=$1&tab=$2 last;
set $var $1;
# ❌ 高危模式 2:带 query string 的 API 路由
rewrite ^/api/v1/(.*)$ /api.php?path=$1? last;
if ($request_method = POST) { ... }
# ❌ 高危模式 3:多重 rewrite 链
rewrite ^/old/(.*)$ /new/$1?redirect=1 last;
rewrite ^/new/(.*)$ /index.php?page=$1 last;
方法三:验证当前版本
nginx -v
# 若版本在 0.6.27 ~ 1.30.0 之间,则存在漏洞风险
七、修复方案
方案一:立即升级(强烈推荐 ⭐)
这是最根本、最安全的解决方案。官方已发布补丁版本:
| 产品线 | 安全版本 |
|---|---|
| NGINX 开源主线版 | 1.31.0 |
| NGINX 开源稳定版 | 1.30.1 |
| NGINX Plus | R37+ 或对应补丁版本 |
平滑升级命令示例(基于源码编译用户):
# 1. 备份配置
cp /usr/local/nginx/conf/nginx.conf /usr/local/nginx/conf/nginx.conf.bak
# 2. 下载新版
wget https://nginx.org/download/nginx-1.31.0.tar.gz
tar -zxvf nginx-1.31.0.tar.gz
cd nginx-1.31.0
# 3. 使用与原版本相同的编译参数
./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_v2_module [你的其他参数...]
make
# 4. 平滑热升级(不中断服务)
make upgrade
# 或手动:
# kill -USR2 `cat /usr/local/nginx/logs/nginx.pid`
# kill -WINCH `cat /usr/local/nginx/logs/nginx.pid.oldbin`
# kill -QUIT `cat /usr/local/nginx/logs/nginx.pid.oldbin`
包管理器用户:
- AlmaLinux/RHEL/CentOS:测试仓库已推送补丁包,可通过
dnf upgrade nginx获取。 - Ubuntu/Debian:关注官方安全更新通道。
- Docker:拉取
nginx:1.31.0或nginx:1.30.1镜像重建容器。
方案二:临时配置缓解(无法立即升级时)
如果业务窗口不允许立即升级,可通过修改配置临时规避。只需破坏四个触发条件中的任意一个即可:
缓解措施 A:改用命名捕获(推荐)
将 $1、$2 等未命名捕获改为 PCRE 命名捕获,这可以完全绕过漏洞代码路径:
# ❌ 改造前(危险)
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;
缓解措施 B:重构指令顺序
避免在 rewrite + ? 之后紧跟 set/if/rewrite。可以通过拆分 location 或调整逻辑来隔离:
# ❌ 危险:rewrite 和 set 在同一 location
location /api/ {
rewrite ^/api/(.+)$ /index.php?route=$1 last;
set $var $1;
}
# ✅ 安全:将 set 移出或重构
location /api/ {
rewrite ^/api/(.+)$ /index.php?route=$1 last;
}
location @backend {
# set 操作放在此处,不直接跟在 rewrite 后
}
缓解措施 C:移除问号(如果业务允许)
如果 rewrite 不需要拼接 query string,移除 ? 及其后的内容:
# 如果不需要传递参数,可改为:
rewrite ^/api/(.+)$ /index.php last;
修改后务必验证配置并重载:
sudo nginx -t
sudo systemctl reload nginx
八、漏洞时间线与发现背景
| 时间 | 事件 |
|---|---|
| 2008 年 | 漏洞代码随 NGINX 0.6.27 引入 |
| 2026 年 4 月 | depthfirst AI 安全分析系统自主发现漏洞 |
| 2026-04-24 | F5 官方确认漏洞报告 |
| 2026-05-13 | 协调披露日:发布 CVE-2026-42945,同步上线 1.31.0 / 1.30.1 |
| 2026-05-13 至今 | PoC 公开,全球自动化扫描器开始索引脆弱目标 |
值得注意的是,这是AI 自主代码审计发现重大 0day 漏洞的标志性案例之一。depthfirst 的系统在”单次点击” onboarding NGINX 源码后,自主发现了包括 CVE-2026-42945 在内的 4 个内存破坏漏洞。
九、总结与行动清单
CVE-2026-42945 是一个典型的**“配置即攻击面”**漏洞。它提醒我们:即使是最成熟、最广泛部署的基础软件,也可能隐藏着长达数十年的逻辑缺陷。
立即行动清单
- 1. 版本排查:运行
nginx -v,确认是否在 0.6.27 ~ 1.30.0 范围内。 - 2. 配置扫描:执行
grep -RnE 'rewrite[[:space:]].*\$[0-9].*\?' /etc/nginx/查找危险模式。 - 3. 制定升级计划:优先安排升级到 1.31.0 或 1.30.1,这是唯一彻底的修复方式。
- 4. 临时加固:若无法立即升级,将未命名捕获
$1/$2改为命名捕获(?<name>...)。 - 5. 监控告警:关注 WAF/IDS 告警,留意异常的 HTTP 请求模式。
- 6. 容器检查:排查基于旧版 NGINX 的 Docker 镜像和 Kubernetes Ingress Controller。
参考资源
⚠️ 免责声明:本文仅供安全研究和防御参考,请勿将 PoC 或利用技术用于非法用途。请立即升级你的 NGINX 实例,保护你的服务与用户数据安全。
撃っていいのは撃たれる覚悟のあるヤツだけだ。