Hamid-K/nginx-rift-private-lab

GitHub: Hamid-K/nginx-rift-private-lab

这是一个针对Nginx漏洞CVE-2026-42945的私有实验室,提供绕过ASLR的利用链和自动化评估工具。

Stars: 75 | Forks: 15

# ool/library name, so keep in English. 针对 **CVE-2026-42945** 的远程代码执行(RCE)概念验证,这是 NGINX 的 `ngx_http_rewrite_module` 自 2008 年引入的一个严重堆缓冲区溢出漏洞。该漏洞使得攻击者可以对使用 `rewrite` 和 `set` 指令的服务器进行未经身份验证的远程代码执行。 此分支扩展了原始 PoC,增加了绕过地址空间布局随机化(ASLR)的利用链,该链将 NGINX 溢出与一个常见的同一主机本地文件包含(LFI)/任意文件读取原语相结合。该文件读取原语用于恢复 nginx worker 映射、libc 和活动的 `/proc//mem`,然后远程推导出 `system()` 地址和可用的堆目标。 此实验室的早期版本会故意使一个 nginx worker 崩溃,从而让服务生成一个核心转储文件,然后通过文件读取原语获取并解析该核心转储文件,以恢复包括堆目标在内的、受 ASLR 保护的进程状态。在本仓库中,**coreless** 仅作为"不使用可读崩溃核心转储"的简写:当前的默认路径用活动的 procfs 内存读取取代了对崩溃核心转储的依赖,而保留的遗留 **core-guided** 路径仍使用生成的 worker 核心转储。 此漏洞——连同另外三个内存损坏问题(CVE-2026-42946、CVE-2026-40701、CVE-2026-42934)——是由 [depthfirst](https://depthfirst.com) 的安全分析系统在仅点击一次导入 NGINX 源代码后自主发现的。 ## 漏洞简述(TL;DR) NGINX 的脚本引擎使用两遍处理过程:首先计算所需缓冲区大小,然后复制数据。当 `rewrite` 替换字符串包含 `?` 时,主引擎上的 `is_args` 标志会被设置,但长度计算过程运行在一个新初始化的子引擎上。因此: - **长度计算阶段**看到 `is_args = 0` → 返回原始捕获长度。 - **数据复制阶段**看到 `is_args = 1` → 使用 `NGX_ESCAPE_ARGS` 调用 `ngx_escape_uri`,将每个可转义字节扩展为 3 个字节。 复制操作导致堆缓冲区溢出,其中包含攻击者控制的 URI 数据。利用过程使用跨请求的堆布局技术(heap feng shui)来损坏相邻 `ngx_pool_t` 的 `cleanup` 指针(通过 POST 主体进行喷射,因为 URI 字节不能包含空字节),将其重定向到一个伪造的 `ngx_pool_cleanup_s` 结构体,该结构体在内存池销毁时调用 `system()`。 在此处阅读更多关于此漏洞的详细信息:[技术分析](https://depthfirst.com/research/nginx-rift-achieving-nginx-rce-via-an-18-year-old-vulnerability)。 ## 受影响及修复版本 厂商完整公告: ## 私有研究分支:启用 ASLR 的远程实验链 ![启用 ASLR 的远程利用演示](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/136c307db4074918.gif) ![评估优先的 nginx_rifter 演示](https://raw.githubusercontent.com/Hamid-K/nginx-rift-private-lab/main/demo4.gif) ![nginx_rifter v3 无核心转储 proc-mem 利用演示](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/917c60fc24074921.gif) 此分支保留了原始披露 PoC 的完整性,但增加了第二条研究路径,聚焦于一个更现实的问题: 在此研究分支中的答案是**是,但存在重要限制条件**。工作链并未禁用 ASLR,也未使用原始的硬编码堆/libc 地址。相反,它们通过同一端口的 HTTP 可访问原语推导运行时状态,然后从远程获取的泄露数据中选择最终的堆目标。 目前有两条启用 ASLR 的利用路径,其中无核心转储路径被视为当前最佳 PoC: - `nginx_rifter.py`:清晰、自包含的评估工具和集成利用入口点。其默认利用方法现在是无核心转储的 `/proc//mem` 链。 - `nginx_rifter_core_v2_1.py`:保留的、基于核心转储的旧版 `nginx_rifter.py`。它可用于复现旧的、在 VM 中测试的基于崩溃核心转储的研究路径,但它不再是首选的 PoC。 - `tools/proc_mem_coreless_exploit.py`:较早的独立无核心转储研究测试工具。其逻辑已合并到 `nginx_rifter.py` 中;该工具保留用于原始实验重放。 目标拓扑故意设计为同一端口: - 漏洞路由:`/api/...` - PHP 本地文件读取路由:`/lfi.php?file=...` - phpinfo 提示路由:`/phpinfo.php` - HTTP/2 受害连接:相同的 nginx 监听器和 worker - 证明验证:通过 PHP LFI 端点读回标记文件 当前无核心转储的 proc-mem 路径执行以下高级步骤: 1. 使用 PHP LFI 读取 PHP 标识、nginx PID 文件、nginx worker `/proc//maps` 以及映射的 libc 文件。 2. 通过 LFI 解析目标 libc,计算该 worker 的绝对 `system()` 地址。 3. 发送正常的 NGINX Rift 喷射/探测流量,同时保持 worker 状态活跃。 4. 通过文件读取原语从 `/proc//mem` 读取映射范围。 5. 扫描活动内存,查找带有 nonce 标记的伪造 cleanup 结构体和 cleanup-pool 候选对象。 6. 使用从活动 worker 内存中推导出的、有界的最终候选对象,而不是硬编码的实验室偏移或可读的崩溃核心转储。 7. 通过文件读取原语读取标记输出来验证命令执行。 旧的基于核心转储的路径执行类似的基地址推导,然后故意使一个 worker 崩溃,通过 LFI 读取生成的核心文件,并从该核心文件中挖掘喷射的伪造 cleanup 插槽。这曾是一个有用的研究桥梁,但它依赖于核心转储策略和文件系统权限,这些在默认部署中不太常见。 这与原始的确定性 Docker 演示不同。x86_64 VM 路径保持正常的 Linux ASLR 启用,并在每次运行时重新计算特定于进程的地址。Docker 无核心转储路径也保持 ASLR 启用,并移除了不常见的可读核心转储要求,但它依赖于必须为目标类别验证的 procfs 权限行为。 ### 范围与注意事项 此分支是一个受控的研究实验室。启用 ASLR 的链依赖于并非普遍适用于生产环境的强条件: - PHP 必须暴露一个有用的本地文件读取原语。 - 对于默认的无核心转储 proc-mem 路径,PHP 必须能够读取相同 UID 的 nginx worker 的 `/proc//maps`、映射的 libc 以及大偏移映射下的 `/proc//mem`。 - 对于旧的基于核心转储的路径,PHP 必须能够读取相同 UID 的 nginx worker 的 `/proc//maps`、映射的 libc 以及生成的 worker 核心转储。 - HTTP/2 必须在同一个 nginx 监听器上启用,以提供最终链所需的连接池清理目标。 `phpinfo()` 和 `/proc//maps` 足以恢复 PIE/libc 基地址,但它们本身不足以恢复此利用所需的精确堆对象/窗口。旧链使用可读的崩溃核心转储进行最终信息泄露。当前的默认链则使用 `/proc//mem`,这更接近真实任意文件读取在相同 UID 部署中的后果,因为它暴露了活动的 worker 内存而无需更改核心转储策略。 剩余的重要限制: - `/proc//mem` 受 ptrace 门控。它在 Docker 实验室中以及在对官方 `nginx:stable` 镜像模型的相同 UID 检查中有效,但在默认 procfs 保护下,不同 UID 的应用进程应该会失败。 - 文件读取原语必须支持大偏移或等效的范围 API。 - proc-mem 路径的真正 Ubuntu VM 复测仍在进行中。 - 尚未找到直接的非 LFI nginx 响应内存泄露。被动反射、重定向/头部/主体探测、初始的延迟代理过读扫描以及 SSRF 辅助的源代码审查均未产生与 ASLR 相关的泄露。 ### 当前工具 当前清晰的入口点是 `nginx_rifter.py`,这是一个评估优先的工具,旨在更接近授权测试人员如何评估一个已知存在漏洞、且具有 HTTP 可访问本地文件读取原语的 nginx 部署。 与初始演示运行器相比,`nginx_rifter.py` 在多个方面改进了工作流程: - 评估是默认模式。除非明确提供 `--exploit`,否则不会运行崩溃利用。 - 目标以 `HOST:PORT` 形式提供,文件读取原语通过 `--file-read-template` 模块化。 - 在依赖 LFI 原语之前,它会对其进行分析,包括文本读取、二进制读取、范围读取、`/proc/self/status`、`/proc/self/maps` 以及相同 UID worker procfs 的可达性。 - 它通过远程原语发现 nginx worker 映射、libc、`system()`、构建 ID、二进制哈希、OS 详情以及 proc-mem/核心转储设置。 - 它尝试从主进程命令行和常见配置路径发现 nginx 配置,然后标记易受攻击的 `rewrite` + `set` 路由候选。 - 它打印一个利用链可行性矩阵,以便在任何尝试利用之前清楚地看到缺失的先决条件。 - 利用模式是显式的,并集成到 `nginx_rifter.py` 中;默认方法是无核心转储的 proc-mem。 当前的 `nginx_rifter.py` 是自包含的。它不再导入或调用早期的演示 PoC 版本或 `tools/proc_mem_coreless_exploit.py` 来进行评估或利用。 旧的基于核心转储的 `nginx_rifter.py` 实现被保留为 `nginx_rifter_core_v2_1.py`。 较新的 `artifacts/nginx_rifter_v3_coreless_exploit_20260519.gif` 展示了合并后的 v3 `nginx_rifter.py` 无核心转储利用路径。`demo4.gif` 展示了早期一体化核心转储工具的评估和显式利用流程。更早的 `nginx-aslr-demo.gif` 仍作为原始的启用 ASLR 的利用演示。 ## 使用方法 在 Ubuntu 24.04.3 LTS 上测试。 原始 ASLR 禁用的 Docker 复现: 1. `./setup.sh` — 构建容器。 2. `docker compose -f env/docker-compose.yml up` — 启动存在漏洞的 NGINX 服务器。 3. `python3 poc.py --shell` — 获得一个 shell。 关于本地 Docker 复现流程,请参见 [LAB.md](LAB.md)。 旧版启用 ASLR 的 VM 基于核心转储的链: ``` ./nginx_rifter_core_v2_1.py --target :19321 --exploit --cmd id --fast ``` 评估优先的 v3 工具: ``` ./nginx_rifter.py --target :19321 ``` `nginx_rifter.py` 是当前面向现实世界的评估器和集成 PoC 入口点。其默认模式不运行崩溃利用路径。它分析 HTTP 文件读取原语,检查范围和二进制读取,对 OS/nginx/libc 进行指纹识别,发现 nginx worker 和与 ASLR 相关的映射,测试相同 UID `/proc//mem` 的可读性,尝试通过 pid/cmdline/配置读取恢复 nginx 配置路径,标记易受攻击的 `rewrite` + `set` 路由候选,并打印当前无核心转储链的可行性矩阵。 当前的 `nginx_rifter.py` 是自包含的。它不再导入或调用早期的演示 PoC 版本或独立的 proc-mem 研究工具进行评估或利用。 对于自定义的 LFI/下载格式: ``` ./nginx_rifter.py --target :19321 \ --file-read-template 'http://{host}:{port}/download?path={path_url}{range_query}' ``` 利用执行是显式的: ``` ./nginx_rifter.py --target :19321 --exploit --cmd id --fast # - "Rift" – if it's part of a technical term or name, keep in English. But in the second heading, "exploit" and others are kept in English. ./nginx_rifter.py --target :19321 --exploit --derive-only --cmd id ``` 默认的利用方法是无核心转储的 proc-mem。以下选项已被默认选中,因为它们是对于无核心转储 Docker 证明最可靠的: ``` --exploit-method proc-mem --target-len 6 --max-region 268435456 ``` 旧的可读核心转储模式仍可用于比较,但版本化脚本在复现该旧路径时更清晰: ``` ./nginx_rifter_core_v2_1.py --target :19321 --exploit --cmd id --fast ``` 旧版便于录制的终端演示: ``` ./demo_ctf_exploit_v1_9.py --host :19321 --cmd id --clear ``` `demo_ctf_exploit_v1_9.py` 是用于基于核心转储的实验室路径的旧版操作员运行器。当前首选的 PoC 入口点是 `nginx_rifter.py`。 默认的文件读取原语是此分支的 PHP 路由: ``` /lfi.php?file=&offset=&length= ``` 对于其他已知存在漏洞的 CTF 应用或测试平台,文件读取向量是模块化的: ``` ./nginx_rifter.py --target :19321 --exploit --cmd id \ --target-profile generic \ --file-read-template 'http://{host}:{port}/download?path={path_url}{range_query}' ``` 模板支持 `{host}`、`{port}`、`{path_url}`、`{offset}`、`{length}` 和 `{range_query}`。通用分析会跳过此分支实验室特定的 nginx 配置断言,但默认利用仍然需要相同的基础能力:可读的 nginx worker `/proc` 映射、可读的 libc 以及可读的 `/proc//mem`。`phpinfo()` 是可选的;使用 `--phpinfo-path ''` 可禁用它。 现实性注意事项:LFI/文件读取漏洞类别和同主机 nginx/PHP-FPM 部署模型是现实的。proc-mem 链比早期的崩溃核心转储链更现实,因为它不需要启用或读取 worker 核心转储。它仍然不是普遍的默认生产环境假设:相同 UID 的进程布局、procfs/Yama 策略、容器命名空间设置以及文件读取原语的质量决定了 `/proc//mem` 是否可达。 无 LFI 研究探测: ``` python3 tools/non_lfi_leak_probe.py --target :19321 python3 tools/non_lfi_active_response_probe.py --target :19321 ``` 这些是阴性研究探测,而非利用入口点。它们在不使用 LFI、phpinfo、procfs、核心转储、调试器访问或硬编码实时 ASLR 基址的情况下,测试被动反射汇点和初始的延迟响应过读格式。 其他实验室笔记和运行日志位于 `docs/` 下,特别是: - `docs/CTF_PLAN.md` - `docs/CTF_FINDINGS.md` - `docs/CTF_TESTS.md` - `docs/CTF_EXPERIMENT_LOG.md` - `docs/DEMO_POC_IMPROVEMENTS.md` - `docs/KNOWN_LAYOUT_PATTERNS.md` - `docs/VAGRANT_ESXI.md` - `docs/CORELESS_ASLR_PLAN.md` - `docs/CORELESS_ASLR_FINDINGS.md` - `docs/NON_LFI_ASLR_BYPASS_LOG.md` - `docs/DEMO_RECORDING_WORKFLOW.md`
标签:请求拦截, 逆向工具