
VirtualBox 7.2.20 - Alta - Local - Gravação de arquivo - escape de destino href em OVF
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · vbox-ovf-href-dest-escape
Classe: Gravação de arquivo Alcance: Local (host) UI:R
Oracle VM VirtualBox OSS 7.2.20 (f2792cf44) - Oracle
Um usuário do host que importa um OVF/OVA hostil grava bytes de imagem de disco fora da pasta da nova VM. ovf:href é o nome do arquivo de destino. RTPathAbsExCxx não usa RTPATHABS_F_STOP_AT_BASE. O auxiliar de caminho único insere _%i antes do sufixo e não remove o basename.
| ID | ainda sem CVE |
| Classe | Gravação de arquivo (caminho de destino OVF/OVA) |
| Alcance | Local (host) UI:R (a vítima importa um appliance hostil) |
| CWE | CWE-22 |
| CVSS | Alto: 7.8 CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N |
| Produto | Oracle VM VirtualBox OSS |
| Afetado | 7.2.20 (f2792cf44f663989818507e36d3db5f978523c5e) |
| Autenticação | nenhuma no VirtualBox. O usuário do host abre Arquivo/Importar ou VBoxManage import. |
| Licença | GNU Affero GPL v3.0 |
| Laboratório | apenas 127.0.0.1. Harness de código-fonte. O VirtualBox não é inicializado. |
Envie um diretório OVF ou um OVA. Coloque ../somewhere/disk.vmdk ou um caminho absoluto /path/disk.iso em ovf:href. O operador que o importa grava esses bytes de imagem de disco com CREATE_REPLACE usando o UID do importador, incluindo diretórios pai que não existiam. Sufixo obrigatório (vmdk / iso / outras extensões MediumFormat). Isto não é uma gravação de authorized_keys sem sufixo.
| Privilégio | Método + sink | O que concede | Procedência |
|---|---|---|---|
| Integridade | IAppliance::read copia File/href sem remover o basename (ovfreader.cpp). Appliance::interpret() define dest = di.strHref (ApplianceImplImport.cpp 802-851). | O nome do arquivo de destino é escolhido pelo atacante, incluindo ../ e caminhos absolutos. | Comprovado em laboratório (hrefs relativos e absolutos) |
| Integridade | i_ensureUniqueImageFilePath (ApplianceImpl.cpp 1126-1160) chama RTPathAbsExCxx(strAbsName, aMachineFolder, aName) sem RTPATHABS_F_STOP_AT_BASE. A colisão insere _%i antes do sufixo de aName, não de um basename. | O destino único ainda sai da pasta da máquina. ../oracle/WITNESS.vmdk torna-se ../oracle/WITNESS_1.vmdk. | Comprovado em laboratório (unique-keeps-dotdot=yes) |
| Integridade | Importação i_importOneDiskImage AbsEx novamente (ApplianceImplImport.cpp 4169-4171). i_importCreateAndWriteDestinationFile (1043-1053) cria diretórios pai e depois RTFILE_O_CREATE_REPLACE. | Os bytes da imagem de disco vão parar fora da pasta da VM. Um href absoluto ignora a pasta da máquina. O controle disk.vmdk permanece na pasta. | Comprovado em laboratório (relative-escape=yes absolute-href=yes control-in-folder=yes) |
| Reconhecimento | O assistente de importação / VBoxManage import --dry-run mostra o destino. | O caminho é visível. Não é, por si só, um vazamento de segredo. | Inferido |
| Disponibilidade | Destino relativo que cai no disco de outra VM. | Sobrescreve esse arquivo com o UID do importador. | Inferido (mesma gravação CREATE_REPLACE) |
| Fechado | Destino sem sufixo MediumFormat | A importação lança has no extension. Não é uma gravação de authorized_keys / crontab sem sufixo. | Fechado |
| Fechado | Destino NVRAM | Forçado para {vmname}.nvram dentro da pasta da máquina. | Fechado |
| Fechado | Nome da VM .. | sanitiseMachineFilename o desfigura. | Fechado |
| Fechado | Pastas compartilhadas / ExtraData / RawFile serial | Sanitizados no caminho vbox:Machine. | Fechado |
| Fechado | Kernel do host, guest-para-host | Não é este resíduo. Não requer inicialização da VM. Mesmo UID do importador. | Fechado |
A OVA é o caminho limpo: o membro do tar fornece os bytes, o href fornece o destino escapado. Sem 3D, sem Guest Additions, sem VRDP, sem PUEL.
Eu fiquei na tag v7.2.20 (f2792cf44) após a CPU de setembro de 2026 e li a importação de OVF. ExtraData, pastas compartilhadas, destino NVRAM e RawFile serial já estão removidos. O destino do disco não está. interpret() copia di.strHref diretamente para o valor VBox do HardDiskImage:
Utf8Str strFilename = di.strHref;
/* ... */
i_ensureUniqueImageFilePath(strMachineFolder, devType, strFilename);
pNewDesc->i_addEntry(VirtualSystemDescriptionType_HardDiskImage,
hd.strDiskId,
di.strHref,
strFilename,
di.ulSuggestedSizeMB,
strExtraConfig);
ApplianceImpl.cpp 1126-1160 completa esse nome em relação à pasta da máquina sem RTPATHABS_F_STOP_AT_BASE, e então modifica aName no local:
int vrc = RTPathAbsExCxx(strAbsName, aMachineFolder, aName);
/* ... */
const char *pszSuffix = RTPathSuffix(aName.c_str());
offDashNum = pszSuffix ? (size_t)(pszSuffix - aName.c_str()) : aName.length();
aName.replace(offDashNum, cchDashNum, szTmp, cchTmp);
Import repete AbsEx no dest ainda relativo (ApplianceImplImport.cpp 4169-4171) e gravações CREATE_REPLACE. Os testes IPRT documentam a mesma junção: o segundo argumento absoluto prevalece; /VirtualBox/Machines mais ../VirtualBox.xml é /VirtualBox/VirtualBox.xml.
Caminhos errados já registrados: tratar uma gravação de authorized_keys sem sufixo como o resíduo (a importação lança exceção); dest de NVRAM (forçado dentro da pasta); nome de VM .. (sanitizador); pastas compartilhadas / ExtraData / RawFile serial (já sanitizados). Teatro: kernel do host, guest-to-host. O oráculo é uma linha testemunha fora da pasta da máquina mais um disk.vmdk de controle que permaneceu no lugar.
python3 vbox-ovf-href-dest-escape-Abraxas-Labs.py
ou
cd lab
./run.sh
Source harness de interpret dest-join, unique-path e da escrita de importação CREATE_REPLACE. Docker compose, loopback, sem binário VirtualBox. Pasta da máquina /work/Machines/ImportedVM. Oracle /work/oracle.
SUCCESS vbox-ovf-href-dest-escape relative-escape=yes unique-keeps-dotdot=yes absolute-href=yes control-in-folder=yes VBOX-OVF-HREF-DEST-ESCAPE-WITNESS
Remover o basename de ovf:href antes que ele se torne um dest, ou passar RTPATHABS_F_STOP_AT_BASE (e rejeitar nomes absolutos). Rejeitar RTPATH_PROP_DOTDOT_REFS. O unique-path deve modificar o basename, não a string relativa.
f2792cf44f663989818507e36d3db5f978523c5e)ApplianceImplImport.cpp 802-851, 1043-1053, 4169-4171ApplianceImpl.cpp 1126-1160