Hotdry.

Article

Nginx RIFT CVE-2026-42945 漏洞根因解析与利用检测实战

深入剖析 Nginx rewrite 模块中隐藏 18 年的堆缓冲区溢出漏洞,提供 exploit 向量识别、检测规则与可落地缓解参数。

2026-05-14security

Nginx RIFT(CVE-2026-42945)是一个在 ngx_http_rewrite_module 中潜伏了近 18 年的堆缓冲区溢出漏洞。攻击者只需发送一个精心构造的 HTTP 请求,即可触发确定性内存损坏,在无需认证的情况下实现远程代码执行或造成 worker 进程崩溃。此漏洞影响范围极广,覆盖 Nginx Open Source 0.6.27 至 1.30.0、NGINX Plus R32 至 R36,以及基于 Nginx 的众多网关与 Ingress 产品。鉴于该漏洞已公开披露且利用门槛较低,安全团队急需理解其根因、掌握 exploit 向量特征,并部署有效的检测与缓解措施。

漏洞根因:C 语言脚本引擎的双阶段计算错位

理解漏洞根因对于制定精准检测策略至关重要。Nginx 的 rewrite 指令由 src/http/ngx_http_script.c 中的脚本引擎处理,该引擎采用两阶段执行模式:首先计算需要分配的内存大小,然后执行实际的数据写入。这两个阶段必须在所有边界条件上保持严格一致,否则就会产生缓冲区溢出。问题恰恰出在这个一致性的微妙破坏上。

当 rewrite 指令的替换字符串包含问号时,ngx_http_script_start_args_code 函数会设置 e->is_args = 1 标志,但关键问题在于:这个标志从未被清除。此后的 set 指令在计算缓冲区长度时,会创建一个全新的零初始化子引擎来执行测量,此时 is_args 标志为初始状态,ngx_http_script_copy_capture_len_code 测量的是捕获组的原始字节长度。然而,当实际执行数据复制时,代码使用的是主引擎,而主引擎的 is_args 标志仍然保持为 1,导致 ngx_http_script_copy_capture_code 再次通过 ngx_escape_uriNGX_ESCAPE_ARGS 模式下进行转义处理。每当捕获组中包含加号(+)、百分号(%)或与号(&)时,对应的字节数就会膨胀两倍。分配缓冲区时按照原始长度计算,实际写入时却写入了膨胀后的更多数据,堆溢出就此发生。

这种设计缺陷的危险性在于其确定性:攻击者可以精确控制溢出数据的内容和大小,而非依赖随机内存布局。这为可靠的全链利用创造了条件。值得注意的是,Nginx 的多进程架构反而助长了这一漏洞的利用:worker 崩溃后 master 进程会立即重启,新 worker 的堆布局与之前一致,攻击者可以无限次重试而无需承担任何代价。

利用向量分析:识别危险配置模式

并非所有使用 rewrite 指令的 Nginx 配置都受此漏洞影响。漏洞触发需要满足特定的配置模式组合,理解这些模式是制定检测规则的前提。

第一个必要条件是使用未命名正则捕获组。在 rewrite 指令中捕获 URI 片段时,开发者通常使用 $1$2 等未命名变量来引用捕获内容。例如 rewrite ^/users/([0-9]+)/profile/(.*)$ /profile.php?id=$1&tab=$2 last; 中,([0-9]+) 捕获用户 ID,(.*) 捕获资料页面路径,这些捕获通过 $1$2 引用到替换目标 URL 中。

第二个必要条件是替换字符串中包含问号。问号在 HTTP URL 中用于分隔路径与查询字符串,Nginx 的 rewrite 引擎会将问号视为查询参数的开始标记,这正是触发 ngx_http_script_start_args_code 设置 is_args = 1 标志的入口点。

第三个必要条件是后续指令链中存在 rewrite、if 或 set 指令的再次处理。仅仅有一条包含问号替换的 rewrite 指令不足以触发漏洞;必须存在后续指令再次处理捕获组引用,才能复现两阶段计算的不一致。上例中的 rewrite ... /profile.php?id=$1&tab=$2 last; 本身就包含多个 $1$2 引用,后续的内部跳转或条件判断会触发第二次处理。

综合来看,最典型的危险模式可描述为:在同一 server 或 location 块内,存在使用未命名捕获组 $1$2 等的 rewrite 指令,其替换目标 URL 中包含问号(用于构造查询参数),并且存在后续的 rewrite、if 或 set 指令对这些捕获组进行二次处理。这个模式在动态路由、用户个人主页、多级路径重写等常见业务场景中极为普遍。

检测策略:从配置审计到流量监控

有效的检测需要多层次部署,在漏洞窗口期内最大化发现利用尝试的概率。以下三个层次相互补充,构成纵深检测体系。

第一层:配置审计与风险定位

在流量监控之前,首要任务是梳理内网所有 Nginx 实例的配置,识别哪些处于危险模式。这一步骤的价值在于将被动检测转化为主动排查,优先处理最可能暴露在互联网的节点。

使用以下命令或脚本扫描配置文件,定位包含未命名捕获组且替换字符串含问号的 rewrite 指令:

# 在 Nginx 配置目录递归搜索危险 rewrite 模式
grep -rn --include="*.conf" 'rewrite.*\$\([0-9]\+.*?' /etc/nginx/
grep -rn --include="*.conf" 'rewrite.*\$\([^*]*\).*?' /etc/nginx/

# 更精确的检测:提取 rewrite 行并分析
find /etc/nginx -name "*.conf" -exec cat {} \; | grep -E 'rewrite\s+\^.*\$\s+.*\?' | grep -E '\$\d+'

同时检查 Nginx 版本,确认是否处于受影响范围:

nginx -v
# 受影响版本:0.6.27 至 1.30.0(Open Source)
# 受影响版本:R32 至 R36(Plus)

对于使用容器编排的环境,批量检查命令可能为:

# 检查所有运行中容器的 Nginx 版本与配置
docker ps --format "{{.Names}}" | xargs -I {} docker exec {} nginx -v 2>&1
kubectl get pods -o jsonpath='{.items[*].spec.containers[*].name}' | tr ' ' '\n' | xargs -I {} kubectl exec deploy/{} -- nginx -v 2>&1

第二层:流量特征检测与日志分析

在完成配置审计后,需要在流量层面部署检测规则,识别正在发生的利用尝试。攻击者发送的请求通常具有以下可观测特征:

请求 URI 中包含与已知危险 rewrite 模式匹配的正则路径。例如,如果配置中存在 rewrite ^/users/([0-9]+)/profile/(.*)$ /profile.php?id=$1&tab=$2 last;,攻击者的探测请求会形如 /users/12345/profile/somepage,其中 12345 填充用户 ID 捕获组,路径中还会包含需要转义的特殊字符如 %2B(加号的 URL 编码)或 %25(百分号本身),以触发溢出条件。

因此,流量检测应聚焦于:包含 %2B%26%2F(URL 编码的特殊字符)的请求,且这些请求命中包含上述危险 rewrite 配置的路径。WAF 或 IDS 规则可参考以下逻辑编写:

# 检测针对含 $1/$2 类未命名捕获 rewrite 的探测
# 条件:请求命中 /users/\d+/profile/.* 路径 且 包含编码字符
alert http any any -> $HOME_NET $HTTP_PORTS (msg:"NGINX RIFT CVE-2026-42945 exploit probe detected"; \
  flow:established,to_server; \
  http.uri; pcre:"/\/users\/[0-9]+\/profile\/.*/"; \
  http.uri; pcre:"/(%2B|%26|%25|%2F)+/"; \
  sid:20264501; rev:1;)

Nginx 访问日志和错误日志同样重要。当漏洞被触发时,worker 进程可能出现异常行为:大量 500 状态码与特定请求模式相关联、worker 进程频繁重启、以及错误日志中出现堆相关的不完整信息(如果启用了详细日志)。建议配置日志告警规则,当特定路径的 500 错误率出现异常峰值时触发告警:

# 统计单位时间内特定路径的 500 错误数量
awk '$9 == 500 && $7 ~ /\/users\/[0-9]+\/profile\// {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

第三层:主机层进程监控与异常检测

在应用层检测之外,主机层监控可以发现更隐蔽的利用迹象。堆缓冲区溢出在成功利用前通常会经历多次试探,worker 进程的内存使用量可能出现异常模式。

监控 worker 进程的生命周期和重启频率:systemctl status nginx 或进程管理接口可暴露异常的 worker 重启行为。若单个 server 块的 rewrite 漏洞被反复利用,master 进程会不断 fork 新 worker,对应的主机资源消耗模式会显著偏离正常基线。

启用并检查核心转储(core dump):如果在漏洞曝光后的短期内需要对历史可疑事件进行事后分析,检查 /var/crash 或配置的核心转储目录,定位崩溃的 worker 进程并分析其堆状态。AddressSanitizer(ASan)构建的 Nginx 可以输出详细的堆损坏信息,但这类构建不应在生产环境长期运行。

缓解策略:紧急修复与配置加固

升级路径:首选方案

应对此漏洞的最优解是升级到修复版本。F5 已在协调披露中发布补丁,修复版本如下:

产品 修复版本
Nginx Open Source 1.31.0 或 1.30.1
Nginx Plus R36 R36 P4
Nginx Plus R32 R32 P6
Nginx Instance Manager 迁移至含修复的分支
Nginx Gateway Fabric 迁移至含修复的分支
Nginx Ingress Controller 迁移至含修复的分支

升级后必须重启 Nginx,确保所有 worker 进程加载修复后的二进制文件:

# Debian/Ubuntu
apt-get update && apt-get install nginx
nginx -v && systemctl restart nginx

# RHEL/CentOS
yum update nginx
nginx -v && systemctl restart nginx

配置加固:无法立即升级时的替代方案

若因业务连续性约束无法立即执行升级,可通过修改配置消除漏洞触发条件。此方案的核心思路是将所有未命名捕获组替换为命名捕获组,因为命名捕获不会经过 ngx_escape_uri 的危险路径。

危险配置示例(应立即修复):

location /users {
    rewrite ^/users/([0-9]+)/profile/(.*)$ /profile.php?id=$1&tab=$2 last;
    # 后续 rewrite、if 或 set 指令会触发漏洞
}

修复后配置:

location /users {
    rewrite ^/users/(?<user_id>[0-9]+)/profile/(?<section>.*)$ /profile.php?id=$user_id&tab=$section last;
    # 命名捕获 $user_id 和 $section 不经过危险的 is_args 逻辑
}

使用正则测试工具验证配置变更不影响业务逻辑,然后重新加载配置:

nginx -t && systemctl reload nginx

临时缓解:网络层隔离

在等待修复或配置变更生效期间,可实施以下临时缓解措施:将存在漏洞的 location 块从公网访问范围移除,或通过 ACL 限制只有可信 IP 可访问相关路径;使用七层防火墙规则对包含 URL 编码特殊字符的可疑请求进行初步过滤;考虑在负载均衡层暂时摘除高风险节点,待修复后再重新上线。

漏洞影响范围评估与优先级矩阵

制定修复计划时,需要根据业务影响范围和暴露程度确定优先级。以下矩阵提供了评估框架:

高优先级场景包括:直接暴露在互联网且运行受影响版本 Nginx 的业务;配置中明确存在危险 rewrite 模式的 API 网关或 Web 服务;使用 Nginx Ingress Controller 的 Kubernetes 集群且版本处于受影响范围。

中优先级场景包括:内部系统但 Nginx 版本受影响的静态资源服务;使用了危险 rewrite 模式但访问路径较深的辅助服务。

低优先级场景包括:历史遗留的 Nginx 实例但已不再处理请求的废弃节点;配置中不存在危险 rewrite 模式的服务。

对于使用了 Nginx App Protect WAF 或 F5 WAF 的用户,这些安全产品本身处于受影响版本范围内,但它们的策略引擎可能在检测针对后端服务的利用尝试时仍能发挥作用,前提是 WAF 自身已升级到修复版本。

总结:检测与响应的关键要点

Nginx RIFT 漏洞的危险性源于三个因素的叠加:代码缺陷的存在时间极长(18 年)、利用条件相对宽松(无需认证)、影响范围极广(覆盖主流版本)。安全团队应以本次披露为契机,加速推进 Nginx 版本的统一管理,并在配置层面建立 rewrite 指令的安全编码规范。

检测策略应遵循分层部署原则:配置审计层负责定位风险资产,优先处理高暴露节点;流量监控层部署 exploit 特征检测,重点关注包含 URL 编码特殊字符且命中危险 rewrite 路径的请求;主机监控层追踪 worker 进程行为异常和崩溃事件。缓解措施中,升级到 1.31.0 或 1.30.1 是首选方案;若升级窗口期较长,配置层面的命名捕获改造可在短期内消除漏洞触发条件。两种方案并非互斥,配置加固可与升级并行推进,为防御深度增加冗余。


参考资料

security

内容声明:本文无广告投放、无付费植入。

如有事实性问题,欢迎发送勘误至 i@hotdrydog.com