CVE-2026-42945 NGINX RCE漏洞实战排查:检测脚本+加固配置全清单

📅 2026/6/19 17:07:08
CVE-2026-42945 NGINX RCE漏洞实战排查:检测脚本+加固配置全清单
早上九点刚坐工位上安全群就弹了满屏红消息。CVE-2026-42945NGINX rewrite模块堆溢出未授权远程RCECVSS 9.2。我手里管着二十多台公网NGINX节点三套生产K8s集群的Ingress全是Nginx Ingress Controller当时脑子第一反应不是去挖原理是先确认两件事我线上的机器会不会被打穿有没有办法十分钟内扫完所有节点当天从排查到整改完花了三个多小时踩了好几个坑比如有些rewrite藏在Ingress的annotation里差点漏扫比如系统自带源的NGINX版本根本没更到修复版。这篇把完整流程全整理出来从漏洞判定、一键检测、分级加固到入侵排查所有脚本和配置都能直接复制用运维和安全岗的朋友拿过去就能落地。漏洞真实影响边界别看到全版本就慌很多人一看到“全版本影响”就直接全量推升级最后业务出故障得不偿失。这个漏洞不是装了受影响版本就一定会被RCE三个触发条件缺一个攻击者都拿不到执行权限。漏洞出在ngx_http_rewrite_module就是我们天天用的rewrite重写模块。NGINX处理一条rewrite规则的时候分两步走第一步预计算内存长度只按原始字符串的字节数申请堆内存。第二步真正往缓冲区里写数据的时候如果替换的目标字符串里带问号?NGINX会自动对正则捕获组的内容做URL转义。比如一个特殊字符#转义后会变成%231个字节直接膨胀成3个字节。预计算的时候没把转义膨胀的部分算进去缓冲区开小了写数据的时候直接越界写到相邻的堆内存里形成堆缓冲区溢出。攻击者只要构造一串带特殊字符的URI让NGINX匹配到危险rewrite规则就能控制溢出的内容。轻则打崩worker进程让网站直接502重则泄露内存里的敏感数据比如会话令牌、配置密钥如果系统没开ASLR甚至能稳定执行任意代码直接接管服务器。CVE-2026-42945漏洞触发流程攻击者构造恶意URI → NGINX匹配rewrite规则 → 按原始长度申请堆缓冲区 → URL转义后数据溢出 → 篡改堆内存 → 触发DoS或RCE。三个必要触发条件必须同时满足才能实现RCENGINX版本在受影响范围内rewrite规则的替换字符串中包含问号?rewrite使用$1、$2这类未命名正则捕获组且当前rewrite指令后紧跟rewrite、if、set指令这里划重点很多老版本NGINX配置里根本没有带问号的rewrite也不用捕获组传参最多存在理论DoS风险完全不用担心被远程拿权限。不用看到漏洞预警就连夜升级把业务搞挂。完整影响版本范围开源NGINX受影响版本从0.6.27一直覆盖到1.30.0前后跨度接近20年几乎是NGINX诞生以来的全量版本。官方已经发布修复的稳定版为1.24.1、1.26.4、1.30.1主线开发版1.31.0及以上也自带修复。补个实战提醒别全信nginx -v输出来的版本号。很多厂商的定制化NGINX会修改版本字符串尤其是云厂商的网关产品。最稳妥的方式是结合配置扫描本地PoC验证不要只靠版本号下结论。NGINX Plus商业版R32到R36的全版本受影响对应修复补丁为R32 P6、R36 P4用商业版的直接找F5官方拿补丁包就行。衍生生态产品所有基于开源NGINX二次开发的组件都受波及。比如大家常用的Nginx Ingress Controller1.14.4及之前的版本底层NGINX都带这个漏洞还有NGINX Instance Manager、App Protect WAF、Gateway Fabric这些产品对应旧版本全部需要更新。尤其是K8s环境很多人只会查宿主机的NGINX忘了集群里的Ingress控制器这是最容易漏的点。全场景排查实操附可直接运行的检测脚本我把排查拆成了两步走先查版本圈定风险范围再扫配置确认利用可能。两种场景的脚本都整理好了单机和K8s集群都能直接用。单机物理机/虚拟机排查第一步版本快速校验直接执行这几条命令就能拿到当前NGINX的版本和编译信息。# 查看主版本号nginx-v# 查看完整编译参数确认rewrite模块是否启用默认都内置nginx-V# RPM系CentOS/RHEL/Rocky查安装包rpm-qa|grepnginx# DEB系Ubuntu/Debian查安装包dpkg-l|grepnginx输出的版本号如果低于1.30.1就属于受影响版本范围继续往下扫配置。第二步高危rewrite配置扫描这一步是核心直接决定你的机器会不会被RCE。我写了个一键扫描脚本自动定位NGINX配置目录递归扫描所有.conf文件匹配符合触发条件的rewrite规则最后直接输出风险判定结果。#!/bin/bash# CVE-2026-42945 NGINX高危配置检测脚本# 功能递归扫描所有NGINX配置识别可触发RCE的rewrite规则echo CVE-2026-42945 高危配置检测 echo检测规则: rewrite 未命名捕获组(\$1/\$2) 替换串含问号(?)echo-----------------------------------------# 自动识别NGINX配置根目录NGINX_BIN$(whichnginx2/dev/null)if[-n$NGINX_BIN];thenCONF_PATH$(nginx-V21|grep-oPconf-path\K[^ ])NGINX_CONF_DIR$(dirname$CONF_PATH)elseNGINX_CONF_DIR/etc/nginxecho[提示] 未检测到nginx命令使用默认配置路径: /etc/nginxfiif[!-d$NGINX_CONF_DIR];thenecho[错误] 配置目录不存在请手动指定路径后重试exit1fiecho配置根目录:$NGINX_CONF_DIRecho正在扫描配置文件...echo-----------------------------------------# 统计风险项TOTAL_FILES0RISK_FILES0RISK_RULES0whileIFSread-rconf_file;doTOTAL_FILES$((TOTAL_FILES1))# 匹配危险rewrite规则matches$(grep-nErewrite[[:space:]].*\$[0-9].*\?$conf_file2/dev/null)if[-n$matches];thenRISK_FILES$((RISK_FILES1))echo-e\n[高危] 配置文件:$conf_fileecho$matches# 统计规则条数rule_count$(echo$matches|wc-l)RISK_RULES$((RISK_RULESrule_count))fidone(find$NGINX_CONF_DIR-typef-name*.conf)echoecho-----------------------------------------echo扫描完成共扫描$TOTAL_FILES个配置文件echo发现高危配置文件:$RISK_FILES个危险rewrite规则:$RISK_RULES条echo# 风险判定if[$RISK_RULES-gt0];thenecho风险等级: 高危 | 存在可被RCE利用的配置请立即整改elseecho风险等级: 低危 | 未发现高危rewrite规则仅存在理论DoS风险fi脚本用法很简单保存成cve-2026-42945-check.sh加执行权限直接跑就行chmodx cve-2026-42945-check.sh ./cve-2026-42945-check.sh我当天扫自己的环境光一个业务站点的配置就找出5条高危规则全是之前开发图省事写的rewrite ^/(.*)$ /index.php?path$1 last这种写法。典型的高危配置样例长这样location / { rewrite ^/(.*)$ /index.php?route$1 break; set $uri_new $uri; }这条规则三个触发条件全中替换串带问号用了$1未命名捕获组rewrite后面紧跟了set指令。攻击者只要构造带特殊字符的URI访问任意路径就能触发堆溢出。K8s集群批量排查K8s环境是重灾区很多人只管节点上的组件忘了Ingress控制器。而且Ingress的rewrite规则很多是写在annotation的configuration-snippet里分散在各个命名空间人工查根本查不过来。同样给大家一个批量扫描脚本一键拉取全集群所有Ingress的配置片段识别危险rewrite规则。#!/bin/bash# K8s Nginx Ingress CVE-2026-42945 批量检测脚本# 依赖: kubectl、jqecho K8s Nginx Ingress 漏洞检测 echo----------------------------------------echo[1/2] 检测Ingress控制器镜像版本# 尝试常见的ingress命名空间fornsiningress-nginx nginx-ingress ingress;dopods$(kubectl get pods-n$ns-lapp.kubernetes.io/nameingress-nginx-ojsonpath{.items[*].spec.containers[0].image}2/dev/null)if[-n$pods];thenecho命名空间:$nsecho镜像版本:$podsbreakfidoneechoecho[2/2] 扫描所有Ingress的危险rewrite配置echo----------------------------------------# 扫描configuration-snippet中的危险rewritekubectl get ingress --all-namespaces-ojson2/dev/null|jq-r .items[] | .metadata.namespace as $ns | .metadata.name as $ingress | .metadata.annotations | if .[nginx.ingress.kubernetes.io/configuration-snippet] then .[nginx.ingress.kubernetes.io/configuration-snippet] as $snippet | if ($snippet | gsub(\n; ) | test(rewrite[[:space:]].*\\$[0-9].*\\?)) then [高危] 命名空间: $ns | Ingress: $ingress\n危险配置片段:\n$snippet\n else empty end else empty end echoecho扫描完成脚本依赖kubectl和jq跑之前先确认环境里有这两个工具。踩个坑提醒有些公司会用server-snippet或者location-snippet注入rewrite规则上面的脚本只查了configuration-snippet。如果你们环境有其他注入方式记得对应加扫描规则别漏了。NGINX漏洞全场景排查流程获取资产清单 → 版本校验 → 配置扫描 → 风险分级高危/低危 → 对应处置路径升级改配置/仅升级/观察。分级加固方案按业务场景选对应方案排查完风险接下来就是修复。我按优先级分了三层大家根据自己的业务停机窗口选能升级的优先升级不能升级的先上临时缓解。第一层版本升级永久修复这是官方推荐的最彻底方案直接从根源补上内存计算的逻辑漏洞。Debian / Ubuntu 系列先加NGINX官方源系统自带的universe源通常更新很慢很多时候拿不到最新的修复版。# 安装依赖sudoaptinstallcurlgnupg2 ca-certificates lsb-release ubuntu-keyring# 导入官方GPG密钥curlhttps://nginx.org/keys/nginx_signing.key|gpg--dearmor|sudotee/usr/share/keyrings/nginx-archive-keyring.gpg/dev/null# 添加官方稳定版源echodeb [signed-by/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/ubuntu$(lsb_release-cs)nginx|sudotee/etc/apt/sources.list.d/nginx.list# 设置源优先级优先用官方源echo-ePackage: *\nPin: origin nginx.org\nPin: Release onginx\nPin-Priority: 900\n|sudotee/etc/apt/preferences.d/99nginx然后执行升级sudoaptupdatesudoaptinstallnginx升级完校验版本再检查配置最后平滑重载nginx-vnginx-tsystemctl reload nginxCentOS / RHEL / Rocky 系列同样先加官方源# 创建yum源配置cat/etc/yum.repos.d/nginx.repoEOF [nginx-stable] namenginx stable repo baseurlhttp://nginx.org/packages/centos/$releasever/$basearch/ gpgcheck1 enabled1 gpgkeyhttps://nginx.org/keys/nginx_signing.key module_hotfixestrue EOF然后升级dnf update nginx-y# 老版本用yumyum update nginx-y源码编译安装场景如果是自己编译的NGINX直接下载对应版本的源码用原来的编译参数重新编译替换就行。记得先备份旧的二进制文件出问题能快速回滚。# 下载1.30.1稳定版源码wgethttp://nginx.org/download/nginx-1.30.1.tar.gztarzxf nginx-1.30.1.tar.gzcdnginx-1.30.1# 用原编译参数configure这里替换成你自己之前的编译参数./configure--prefix/usr/local/nginx --with-http_ssl_module# 编译不要直接make installmake# 备份旧二进制mv/usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.bak# 替换新二进制cpobjs/nginx /usr/local/nginx/sbin/# 平滑升级makeupgradeK8s Ingress升级直接替换镜像版本到v1.14.5及以上滚动更新控制器Pod就行。kubectlsetimage deployment/ingress-nginx-controller-ningress-nginxcontrollerregistry.k8s.io/ingress-nginx/controller:v1.14.5升级注意事项都是我踩过的坑升级前必须跑nginx -t校验配置跨大版本升级可能会有指令弃用直接重启会起不来。生产环境先更灰度节点跑10分钟业务流量没问题再全量推别上来就全集群更。升级后留好旧版本的安装包和配置备份出问题能分钟级回滚。第二层临时缓解方案无停机窗口应急用有些核心业务没有停机窗口短时间内没法升级这时候先改配置直接堵死漏洞触发条件防护效果一样能防住RCE。方案1替换未命名捕获组为命名捕获组漏洞触发的核心依赖$1、$2这类未编号捕获组的处理逻辑换成命名捕获组之后rewrite引擎会走另一套处理流程不会触发内存溢出。改造前后的对比# 高危写法 rewrite ^/(.*)$ /index.php?route$1 last; # 安全写法 rewrite ^/(?route.*)$ /index.php?route$route last;功能完全一致业务无感知只是把正则里的捕获组起个名字替换的时候用名字引用。批量替换可以用sed命令注意先备份配置正则写错会导致服务异常建议先单文件测试再全量操作。方案2移除rewrite替换串中的问号如果业务逻辑允许把参数传递从rewrite里挪出去。比如用proxy_pass直接拼接参数或者用try_files实现路由转发从根源上消除触发条件。举个例子原来用rewrite传参的逻辑可以改成用try_filesfastcgi_param传参完全避开rewrite的问号逻辑。方案3开启系统ASLR内存随机化这个不能根治漏洞但能大幅提升RCE的利用难度。关闭ASLR的系统攻击者可以稳定计算内存地址直接拿到shell开启ASLR之后内存地址是随机的利用成功率会降到极低。执行这两条命令开启临时永久生效# 临时生效重启后失效echo2/proc/sys/kernel/randomize_va_space# 永久生效echokernel.randomize_va_space 2/etc/sysctl.confsysctl-p验证是否开启cat/proc/sys/kernel/randomize_va_space输出2就是完全随机模式。这里强调一句ASLR只是辅助防护绝对不能只开个ASLR就觉得万事大吉。攻击者可以配合内存泄露漏洞绕过ASLR该升级还是要升级该改配置还是要改。第三层边界防护兜底WAF流量拦截如果连配置都没权限改比如用的是云服务商的托管网关那就在上层WAF加拦截规则先把攻击载荷挡在外面。两个核心拦截规则拦截超长URI请求。攻击载荷需要填充大量字符触发溢出通常URI长度会远超正常请求。限制URI长度在合理范围内能挡住绝大多数自动化扫描。NGINX本身可以加这两条配置限制请求头大小http { client_header_buffer_size 512k; large_client_header_buffers 2 1k; }拦截包含大量URL转义字符的请求。攻击载荷里会有大量%XX格式的转义字符WAF加规则匹配URI中连续多个转义字符的请求直接拦截。再加一层频率限制单IP每秒请求数限制在合理范围阻断扫描器批量探测。NGINX漏洞四层加固架构图系统层ASLR、权限控制、服务层版本升级、配置改造、边界层WAF、限流拦截、运营层监控告警、定期扫描。入侵痕迹排查公网暴露机器必做如果你的NGINX已经在公网跑了很久漏洞公开前就对外提供服务一定要做一次完整的入侵排查。这个漏洞藏了近20年不排除有攻击者早就掌握了利用手法。排查分三步从最明显的日志痕迹到系统级后门。第一步查进程崩溃与core dump这个漏洞的低阶PoC很容易打崩worker进程哪怕攻击者没拿到权限扫描探测也会留下崩溃日志。先查NGINX错误日志# 查worker进程异常退出记录grep-iworker process exited/var/log/nginx/error.loggrep-icore dumped/var/log/nginx/error.log如果短时间内出现大量worker进程退出且伴随core dumped提示大概率已经有人在打你的机器。再找系统里的core dump文件# 常见的core文件存放路径find/var/lib/nginx /var/cache/nginx /tmp /root /var/core-namecore.*2/dev/nullcore文件里保存了进程崩溃时的内存快照如果有条件可以分析core文件确认崩溃原因是不是这个漏洞。第二步查访问日志找攻击载荷攻击请求的URI有非常明显的特征带问号参数参数里有大量URL转义序列URI长度远超正常请求。执行这两条命令筛查# 查找带大量URL转义字符的请求grep-E\?.*(%[0-9A-F]{2}){3,}/var/log/nginx/access.log# 查找URI长度超过200字节的请求awk{if(length($7)200) print $0}/var/log/nginx/access.log如果有大量陌生IP发起这类请求且集中在短时间内就是扫描器在批量探测漏洞。第三步系统级后门排查如果攻击者成功实现RCE一定会留后门维持权限。重点查这几个位置定时任务# 查看当前用户定时任务crontab-l# 查看系统级定时任务目录ls-l/etc/cron.d/ls-l/etc/cron.hourly/ls-l/etc/cron.daily/留意陌生的脚本和命令尤其是带反弹shell、下载远程文件的内容。SUID权限文件SUID文件可以让普通用户以文件所有者权限执行是攻击者常用的提权和留后门方式。find/-perm-4000-typef2/dev/null和基线对比看有没有新增的SUID程序尤其是/bin、/tmp、/dev/shm目录下的。异常进程与网络连接# 查看nginx派生的异常子进程psauxf|grepnginx-A10# 查看nginx进程相关的对外连接ss-antp|grepnginx如果看到nginx进程派生了bash、sh、nc、socat这类进程或者有陌生的对外TCP连接基本可以确定已经被入侵。系统用户# 查看UID为0的特权用户awk-F:$30 {print $1}/etc/passwd检查有没有新增的root权限用户。这里提个取证注意事项如果确认被入侵别直接重启机器。先保存内存镜像、日志和可疑文件再做处置重启会丢失内存中的关键证据。长期安全建设避免下次再连夜救火这个漏洞藏了快20年才被公开本质是C语言编写的基础组件普遍存在的内存安全问题。以后肯定还会有同类漏洞爆出来日常做好这几件事下次再出预警你不用再慌。第一落地配置基线与自动化校验直接把“禁止使用未命名捕获组进行rewrite参数传递”写进NGINX配置规范作为上线强制要求。把配置扫描集成到CI/CD流水线里发布前自动跑检测脚本不符合规范的配置直接打回不用等漏洞爆了再全量扫。可以用现成的工具比如nginx-linter也可以用上面的检测脚本改改直接用成本很低效果很明显。第二最小化运行与编译很多人装NGINX的时候把所有模块全装上其实大半都用不上平白增加攻击面。源码编译的时候只启用业务必须的模块不用的全部关掉。同时加上安全编译选项从编译层面缓解内存溢出漏洞的危害CFLAGS-fPIE -fstack-protector-all -Wl,-z,relro,-z,now -D_FORTIFY_SOURCE2\./configure\--prefix/usr/local/nginx\--with-http_ssl_module\--with-http_v2_module\--without-http_autoindex_module\--without-http_ssi_module\--without-http_dav_module运行权限也要收紧worker进程用普通用户跑禁止用root。配置文件里加一句user nginx nginx;就算真的被攻破攻击者也只能拿到普通用户权限没法直接控制整台服务器。第三完善监控告警体系两个核心告警规则必须配上NGINX worker进程异常退出、core dump文件生成直接触发高危告警。内存破坏类漏洞的利用几乎都会伴随进程崩溃这是最及时的预警信号。单IP短时间内发起大量超长URI请求自动触发限流甚至拉黑。绝大多数攻击都是先扫描再利用把扫描挡住就能规避90%的风险。日志至少留存90天最好接入SIEM平台统一分析方便事后溯源和取证。第四容器环境专项加固容器化部署的NGINX和Ingress要单独做安全加固。容器必须以非root用户运行设置只读根文件系统去掉所有不必要的CAP权限禁止特权模式禁止挂载宿主机的敏感目录。比如Ingress控制器的安全上下文配置securityContext:runAsNonRoot:truerunAsUser:101readOnlyRootFilesystem:trueallowPrivilegeEscalation:falsecapabilities:drop:-ALL第五定期演练与漏洞复盘别等漏洞爆了才临时抱佛脚。每个月做一次全量组件版本扫描覆盖所有中间件和依赖库。每半年做一次漏洞演练拿最新的PoC在测试环境打一遍验证自己的防护规则到底管不管用。很多公司的WAF规则看起来全真打起来一个都拦不住就是因为从来没实测过。现在整个行业都在往内存安全的方向走用Rust重写基础组件是大趋势。未来这类C语言写的基础组件内存漏洞会越来越少但在完全过渡完之前我们还是要把配置、权限、监控这些基础工作做扎实。高频问题整理我只用NGINX做静态文件服务没有rewrite规则要不要升级答理论上只有DoS风险不会被远程执行代码。但建议还是找业务窗口升了漏洞的利用手法一直在迭代现在安全不代表一直安全早补早安心。改命名捕获组会不会影响业务逻辑答完全不会。命名捕获组和未命名捕获组的匹配逻辑、替换结果完全一致只是写法不同业务侧无感知。1.16、1.18这种老版本官方有补丁吗答官方只给当前维护的稳定分支出修复包更老的版本没有官方补丁。要么升级到支持的版本要么自己回补代码补丁要么改配置做临时缓解。我开了WAF是不是就不用升级了答不是。WAF只能拦截已知的攻击载荷攻击者稍微改一下payload就能绕过。版本升级才是根本解决方式WAF只是兜底防护。你们线上的NGINX扫完发现了多少处高危rewrite配置有没有遇到升级后配置不兼容的情况欢迎在评论区留言交流。如果需要支持多服务器批量巡检的Python版检测脚本也可以评论区说一声我后续整理出来更新。