
Oracle VM VirtualBox 7.2.20 - Élevée - Locale - Lecture de fichier - jointure de chemin d'extension FLAT sparse VMDK
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · vbox-vmdk-sparse-extent
Classe : Lecture de fichier Portée : Local (hôte) UI:R
Oracle VM VirtualBox OSS 7.2.20 (f2792cf44) - Oracle
Un utilisateur de l'hôte qui importe un répertoire OVF ou un OVA dont le disque est un descripteur VMDK sparse accompagné d'une extent FLAT ouvre un chemin de l'hôte nommé dans cette extent et copie ces octets dans le disque importé. Après vmdkParseDescriptor, chaque extent dont le pszBasename commence par RTPATH_SLASH est utilisée telle quelle ; sinon RTPathJoinA(descriptor dir, pszBasename) qui suit les ../. FLAT et HOSTED_SPARSE effectuent ensuite vmdkFileOpen sur ce chemin complet. streamOptimized (export VirtualBox habituel, magie VMDK) est un fichier unique et ne suit pas ce parcours. L'import accepte toujours le spécificateur sparse.
| ID | pas encore de CVE |
| Classe | Lecture de fichier (chemin d'extent FLAT/sparse d'un VMDK sparse) |
| Portée | Local (hôte) UI:R (la victime importe une appliance hostile) |
| CWE | CWE-22 |
| CVSS | Élevé : 7.7 CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N |
| Produit | Oracle VM VirtualBox OSS |
| Affecté | 7.2.20 (f2792cf44f663989818507e36d3db5f978523c5e) |
| Auth | aucune sur VirtualBox. L'utilisateur de l'hôte ouvre Fichier/Importer ou VBoxManage import. |
| Licence | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1 uniquement. Harnais source. VirtualBox n'est pas démarré. |
Livrer un répertoire OVF ou un OVA. Placer un descripteur VMDK sparse (# Disk DescriptorFile, createType="monolithicFlat") à côté d'une extent FLAT dont le basename entre guillemets est ../../somewhere/secret ou /path/secret. L'opérateur qui l'importe ouvre ce chemin de l'hôte avec l'UID importateur et copie les octets dans le disque de destination. streamOptimized (magie VMDK 0x564D444B) ne consulte pas le nom FLAT intégré. Il s'agit d'une lecture de fichiers que l'UID VBox peut ouvrir, et non d'une écriture sans suffixe de authorized_keys.
| Privilège | Méthode + sink | Ce que cela accorde | Provenance |
|---|---|---|---|
| Recon | Import d'un VMDK sparse ASCII. Après vmdkParseDescriptor, RTPathJoinA(descriptor dir, pszBasename) sans réduction des ../ (VMDK.cpp 3472-3503). vmdkFileOpen FLAT de ce chemin complet. L'import copie ces octets dans dest. | Les octets du fichier hôte nommés par ../ atterrissent dans le disque importé. Lab pszBasename ../../oracle/VBOX-VMDK-SPARSE-EXTENT-WITNESS joint à /work/import/disk/../../oracle/... et copié dans /work/import/out.vmdk. | Prouvé en lab (relative-escape=yes) |
| Recon | Même parcours. pszBasename[0] == RTPATH_SLASH est utilisé tel quel (VMDK.cpp 3477-3485). | Chemin hôte absolu ouvert et copié. Lab /work/oracle/VBOX-VMDK-SPARSE-EXTENT-WITNESS. | Prouvé en lab (absolute-extent=yes) |
| Recon | Contrôle FLAT disk-flat.vmdk joint sous le répertoire du descripteur. | Reste dans le dossier. Lab fullname /work/import/disk/disk-flat.vmdk. Octets CONTROL-FLAT-NOT-ORACLE. | Prouvé en lab (control-in-folder=yes) |
| Recon | streamOptimized avec magie VMDK. vmdkDescriptorRead prend vmdkDescriptorReadSparse. FLAT ASCII embarqué nommant l'oracle. | N'a pas ouvert le nom embarqué. Dest est resté le fichier stream (STREAMOPTIMIZED-SELF-NOT-ORACLE). | Prouvé en lab (streamoptimized-consults-extent=no) |
| Recon | Démarrage de l'invité, puis lecture du volume converti. | L'invité voit le contenu du fichier hôte lisible par l'UID de l'importateur qui a atterri dans dest. | Déduit (même copie ; le lab ne démarre pas d'invité) |
| Disponibilité | Dest d'import qui existe déjà, ou un attachement ultérieur du disque converti. | Écrasement de la disponibilité du disque dest. Le contenu devient le fichier hôte ouvert. | Déduit (même écriture de dest) |
| Fermé | VMDK streamOptimized (export VirtualBox habituel) | Branche magie. Fichier unique. Le nom FLAT embarqué n'est pas ouvert. | Fermé |
| Fermé | Lettre de lecteur Windows absolue (C:\...) | Peut manquer pszBasename[0] == RTPATH_SLASH. Le code qualifie la vérification absolue de hack (@todo implement proper path absolute check). | Fermé |
| Fermé | Écritures sans suffixe (authorized_keys, crontab) | Pas un résidu d'écriture. L'ouverture d'extent est une lecture du chemin hôte nommé. | Fermé |
| Fermé | Noyau hôte, invité-vers-hôte, autres VM, mémoire VBoxSVC | Pas ce résidu. Aucun démarrage de VM requis pour la copie. Même UID que l'importateur. | Fermé |
OVA suit le même parcours une fois le descripteur sparse sur disque : le membre tar fournit le descripteur plus (en option) le FLAT dans le dossier ; le basename de l'extent fournit l'ouverture échappée. Pas de 3D, pas de Guest Additions, pas de VRDP, pas de PUEL.
Je me suis arrêté sur le tag v7.2.20 (f2792cf44) après le CPU de septembre 2026 et j'ai lu l'import VMDK. ExtraData, dossiers partagés, dest NVRAM et serial RawFile sont déjà retirés. Le dest ovf:href est un résidu voisin. L'export VirtualBox habituel est streamOptimized. interpret() accepte toujours le spécificateur sparse (g_pszVMDKSparseURI). Après vmdkParseDescriptor, le basename de l'extent est joint sans réduire les ../ ni rejeter les chemins absolus :
/* 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 équilibre uniquement les barres obliques. Il ne réduit pas ... FLAT et HOSTED_SPARSE ouvrent ensuite cette chaîne :
case VMDKETYPE_FLAT:
rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszBasename, pExtent->pszFullname,
VDOpenFlagsToFileOpenFlags(uOpenFlags, false /* fCreate */));
vmdkDescriptorRead effectue un split sur le magic. Le magic sparse VMDK (0x564D444B) passe par vmdkDescriptorReadSparse et conserve le fichier déjà ouvert comme extent. L'ASCII passe par vmdkDescriptorReadAscii et la jointure ci-dessus.
Fausses pistes déjà consignées : traiter streamOptimized comme ce résidu (le magic ne consulte pas le nom FLAT intégré) ; traiter un chemin absolu avec lettre de lecteur Windows comme la vérification slash Unix ; traiter l'écrasement du disque de destination comme une écriture authorized_keys sans suffixe ; démarrer une VM alors que le harness source de la jointure suffit. Théâtre : noyau hôte, invité-vers-hôte. L'oracle est une ligne témoin en dehors du dossier du descripteur plus un disk-flat.vmdk de contrôle resté en place.
python3 vbox-vmdk-sparse-extent-Abraxas-Labs.py
ou
cd lab
./run.sh