
Android Chromium向けのフルチェーンエクスプロイトで、CVE-2026-11057の情報漏えいとCVE-2026-5281のuse-after-freeを組み合わせ、vtableハイジャックと任意コード実行を実現します。
Pixel 7 Android 16 ARM64
commit 994c846bbd7a35241ba7c08158c13d66412a6993 (HEAD -> 146.0.7680.111, tag: 146.0.7680.111)
Author: Roger McFarlane <[email protected]>
Date: Mon Mar 9 12:48:07 2026 -0700
このリポジトリは、CVE-2026-11057(Skia の未初期化グリフ画像メモリ)と CVE-2026-5281(Dawn wire サーバーの DeviceInfo ユースアフターフリー)を組み合わせて完全なチェーンを構成します。すべての変更はレンダラー側で行われ、GPU プロセスのコードは変更されていません:
情報リーク(CVE-2026-11057) — canvas のテキストレンダリングを介して未初期化のグリフ画像バッファをトリガーし、GPU プロセスのヒープからポインタを読み戻し、算術実行でそれらを検証し、PartitionAlloc プールのベースを導出し、偽の Server ターゲット M = POOL + 0x202A08000(キャリブレーション済みオフセット)を計算します。
CC スプレー — createBuffer(label="CCM:<m>:<n>") は、3000 個の不完全な ChunkedCommand(10KB バケット、remainingSize=1、wire サーバーの mChunkedCommands 内で存続)の注入をトリガーします。ペイロードは M 周辺の領域を、Android arm64 向けにレイアウトされた偽の Server で埋めます:+0xB20 に MutexProtected vptr、+0xB50/+0xB58 に ChunkedCommandSerializer、+0xC00/+0xD00 に偽の CommandSerializer/vtable。
5281 トリガー + 占有 — queue.writeBuffer(buffer, 0x414141, ...) はまず Unregister(Device) を呼び出して 16 バイトの DeviceInfo を解放し、次に 16 バイトの占有用 ChunkedCommand を注入してそのスロットを再確保し info->server を M で上書きし、最後に範囲外オフセットで検証エラーをトリガーします。
ダングリングコールバック → vtable ハイジャック — 未キャプチャエラーのコールバックは info->server = M(偽の Server)を参照します:ゼロ化されたミューテックスを通過し、実行は OnUncapturedError → SerializeCommand に到達し、相対 vtable の間接呼び出しが偽の vtable にヒットして pc = fake_vtable + 制御された int32 オフセット となり、pc = 0x7641414141 で実証されます。
注:Android arm64 の Chromium は相対 vtable(
-fexperimental-relative-c++-abi-vtables)を使用します。vtable エントリは絶対関数ポインタではなく 32 ビットの相対オフセットであるため、PoC は vtable ハイジャック時点のマーカーとして制御された int32 オフセットを使用します。
テストデバイスでは、完全なチェーンはほぼ 100% の成功率で vtable ハイジャッククラッシュに到達します。リーク段階では、成功するまでに数回の自動リロードが必要になる場合があります。
SkStrike.cpp.patch — CVE-2026-11057 のリークトリガー。FlattenGlyphsByType() は strike ペイロードを書き換え、GPU プロセスが fImage == nullptr の SkGlyph を作成し、最終的に未初期化の画像バッファを読み取ってヒープポインタをリークします。Device.cpp.patch — Dawn wire クライアントの CC スプレー。APICreateBuffer() は CCM: ラベルを解析し、Android arm64 の偽の Server ペイロードを構築し、GPU プロセス内で存続する N 個の不完全な ChunkedCommand を注入します。ApiProcs.cpp.patch — CVE-2026-5281 のトリガー + 占有。QueueWriteBuffer のマジックオフセット 0x414141 で、Unregister(Device) を呼び出して DeviceInfo を解放し、16 バイトの ChunkedCommand を注入してスロットを再確保し info->server = M を設定し、その後範囲外オフセットで処理を進めてダングリングコールバックを発火させます。exploit.html — ページオーケストレーション:リークプリミティブ(groom/draw/readCell/verifyRuns/derivePoolBase)、CC スプレー、およびスタンドアロンの exploit5281() トリガー。失敗時にはスプレー状態をクリーンアップしてリロードし、各段階が干渉しないようにします。この ExP は vtable ハイジャック の段階(制御された間接呼び出しターゲット、pc = base+0x41414141)までのみ開示されています。制御されたジャンプ以降の段階、および RCE の実装は機密として保持され、このリポジトリには含まれていません。
私のエクスプロイトは、元の報告者のアプローチとは重要な点で異なります。 元のエクスプロイトは、GPU プロセスの PartitionAlloc ソースコードを変更してアドレスランダム化を無効化することで実現されていました。このアプローチは概念実証の目的にのみ適しています。 対照的に、私のエクスプロイトは情報開示脆弱性を組み合わせてアドレスランダム化をバイパスし、実環境で動作する完全に機能するエクスプロイトを実現します。
# Set build arguments here. See `gn help buildargs`.
is_official_build = true
is_debug = false
symbol_level = 0
v8_symbol_level = 0
blink_symbol_level = 0
is_component_build = false
proprietary_codecs = true
ffmpeg_branding = "Chrome"
dcheck_always_on =false
optimize_webui = true
android_static_analysis = "off"
target_os = "android"
target_cpu = "arm64"
# Disable PartitionAllocEventuallyZeroFreedMemory
disable_fieldtrial_testing_config = true
treat_warnings_as_errors = false
adb logcat | grep DEBUG を実行する