
VirtualBox 7.2.20 — высокий уровень — локальная — запись файла — выход за пределы каталога назначения через href в OVF
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · vbox-ovf-href-dest-escape
Класс: запись файлов Достижимость: локальная (хост) UI:R
Oracle VM VirtualBox OSS 7.2.20 (f2792cf44) — Oracle
Пользователь хоста, импортирующий враждебный OVF/OVA, записывает байты образа диска за пределами папки новой виртуальной машины. ovf:href — это имя файла назначения. RTPathAbsExCxx не принимает RTPATHABS_F_STOP_AT_BASE. Помощник уникальных путей вставляет _%i перед суффиксом и не отбрасывает базовое имя.
| ID | CVE пока нет |
| Класс | Запись файлов (путь назначения OVF/OVA) |
| Достижимость | Локальная (хост) UI:R (жертва импортирует враждебный appliance) |
| CWE | CWE-22 |
| CVSS | Высокий: 7.8 CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/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. Поместить ../somewhere/disk.vmdk или абсолютный /path/disk.iso в ovf:href. Оператор, импортирующий его, выполняет CREATE_REPLACE-запись этих байтов образа диска от имени импортирующего UID, включая родительские каталоги, которых не существовало. Суффикс обязателен (vmdk / iso / другие расширения MediumFormat). Это не запись authorized_keys без суффикса.
| Привилегия | Метод + точка записи | Что даёт | Происхождение |
|---|---|---|---|
| Целостность | IAppliance::read копирует File/href без отбрасывания базового имени (ovfreader.cpp). Appliance::interpret() задаёт dest = di.strHref (ApplianceImplImport.cpp 802-851). | Имя файла назначения выбирает атакующий, включая ../ и абсолютные пути. | Доказано в лаборатории (относительные и абсолютные href) |
| Целостность | i_ensureUniqueImageFilePath (ApplianceImpl.cpp 1126-1160) вызывает RTPathAbsExCxx(strAbsName, aMachineFolder, aName) без RTPATHABS_F_STOP_AT_BASE. При коллизии вставляется _%i перед суффиксом aName, а не базовое имя. | Уникальный dest всё равно выходит за пределы папки машины. ../oracle/WITNESS.vmdk становится ../oracle/WITNESS_1.vmdk. | Доказано в лаборатории (unique-keeps-dotdot=yes) |
| Целостность | Импорт i_importOneDiskImage снова AbsEx (ApplianceImplImport.cpp 4169-4171). i_importCreateAndWriteDestinationFile (1043-1053) создаёт родительские каталоги, затем RTFILE_O_CREATE_REPLACE. | Байты образа диска попадают за пределы папки ВМ. Абсолютный href игнорирует папку машины. Контрольный disk.vmdk остаётся в папке. | Доказано в лаборатории (relative-escape=yes absolute-href=yes control-in-folder=yes) |
| Разведка | Мастер импорта / VBoxManage import --dry-run показывает dest. | Путь виден. Само по себе это не утечка секретов. | Предположительно |
| Доступность | Относительный dest, попадающий на диск другой ВМ. | Перезапись этого файла от имени импортирующего UID. | Предположительно (та же запись CREATE_REPLACE) |
| Закрыто | Dest без суффикса MediumFormat | Импорт выдаёт has no extension. Это не запись authorized_keys / crontab без суффикса. | Закрыто |
| Закрыто | Dest NVRAM | Принудительно {vmname}.nvram в папке машины. | Закрыто |
| Закрыто | Имя ВМ .. | sanitiseMachineFilename искажает его. | Закрыто |
| Закрыто | Общие папки / ExtraData / последовательный RawFile | Санитизируются на пути vbox:Machine. | Закрыто |
| Закрыто | Ядро хоста, гость-в-хост | Не этот остаток. Запуск ВМ не требуется. Тот же UID, что у импортирующего. | Закрыто |
OVA — это чистый путь: элемент tar предоставляет байты, href — экранированный dest. Без 3D, без Guest Additions, без VRDP, не PUEL.
Я остановился на теге v7.2.20 (f2792cf44) после CPU за сентябрь 2026 и прочитал импорт OVF. ExtraData, общие папки, dest NVRAM и последовательный RawFile уже вырезаны. А dest диска — нет. interpret() копирует di.strHref напрямую в значение VBox 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 дополняет это имя относительно папки машины без RTPATHABS_F_STOP_AT_BASE, затем изменяет aName на месте:
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 повторно применяет AbsEx к всё ещё относительному dest (ApplianceImplImport.cpp 4169-4171) и выполняет CREATE_REPLACE-записи. Тесты IPRT документируют то же объединение: абсолютный второй аргумент побеждает; /VirtualBox/Machines плюс ../VirtualBox.xml даёт /VirtualBox/VirtualBox.xml.
Уже зафиксированные неверные пути: трактовка записи authorized_keys без суффикса как остатка (import выбрасывает исключение); dest NVRAM (принудительно внутри папки); имя VM .. (санитайзер); общие папки / ExtraData / последовательный RawFile (уже санитизированы). Театр: хост-ядро, гость-к-хосту. Оракул — строка-свидетель вне папки машины плюс контрольный disk.vmdk, который остался на месте.
python3 vbox-ovf-href-dest-escape-Abraxas-Labs.py
или
cd lab
./run.sh
Исходный harness для interpret dest-join, unique-path и записи импорта CREATE_REPLACE. Docker compose, loopback, без бинарника VirtualBox. Папка машины /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
Удалите базовое имя из ovf:href до того, как оно станет dest, или передайте RTPATHABS_F_STOP_AT_BASE (и отклоняйте абсолютные имена). Отклоняйте RTPATH_PROP_DOTDOT_REFS. Unique-path должен изменять базовое имя, а не относительную строку.
f2792cf44f663989818507e36d3db5f978523c5e)ApplianceImplImport.cpp 802-851, 1043-1053, 4169-4171ApplianceImpl.cpp 1126-1160