
CVE-2024-4947(V8 Maglev の型混同)の教育的コンセプト実証であり、トリガーからサンドボックス化されていない d8 ビルド上での任意コード実行までの完全なチェーンを示しています。
CVE-2024-4947(V8 Maglev 型混同)に対する、自己完結型の完全なエクスプロイトチェーンです。最初の型混同トリガーから任意コード実行に至るまでをすべて含みます。この PoC はサンドボックスなしの d8 ビルドに対して動作し、コード実行の証明として CVE-2024-4947-PWNED を stdout に出力します。
⚠️ これはパッチ適用済みの公開済み脆弱性を実演する研究・教育目的の PoC です。開発用の V8 シェル(
d8 --allow-natives-syntax)を対象としており、実際の Chrome ブラウザではありません。免責事項を参照してください。
$ ./v8-build-nosandbox.sh # build the vulnerable d8 (WSL2 Ubuntu, ~10-20 min)
$ d8 --allow-natives-syntax --module exploit/exploit_rce.mjs
[engine] dblData0=0004f470 class=0
[inst] addr=0x001dc274 trusted_data(tagged)=0x00202bd5 td=0x00202bd4
[jt] jump_table_start = 0x00000967426cd000 (external code space)
[bridge] memory0_start -> jt, memory0_size -> huge (r/w reach jt+off)
[slot0] before: e9 3b 08 00 00
[shell] wrote 52 bytes @ jt+0x0100: VERIFIED
CVE-2024-4947-PWNED
$ echo $? # 0
52 バイトのシェルコードは write(1, "CVE-2024-4947-PWNED\n", 20); exit_group(0) です。
CVE-2024-4947 は V8 Maglev JIT コンパイラの型混同で、Chrome 125.0.6422.60(コミット b3c01ac1e60a)で修正されました。これは実際の攻撃(in the wild)で Lazarus APT グループによって悪用されました。Maglev がモジュール名前空間オブジェクト(JSModuleNamespace)へのストアをコンパイルする際、誤った AccessInfo を使用します — ストアは、正規のプロパティストア経路を通らず、隣接オブジェクトの map フィールドに制御された値を書き込む単純な mov [[obj + 4], rax] としてコンパイルされます。
悪用は次の手順で進行します。
NAME_DICTIONARY_TYPE(0xB2)map に破壊し、V8 がオブジェクトのハッシュを保存する場所を変更する。new WeakRef(...) をトリガーしてハッシュの書き込みを隣接オブジェクトの length スロットに着弾させる → **領域外(out-of-bounds)**アクセス。そこから定番の V8 ツールキット、addrOf/fakeObj、そして任意のケージ内読み書きが得られます。
CVE-2024-4947 trigger (fake NAME_DICTIONARY map + WeakRef hash write)
└─► OOB write ─► corrupt doubleArray length
└─► in-cage 4/8-byte arbitrary R/W (the "engine")
└─► overwrite WasmTrustedInstanceData.memory0_start (+0x18)
& memory0_size (+0x20) → huge
└─► wasm load8_u / store8 = clean 64-bit R/W bridge
(no software bounds check in compiled code)
└─► read jump_table_start (+0x38) — external code space
└─► jump table region is RWX (this build)
└─► write shellcode into the slack (jt+0x100)
└─► repoint func0's `e9 rel32` slot at it
└─► call func0 → shellcode → RCE
| # | 段階 | 詳細 |
|---|---|---|
| 1 | トリガー | opt() が型混同ストアを介して偽の map を書き込む。new WeakRef(m) が corruptArray.length を OOB にする。 |
| 2 | エンジン | addrOf/fakeObj。doubleArray の length を破壊 → 任意の 4 バイトアラインされたケージ内アドレスへの任意の 4 バイト R/W。 |
| 3 | 64 ビットブリッジ | WasmTrustedInstanceData.memory0_start(+0x18)は、コンパイル済み wasm の i32.load8_u/i32.store8 がソフトウェア境界チェックなしで使用する生の 64 ビットポインタ(範囲外アクセスはガードページにヒット → SIGSEGV → wasm トラップ)。これを任意のアドレスにリダイレクトし、memory0_size(+0x20)を巨大に設定 → 任意の 64 ビット R/W。 |
| 4 | コードスペースの特定 | jump_table_start(+0x38)は外部コードスペース(4 GB ケージ外)への生の 64 ビットポインタ。 |
| 5 | シェルコードの書き込み | このビルドではジャンプテーブル領域は RWX(V8 が実行時にエントリをパッチするため)。jt+0x100 のスラックに 52 バイトのシェルコードを書き込む。 |
| 6 | スロットの再ポイント | func0 のジャンプテーブルスロットは 5 バイトの e9 <rel32>(ターゲット = スロット + 5 + rel32)。rel32 を jt+0x100 に設定。 |
| 7 | ディスパッチのトリガー | inst.exports.r(0) → JSToWasmWrapper がスロット 0 経由でディスパッチ → シェルコードが実行される。 |
ほとんどの公開 CVE-2024-4947 PoC はサンドボックス化された d8 または実際の Chrome レンダラー(v8_enable_sandbox=true)を対象とし、型混同 / OOB プリミティブで止まっています。この PoC はサンドボックスなしの d8 を対象とし、チェーンをコード実行まで完遂します。重要な違いは次のとおりです。
| 項目 | 一般的な公開 PoC の方式 | 本 PoC |
|---|---|---|
| ターゲットビルド | サンドボックス化された d8 / Chrome レンダラー | v8_enable_sandbox=false d8 — トラステッドポインタは直接参照、外部コードスペースは有効 |
| 64 ビット R/W ブリッジ | JSTypedArray.external_pointer を上書き | その経路はコード範囲の読み取り時にクラッシュする(実験的に検証済み)。代わりに memory0_start を上書きし、生の wasm ロード/ストアを使用 |
| 最終的なコード実行経路 | コードスペースは W^X → JIT スプレー + 間接リダイレクト | ジャンプテーブル領域は RWX → 直接のシェルコード書き込み + e9 rel32 スロットパッチ |
| ジャンプテーブルスロット形式 | ドキュメントは通常 movabs rax, imm64; jmp rax(12 バイト)を想定 | 実測: 5 バイトの e9 <rel32>、ターゲット = スロット + 5 + rel32 |
| フィールドオフセット | サンドボックスビルドのレイアウト | サンドボックスなし WasmTrustedInstanceData: jump_table_start@+0x38、memory0_start@+0x18、memory0_size@+0x20; WasmInstanceObject.trusted_data@+0x0c |
| クリーンな終了 | — | d8 はマルチスレッド: exit(60)ではなく exit_group(231)を使う必要がある。そうしないとプロセスがハングする |
各行の背後にある実験的な知見を含む完全な技術解説については、docs/walkthrough.md を参照してください。
.
├── exploit/
│ ├── Module.mjs # module namespace object corrupted by the trigger
│ ├── exploit_rce.mjs # the full chain (trigger → arbitrary R/W → RCE)
│ └── shellcode.S # assembly source for the 52-byte payload
├── build/
│ └── v8-build-nosandbox.sh # build the vulnerable no-sandbox d8 from V8 source
└── docs/
└── walkthrough.md # deep dive: bridge mechanics, layouts, gotchas
エクスプロイトは Module.mjs(脆弱なモジュール名前空間オブジェクト)を自身のディレクトリからインポートするため、2 つのファイルを同じ場所に置いてください(または import パスを調整してください)。
git、約 10 GB の空きディスクを備えた任意の Linuxdepot_tools(git clone https://chromium.googlesource.com/chromium/tools/depot_tools)# 1. fetch V8 at the vulnerable tag (12.4.254.16 is the pre-fix release)
export PATH="$HOME/depot_tools:$PATH"
cd ~/v8w && fetch v8 && cd v8
git checkout 12.4.254.16 # or the commit just before b3c01ac1e60a
# 2. first build a normal release d8 (needed to seed args.gn), then:
./v8-build-nosandbox.sh # copies args.gn and appends v8_enable_sandbox = false
v8-build-nosandbox.sh は ninja -C out.gn/x64.release_nosandbox -j6 d8 を使用します。
out.gn/x64.release_nosandbox/d8 --allow-natives-syntax --module exploit/exploit_rce.mjs
期待される出力の末尾は次のとおりです。
CVE-2024-4947-PWNED
そしてプロセスはステータス 0 で終了します。
--allow-natives-syntaxは%PrepareFunctionForOptimization/%OptimizeMaglevOnNextCallのランタイム呼び出しに必要です。これが、この PoC が実際のブラウザで実行できない理由です — 設計上、d8 シェルでの概念実証(PoC)です。
V8 エクスプロイト研究にとって真に再利用可能な(そして自明ではない)要素は次のとおりです。
JSTypedArray.external_pointer のリダイレクトが失敗する場合は、代わりに WasmTrustedInstanceData.memory0_start をリダイレクトする。コンパイル済み wasm のバイトロード/ストアにはソフトウェア境界チェックがない。シグナルトラップハンドラはガードページのフォールトのみをトラップに変換するため、マップ済みだが書き込み不可の領域はトラップではなくクラッシュする。try/catch を使用して 1 バイトずつプローブする。wasm の "out of bounds" トラップはガードページ(未マップ)を意味し、実際の SIGSEGV はマップ済みだが RX であることを意味する。e9 rel32 スロット形式 — 多くの解説が想定する movabs 形式ではなく、5 バイトの相対ジャンプ。--print-wasm-code の逆アセンブリ出力と照合して検証済み。このリポジトリは教育および防御的セキュリティ研究のみを目的として提供されます。開発専用の V8 ビルドに対するパッチ適用済み脆弱性の悪用を実演するものです。最新の Chrome に対する武器ではありません。V8 サンドボックスをバイパスするものではなく、非デフォルトの --allow-natives-syntax フラグを必要とします。著者はいかなる誤用についても責任を負いません。
トリガープリミティブ(偽の NAME_DICTIONARY_TYPE map + WeakRef ハッシュ書き込み)は、パッチ適用後に公開された、実攻撃で使用された Lazarus エクスプロイトの公開分析(Google と Exodus Intelligence による CVE-2024-4947 の解説記事を含む)に従っています。後段のステージ(ジャンプテーブルのプロービング、ブリッジ、スロットパッチ)は、今回の作業においてこの特定のビルドに対して実験的に導出されました。JIT スプレーのフォールバックというコンセプトは、公開されている V8 エクスプロイトテクニック(例: CVE-2024-5830 の make_array パターン)に基づいています。
MIT — LICENSE を参照してください。