
Oracle VM VirtualBox 7.2.20 - 高 - ローカル - ファイル読み取り - VMDK スパース FLAT エクステントのパス結合
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · vbox-vmdk-sparse-extent
クラス: ファイル読み取り 到達範囲: ローカル (ホスト) UI:R
Oracle VM VirtualBox OSS 7.2.20 (f2792cf44) - Oracle
ディスクがスパース VMDK ディスクリプタと FLAT エクステントで構成された OVF ディレクトリまたは OVA をインポートするホストユーザーは、そのエクステント内で指定されたホストパスを開き、そのバイト列をインポートされたディスクへコピーしてしまう。vmdkParseDescriptor の後、pszBasename が RTPATH_SLASH で始まる各エクステントはそのまま使用され、そうでなければ RTPathJoinA(descriptor dir, pszBasename) が使われ、これは ../ を辿る。その後 FLAT および HOSTED_SPARSE はその完全パスを vmdkFileOpen する。streamOptimized (通常の VirtualBox エクスポート、VMDK マジック) は単一ファイルであり、この経路を辿らない。インポートは依然としてスパース指定子を受け付ける。
| ID | CVE 未割当 |
| クラス | ファイル読み取り (スパース VMDK の FLAT/スパースエクステントパス) |
| 到達範囲 | ローカル (ホスト) UI:R (被害者が悪意あるアプライアンスをインポートする) |
| CWE | CWE-22 |
| CVSS | High: 7.7 CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N |
| 製品 | Oracle VM VirtualBox OSS |
| 影響バージョン | 7.2.20 (f2792cf44f663989818507e36d3db5f978523c5e) |
| 認証 | VirtualBox 上では不要。ホストユーザーが File/Import を開くか、VBoxManage import を実行する。 |
| ライセンス | GNU Affero GPL v3.0 |
| ラボ | 127.0.0.1 のみ。ソースハーネス。VirtualBox は起動しない。 |
OVF ディレクトリまたは OVA を配布する。スパース VMDK ディスクリプタ (# Disk DescriptorFile、createType="monolithicFlat") を、引用符で囲まれたベース名が ../../somewhere/secret または /path/secret である FLAT エクステントの隣に置く。これをインポートするオペレーターは、インポートを実行する UID としてそのホストパスを開き、バイト列を宛先ディスクへコピーしてしまう。streamOptimized (VMDK マジック 0x564D444B) は埋め込まれた FLAT 名を参照しない。これは VBox UID が開けるファイルの読み取りであり、authorized_keys へのサフィックスなしの書き込みではない。
| 権限 | 手法 + シンク | 得られるもの | 来歴 |
|---|---|---|---|
| Recon | ASCII スパース VMDK のインポート。vmdkParseDescriptor の後、RTPathJoinA(descriptor dir, pszBasename) が ../ を折りたたまずに実行される(VMDK.cpp 3472-3503)。そのフルパスに対して FLAT の vmdkFileOpen が行われる。インポートはそれらのバイトを dest にコピーする。 | ../ で指定されたホストファイルのバイトがインポートされたディスクに格納される。ラボでは pszBasename の ../../oracle/VBOX-VMDK-SPARSE-EXTENT-WITNESS が /work/import/disk/../../oracle/... に結合され、/work/import/out.vmdk にコピーされた。 | ラボで実証済み(relative-escape=yes) |
| Recon | 同じ処理。pszBasename[0] == RTPATH_SLASH はそのまま使用される(VMDK.cpp 3477-3485)。 | 絶対ホストパスが開かれ、コピーされる。ラボでは /work/oracle/VBOX-VMDK-SPARSE-EXTENT-WITNESS。 | ラボで実証済み(absolute-extent=yes) |
| Recon | 対照として FLAT の disk-flat.vmdk がディスクリプタディレクトリ配下に結合される。 | フォルダ内に留まる。ラボでのフルネームは /work/import/disk/disk-flat.vmdk。バイト列は CONTROL-FLAT-NOT-ORACLE。 | ラボで実証済み(control-in-folder=yes) |
| Recon | VMDK マジック付きの streamOptimized。vmdkDescriptorRead は vmdkDescriptorReadSparse を取る。埋め込まれた ASCII FLAT がオラクルを指定していた。 | 埋め込まれた名前は開かれなかった。dest はストリームファイルのまま(STREAMOPTIMIZED-SELF-NOT-ORACLE)。 | ラボで実証済み(streamoptimized-consults-extent=no) |
| Recon | ゲストを起動し、変換されたボリュームを読み取る。 | ゲストは、インポータの UID で読み取り可能なホストファイルの内容が dest に格納されたものを参照できる。 | 推測(同じコピー。ラボではゲストを起動しない) |
| 可用性 | 既に存在するインポート dest、または変換されたディスクの後からのアタッチ。 | dest ディスクの可用性を上書きする。内容は開かれたホストファイルになる。 | 推測(dest への同じ書き込み) |
| クローズ | streamOptimized VMDK(通常の VirtualBox エクスポート) | マジック分岐。単一ファイル。埋め込まれた FLAT 名は開かれない。 | クローズ |
| クローズ | Windows ドライブレターの絶対パス(C:\...) | pszBasename[0] == RTPATH_SLASH を見逃す可能性がある。コードは絶対パスチェックをハックと呼んでいる(@todo implement proper path absolute check)。 | クローズ |
| クローズ | サフィックスなしの書き込み(authorized_keys、crontab) | 書き込みの残存物ではない。エクステントのオープンは指定されたホストパスの読み取りである。 | クローズ |
| クローズ | ホストカーネル、ゲストからホスト、他の VM、VBoxSVC メモリ | この残存物ではない。コピーに VM の起動は不要。インポータと同じ UID。 | クローズ |
OVA も、スパースディスクリプタがディスク上に置かれた後は同じ処理である。tar メンバーがディスクリプタと(任意の)フォルダ内 FLAT を提供し、エクステントのベース名がエスケープされたオープンを提供する。3D なし、Guest Additions なし、VRDP なし、PUEL ではない。
2026年9月の CPU の後、タグ v7.2.20(f2792cf44)に留まり、VMDK インポートを読んだ。ExtraData、共有フォルダ、NVRAM dest、シリアル RawFile は既に除去されている。ovf:href dest は兄弟の残存物である。通常の VirtualBox エクスポートは streamOptimized である。interpret() は依然としてスパース指定子(g_pszVMDKSparseURI)を受け入れる。vmdkParseDescriptor の後、エクステントのベース名は ../ を折りたたまず、絶対パスを拒否せずに結合される:
/* Hack to figure out whether the specified name in the
* extent descriptor is absolute. Doesn't always work, but
* should be good enough for now. */
char *pszFullname;
/** @todo implement proper path absolute check. */
if (pExtent->pszBasename[0] == RTPATH_SLASH)
{
pszFullname = RTStrDup(pExtent->pszBasename);
/* ... */
}
else
{
char *pszDirname = RTStrDup(pImage->pszFilename);
RTPathStripFilename(pszDirname);
pszFullname = RTPathJoinA(pszDirname, pExtent->pszBasename);
/* ... */
}
pExtent->pszFullname = pszFullname;
RTPathJoinA はスラッシュのバランス調整のみを行います。.. の折りたたみは行いません。その後、FLAT と HOSTED_SPARSE がその文字列を開きます:
case VMDKETYPE_FLAT:
rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszBasename, pExtent->pszFullname,
VDOpenFlagsToFileOpenFlags(uOpenFlags, false /* fCreate */));
vmdkDescriptorRead はマジック値で分岐する。VMDK スパースマジック(0x564D444B)は vmdkDescriptorReadSparse を呼び出し、すでに開かれているファイルをエクステントとして保持する。ASCII の場合は vmdkDescriptorReadAscii と上記の結合処理を呼び出す。
すでに記録済みの誤った分岐:streamOptimized をこの残存物として扱うこと(マジック値は埋め込まれた FLAT 名を参照しない);Windows のドライブレター絶対パスを Unix のスラッシュチェックとして扱うこと;dest-disk の上書きをサフィックスなしの authorized_keys 書き込みとして扱うこと;結合処理のソースハーネスで十分なのに VM を起動すること。見せかけ:ホストカーネル、ゲストからホストへ。オラクルは、ディスクリプタフォルダ外の目撃行と、その場に留まった対照用の disk-flat.vmdk である。
python3 vbox-vmdk-sparse-extent-Abraxas-Labs.py
または
cd lab
./run.sh
vmdkParseDescriptor のエクステント結合、vmdkFileOpen、および streamOptimized マジック分岐のソースハーネス。Docker compose、ループバック 127.0.0.1:19250、VirtualBox バイナリなし。ディスクリプタディレクトリ /work/import/disk。Oracle /work/oracle。出力先 /work/import/out.vmdk。
SUCCESS vbox-vmdk-sparse-extent relative-escape=yes absolute-extent=yes control-in-folder=yes VBOX-VMDK-SPARSE-EXTENT-WITNESS
pszBasename 内の .. を折りたたむか拒否します。絶対パスの pszBasename を拒否します。または、ディスクリプタディレクトリ配下でのみエクステントを開きます(RTPATHABS_F_STOP_AT_BASE / realpath-under-base)。pszBasename[0] == RTPATH_SLASH を完全な絶対パスチェックとして扱わないでください。
f2792cf44f663989818507e36d3db5f978523c5e)VMDK.cpp vmdkDescriptorReadSparse 3312、vmdkDescriptorReadAscii エクステント結合 3472-3547、vmdkDescriptorRead 3576-3589ApplianceImpl.cpp g_pszVMDKSparseURI 61、78ApplianceImplImport.cpp i_importOneDiskImage 4343-4408GNU Affero GPL v3.0。LICENSE を参照してください。ループバックラボ専用です。保証はありません。