VMware Workstation PVSCSI LFH Escape (VMware-vmx on Windows 11)
Tip
AWSハッキングを学び、実践する:
HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
バグの構造: fixed-size realloc + scattered OOB writes
PVSCSI_FillSGIはゲストの scatter/gather エントリを内部配列にコピーする。最初は512エントリの静的バッファ (0x2000) で始まり、512エントリを超えると 0x4000 バイトに realloc するが、機能バグにより 毎回の反復で realloc される。- 再割当てサイズは増えない: 0x4000 / 0x10 バイトエントリ = 1024 使用可能エントリ。ゲストが >1024 エントリ を供給すると、各新エントリは新しく割り当てられた 0x4000 チャンクの16バイト先に書き込まれ、隣接するチャンクヘッダやオブジェクトを破壊する。
- オーバーフロー内容: VMware 側は
{u64 addr; u64 len}を保存するが、ゲストは{u64 addr; u32 len; u32 flags}を提供する。32ビットのlenは ゼロ拡張 されるため、各16バイトの OOB 要素の最後の dword は 常に 0x00000000 になる。
LFH の制約と決定論的な “Ping-Pong” 配置
- 0x4000 の割り当ては Windows 11 の LFH に配置される(バケットあたり16チャンク、0x10バイトのメタデータにキー付きチェックサム)。後でヘッダチェックサムが一致してしまうチャンクがあるとプロセスが終了するため、破損したヘッダは再利用してはいけない。
- LFH はランダムな空きチャンクを返すが、直近に解放されたチャンクを含むバケットを優先する。2つの空きスロットだけを強制する方法:
- アロケータを整列させるために、全ての空き 0x4000 チャンクを割り当てる;32 個の SVGA shaders をスプレーして B1 と B2 バケットを埋める。
- B1 を一つの固定されたシェーダ(Hole0)を残して解放し、B1 をアクティブに保つ;B1 に 15 個の URB を割り当てる。
- B2 のシェーダを1つ解放(PONG)、直ちに Hole0 を解放する。LFH は利用可能な2つのスロット間で交互に割り当てを行う(PING (B1) と PONG (B2))。
- 1025 回目の反復は PONG の後のヘッダを破損する(それ以降触れられない);1026 回目は PING の後の URB の最初の16バイトに当たり(メタデータバイパスとして安全)、配置を安定かつ再現可能に保つためにプレースホルダーシェーダで PING/PONG を回収する。
Reap Oracle: 連続するホールのラベリング
- UHCI URB は FIFO キューに存在し、完全に reaped されたときに解放される。制約された16バイトの上書きは常に
actual_lenをゼロ化するため、マーカーとして機能する。 - URB を順に reap し、ゼロになった
actual_lenが見えたら、解放されたスロットをすぐに識別可能なシェーダで埋め直す。これを繰り返すことで Hole0–Hole3 を既知の順序で4つの連続チャンクとしてマッピングでき、後の隣接依存プリミティブに利用できる。
制約付き書き込みを任意上書きに変える(coalescing の悪用)
PVSCSI は隣接するエントリを AddrA + LenA == AddrB で coalesce し、後続エントリを上方に コンパクト化 する。
- Two-pass overflow: PING(奇数インデックス)で開始して早期に終了し coalescing をスキップするようトリガし、次に PONG(偶数インデックス)でトリガして隙間を埋め、偽 S/G エントリを含むスプレー済みシェーダへ書き込みを継続する。
- Vacuum + payload: エントリ
[1023..2047]を{addr=0,len=0}に設定して coalescing によりそれらを一つにまとめ、論理的な穴を作る。後から配置されたペイロードエントリ(シェーダ内のもの)は 上方へ移動 され、被害者 URB の内部に到達する。 - Adjacency-check bypass:
LenA=0とすると条件はAddrA==AddrBになる。以下のようなペアを作ることで
{addr = X, len = 0}
{addr = X, len = Y}
coalescing により {addr=X,len=Y} に統合される。偶数インデックスのゼロサイズ要素は制約されたオーバーフロー由来、奇数インデックスの値はシェーダ内に存在する。結果として、強制ゼロの dword があっても 任意の16バイトパターン を実現できる。
Coalescing の副作用による Hybrid URB infoleak
- 連続チャンクを並べる:
[Hole0 (free/PING), URB1 (target), URB2 (valid, actual_len=0), URB3 (leak target)]。 - URB1 を連続する偽エントリ(サイズ
0xFFFFFFFF)で満たし、URB2 には最小限だけ触れる。coalescing によりこれらは一つのエントリに統合される;合計0xFFFFFFFF * 0x401により URB1 のactual_lenオフセット上位 dword が 0x400 に設定される。 - コンパクションは後続データを上方へコピーし、URB2 のヘッダを URB1 に引き込む。URB1 は有効なヘッダ(pipe/list ポインタ)を持ち、
actual_len=0x400、かつデータポインタは既に URB2 のバッファ末端にある位置を指す。 - URB1 を reap すると URB3 の直前から 0x400 バイトがコピーされ、URB3 のヘッダ / self-reference の OOB read が発生する。これにより絶対ヒープアドレスが露見し、以後作る偽構造に対する ASLR を破ることができる。
Post-leak primitives (no re-triggering the bug)
- Hole0 を占有するシェーダ内に URB 構造を偽造し、coalescing の「上方移動」を使って URB1 を偽データで置換する。
- URB を永続化する:
URB1.next = Hole0を設定してrefcountをインクリメントする;URB1 を reap すると Hole0 バックの偽 URB が FIFO の先頭に来る。以降のプリミティブは Hole0 を新しい偽 URB で再割当てするだけになる。 - Arbitrary read: 任意の
data_ptrとactual_lenを持つ偽 URB を作り、reap してホストメモリをゲストにコピーさせる。 - Arbitrary write (32-bit):
pipeが制御下のメモリを指す偽 URB を作り、UHCI の TDBuffer writeback を悪用して任意アドレスに選んだ dword を書き込む。 - Arbitrary call: USB pipe のコールバックを上書きする;ホストは
RCX+0x90にある制御データでそれを呼ぶ。WinExecを動的に解決(ゲスト側から Kernel32 を読み)し、RCX+0x100から引数をロードしてWinExec("calc.exe")を呼ぶように渡す CFG-valid gadget inside vmware-vmx を経由してピボットする。
LFH タイミングサイドチャネルで初期バケットオフセットを学習する
- 決定論的な Ping-Pong には LFH の空きチャンクオフセット(16 スロットのうちどれが最初に当たるか)を知る必要がある。同期的な VMware Tools コマンド
vmx.capability.unified_loopと共に VMware backdoor 命令 (inl %%dx, %%eax) を使い、0x4000 バイトの文字列 を渡すと、呼び出しごとに 0x4000 の割り当てが 2 回 強制される。 gettimeofdayで 8 回(16 回の割り当て)の呼び出し時間を計測する;LFH が新しいバケットを作ると一つの呼び出しで一貫したスパイクが現れる。さらに1回分の割り当てを追加して繰り返す:スパイクが同じインデックスに留まればオフセットは奇数、位置がズレれば偶数;ノイズが大きければ再試行する。- 注意:
unified_loopはユニークな文字列を解放不可リストに保存するため O(n) の検索オーバーヘッド が発生しノイズが増える。したがってサイドチャネルは素早く収束させる必要がある。
参考文献
Tip
AWSハッキングを学び、実践する:
HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。


