483 字
2 分钟
2026-05-14
潜伏了 18 年!Nginx 爆出高危漏洞 CVE-2026-42945,只需几行 rewrite 就能被搞定
加载中...
加载中...

安全研究机构 depthfirst 上周发了篇报告,漏洞在 ngx_http_rewrite_module 里,就是天天写伪静态用的那个 rewrite 模块。从 2008 年引入到现在,18 年。

怎么触发#

漏洞本质是堆缓冲区溢出,根源在 Nginx 处理 rewrite 规则时会跑两次扫描:第一次算替换后字符串的长度,申请内存;第二次把数据实际写进去。

问题出在 rewrite 目标带 ? 的时候。主引擎会打一个标记,意思是后续写入时要对参数做 URL 转义,一个字符可能膨胀成 3 个字节。但如果这条 rewrite 后面紧跟着另一条 rewritesetif,Nginx 会新起一个子引擎来算长度——这个子引擎不继承那个转义标记。

结果就是:第一次扫描按未转义的长度申请了内存,第二次扫描按转义后的长度往里写,直接溢出。

触发需要同时满足三个条件:

  1. rewrite 目标里带 ?
  2. 用了未命名捕获组($1$2 这类)
  3. 这条 rewrite 后面紧跟着另一条 rewritesetif

中招配置#

location / {
rewrite ^/frim/index(.+?)\.html$ /list/index.php?$1 last;
rewrite ^/play/([0-9]+)-([0-9]+)-([0-9]+)\.html$ /video/index.php?$1-$2-$3 last;
rewrite ^/topic/index\.html$ /topic/index.php?$1 last;
}

这种几条 rewrite 堆在一起带参数传递的写法,各类 CMS 的官方文档里到处都是。用这行命令自查一下:

Terminal window
nginx -T | grep -Pzo '(?s)rewrite[^;]*\?[^;]*;.*?(set|if|rewrite)\s'

有输出就中了。

修复#

版本在 0.6.271.30.0 之间的直接升到 1.30.11.31.0。魔改版的追社区补丁。

升不了的话,把堆在一起的 rewrite 拆进各自独立的 location

# 改之前
location / {
rewrite ^/play/([0-9]+)\.html$ /video.php?$1 last;
rewrite ^/news/([0-9]+)\.html$ /news.php?$1 last;
}
# 改之后
location ~ ^/play/([0-9]+)\.html$ {
rewrite ^ /video.php?$1 last;
}
location ~ ^/news/([0-9]+)\.html$ {
rewrite ^ /news.php?$1 last;
}

或者换用 try_files

现代系统有 ASLR,溢出大概率只是把 worker 进程打死,想打到 RCE 还有门槛。但能修就修。


参考:


潜伏了 18 年!Nginx 爆出高危漏洞 CVE-2026-42945,只需几行 rewrite 就能被搞定
https://www.zhuqiy.com/posts/cve-2026-42945-nginx/
作者
ZHUQIY
发布于
2026-05-14
许可协议
CC BY-NC-SA 4.0