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 后面紧跟着另一条 rewrite、set 或 if,Nginx 会新起一个子引擎来算长度——这个子引擎不继承那个转义标记。
结果就是:第一次扫描按未转义的长度申请了内存,第二次扫描按转义后的长度往里写,直接溢出。
触发需要同时满足三个条件:
rewrite目标里带?- 用了未命名捕获组(
$1、$2这类) - 这条
rewrite后面紧跟着另一条rewrite、set或if
中招配置
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 的官方文档里到处都是。用这行命令自查一下:
nginx -T | grep -Pzo '(?s)rewrite[^;]*\?[^;]*;.*?(set|if|rewrite)\s'有输出就中了。
修复
版本在 0.6.27 到 1.30.0 之间的直接升到 1.30.1 或 1.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 还有门槛。但能修就修。
参考:
- depthfirst 研究报告:https://depthfirst.com/nginx-rift
- NIST 漏洞详情:CVE-2026-42945
潜伏了 18 年!Nginx 爆出高危漏洞 CVE-2026-42945,只需几行 rewrite 就能被搞定
https://www.zhuqiy.com/posts/cve-2026-42945-nginx/