Low Severity CVE-2026-111497
Published: Oct 25, 2026

[GitHub] CVE-2026-111497-brotli-pwn

Other
Type
N/A
CVSS Score
7
Views
Anonymous
Author

Description

CVE-2026-111497: Node.js Brotli decoder OOB write — analysis, PoC, Docker lab

# CVE-2026-111497:Node.js Brotli 解码器越界写

> 中文在前,English version below.

这个仓库记录了我们对 CVE-2026-111497 的复现与分析。所有实验都在本地或自建的实验机上完成,没有接触任何第三方系统。

## 先说结论

| 能力 | 结果 | 条件 |
|---|---|---|
| 本地命令执行 | ✅ 3/3 可重复 | Node + 未修复 libbrotlidec + 确定性布局(`--predictable` 或关闭 ASLR) |
| 拒绝服务 | ✅ 86 字节流即可 | 任意未修复版本,无需大流量 |
| 远程触发溢出 | ✅ 已实证 | 目标进程接受两次 attacker 可控的 write |
| 远程读取进程内存 | ✅ 在 inspector 暴露场景下 | 进程开着 `--inspect` |
| 远程盲打 RCE | ❌ 未成立 | ASLR 开启、无 `--predictable` 时 wrap 补偿不可预测 |

最后一条不是没试,而是这条漏洞本身只提供“相对 ring 的 16 字节写”,没有自带地址泄露;公开 PoC 也停在同一位置。第 5 节写了具体卡点。

## 1. 漏洞本身

Node.js 内置的 Brotli 解码器在 `BrotliDecoderDecompressStream` 的流式路径上,对 `BrotliDecoderState.buffer.u8` 的尾部拷贝缺少长度校验。

- 受影响:Node 22.x < 22.23.4、24.x < 24.22.1、26.x < 26.12.1;已 EOL 的分支不再修复。
- 修复提交:`google/brotli@0ed4268a4401abcb4472096340477cf4af7d1a2b`("Detect and report invalid stream earlier"),Node 侧同时在 `src/node_zlib.cc` 暴露 `BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH`。
- 可复现的最老 commit:`34f020fa9daba975747b29885314c2545b7aa040`。

触发需要一条约 23 MB 的流:先是一个 16 MiB 的 compressed metablock,里面塞满 2^24 条“零输出”的字典变换命令,把 `block_length[2]` 耗尽;随后解码器返回 `NEEDS_MORE_INPUT` 但已经消费完输入。此时再写一小段数据,就会把攻击者字节拷进 8 字节的 `buffer.u8[]`,越过结构体边界。

## 2. 环境要求

- Linux x86-64;
- Node.js 22/24/26,且 `libbrotlidec.so.1` 仍是未修复版本(≤ 1.2.0 / 1.1.x)。Ubuntu 24.04 自带的 `nodejs` 22.22.1 就是动态链接系统 brotli,可以直接用来复现;
- `gcc`、`python3`(生成流和编译用);
- 能读 `/proc/self/mem`(PoC 用它定位 decoder state 和 libc);
- 布局确定性:`setarch x86_64 -R node ...` 或 `node --predictable`。

检查目标是不是动态链接:

```console
$ ldd "$(command -v node)" | grep brotli
libbrotlidec.so.1 => /usr/lib/x86_64-linux-gnu/libbrotlidec.so.1
$ node -p "process.versions.brotli"
1.2.0
```

如果 `ldd` 里没有 `libbrotlidec`(官方静态构建常见),漏洞路径通常进不去,先换发行版打包的 Node。

## 3. 复现

生成触发流(约 23 MB,仓库里不放这个文件):

```console
$ python3 poc/gen_stream.py stAA536.br "$(python3 -c 'print("aa"*536)')"
wrote=stAA536.br bytes=23069229 sha256=...
```

跑本地 PoC:

```console
$ PWNCMD='printf CVE-2026-111497 > /tmp/pwn_marker.txt' PK=4 \
node --predictable poc/pwn_local.js

Community Rating
0

Login to rate this exploit

Quick Actions