Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
vbox-vmdk-sparse-extent — Oracle VM VirtualBox 7.2.20 - High - Local - File read - VMDK sparse FLAT extent path join | Kitploit
Tools/GitHubGitHub/abraxas/vbox-vmdk-sparse-extent
Vulnerability AnalysisExploitationWeb Application ExploitationSecurity VirtualizationPenetration TestingLabs & Practice
GitHubabraxas/vbox-vmdk-sparse-extent

vbox-vmdk-sparse-extent

Oracle VM VirtualBox 7.2.20 - High - Local - File read - VMDK sparse FLAT extent path join

View Repository
22 days agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

Abraxas Labs - vbox-vmdk-sparse-extent

abraxaslabs.tech  ·  github.com/abraxas  ·  @abraxas_null  ·  [email protected]  ·  vbox-vmdk-sparse-extent

vbox-vmdk-sparse-extent

Class: File read Reach: Local (host) UI:R

Oracle VM VirtualBox OSS 7.2.20 (f2792cf44) - Oracle

A host user who imports an OVF directory or OVA whose disk is a sparse VMDK descriptor plus FLAT extent opens a host path named in that extent and copies those bytes into the imported disk. After vmdkParseDescriptor, each extent with pszBasename starting with RTPATH_SLASH is used as-is; otherwise RTPathJoinA(descriptor dir, pszBasename) which follows ../. FLAT and HOSTED_SPARSE then vmdkFileOpen that full path. streamOptimized (usual VirtualBox export, VMDK magic) is a single file and does not take this walk. Import still accepts the sparse specifier.

IDno CVE yet
ClassFile read (sparse VMDK FLAT/sparse extent path)
ReachLocal (host) UI:R (victim imports a hostile appliance)
CWECWE-22
CVSSHigh: 7.7 CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N
ProductOracle VM VirtualBox OSS
Affected7.2.20 (f2792cf44f663989818507e36d3db5f978523c5e)
Authnone on VirtualBox. The host user opens File/Import or VBoxManage import.
LicenseGNU Affero GPL v3.0
Lab127.0.0.1 only. Source harness. VirtualBox is not booted.

What an attacker can do

Ship an OVF directory or an OVA. Put a sparse VMDK descriptor (# Disk DescriptorFile, createType="monolithicFlat") next to a FLAT extent whose quoted basename is ../../somewhere/secret or /path/secret. The operator who imports it opens that host path as the importing UID and copies the bytes into the dest disk. streamOptimized (VMDK magic 0x564D444B) does not consult the embedded FLAT name. This is a read of files the VBox UID can open, not a suffix-free write of authorized_keys.

PrivilegeMethod + sinkWhat it grantsProvenance
ReconImport of an ASCII sparse VMDK. After vmdkParseDescriptor, RTPathJoinA(descriptor dir, pszBasename) with no ../ collapse (VMDK.cpp 3472-3503). FLAT vmdkFileOpen of that full path. Import copies those bytes into dest.Host file bytes named by ../ land in the imported disk. Lab pszBasename ../../oracle/VBOX-VMDK-SPARSE-EXTENT-WITNESS joined to /work/import/disk/../../oracle/... and copied into /work/import/out.vmdk.Lab-proven (relative-escape=yes)
ReconSame walk. pszBasename[0] == RTPATH_SLASH is used as-is (VMDK.cpp 3477-3485).Absolute host path opened and copied. Lab /work/oracle/VBOX-VMDK-SPARSE-EXTENT-WITNESS.Lab-proven (absolute-extent=yes)
ReconControl FLAT disk-flat.vmdk joined under the descriptor directory.Stays in-folder. Lab fullname /work/import/disk/disk-flat.vmdk. Bytes CONTROL-FLAT-NOT-ORACLE.Lab-proven (control-in-folder=yes)
ReconstreamOptimized with VMDK magic. vmdkDescriptorRead takes vmdkDescriptorReadSparse. Embedded ASCII FLAT named the oracle.Did not open the embedded name. Dest stayed the stream file (STREAMOPTIMIZED-SELF-NOT-ORACLE).Lab-proven (streamoptimized-consults-extent=no)
ReconGuest Start, then read the converted volume.Guest sees importer-UID-readable host file contents that landed in dest.Inferred (same copy; lab does not boot a guest)
AvailabilityImport dest that already exists, or a later attach of the converted disk.Overwrite availability of dest disk. Contents become the opened host file.Inferred (same write of dest)
ClosedstreamOptimized VMDK (usual VirtualBox export)Magic branch. Single file. Embedded FLAT name is not opened.Closed
ClosedWindows drive-letter absolute (C:\...)May miss pszBasename[0] == RTPATH_SLASH. The code calls the absolute check a hack (@todo implement proper path absolute check).Closed
ClosedSuffix-free writes (authorized_keys, crontab)Not a write leftover. Extent open is a read of the named host path.Closed
ClosedHost kernel, guest-to-host, other VMs, VBoxSVC memoryNot this leftover. No VM start required for the copy. Same UID as the importer.Closed

OVA is the same walk once the sparse descriptor is on disk: tar member supplies the descriptor plus (optional) in-folder FLAT; the extent basename supplies the escaped open. No 3D, no Guest Additions, no VRDP, not PUEL.

How I found it

I sat on tag v7.2.20 (f2792cf44) after the Sep 2026 CPU and read VMDK import. ExtraData, shared folders, NVRAM dest, and serial RawFile are already stripped. ovf:href dest is a sibling leftover. The usual VirtualBox export is streamOptimized. interpret() still accepts the sparse specifier (g_pszVMDKSparseURI). After vmdkParseDescriptor, the extent basename is joined without collapsing ../ or rejecting absolute paths:

/* 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 slash-balances only. It does not collapse ... FLAT and HOSTED_SPARSE then open that string:

case VMDKETYPE_FLAT:
    rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszBasename, pExtent->pszFullname,
                      VDOpenFlagsToFileOpenFlags(uOpenFlags, false /* fCreate */));

vmdkDescriptorRead splits on magic. VMDK sparse magic (0x564D444B) takes vmdkDescriptorReadSparse and keeps the already-open file as the extent. ASCII takes vmdkDescriptorReadAscii and the join above.

Wrong turns already recorded: treating streamOptimized as this leftover (magic does not consult the embedded FLAT name); treating a Windows drive-letter absolute as the Unix slash check; treating dest-disk overwrite as a suffix-free authorized_keys write; booting a VM when the source harness of the join is enough. Theatre: host kernel, guest-to-host. The oracle is a witness line outside the descriptor folder plus a control disk-flat.vmdk that stayed put.

Lab

python3 vbox-vmdk-sparse-extent-Abraxas-Labs.py

or

cd lab
./run.sh

Source harness of vmdkParseDescriptor extent join, vmdkFileOpen, and the streamOptimized magic branch. Docker compose, loopback 127.0.0.1:19250, no VirtualBox binary. Descriptor dir /work/import/disk. Oracle /work/oracle. Dest /work/import/out.vmdk.

SUCCESS vbox-vmdk-sparse-extent relative-escape=yes absolute-extent=yes control-in-folder=yes VBOX-VMDK-SPARSE-EXTENT-WITNESS

The fix

Download Tool