
Oracle VM VirtualBox 7.2.20 - 높음 - 로컬 - 파일 읽기 - VMDK 스파스 FLAT extent 경로 결합
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · vbox-vmdk-sparse-extent
분류: 파일 읽기 도달 범위: 로컬(호스트) UI:R
Oracle VM VirtualBox OSS 7.2.20 (f2792cf44) - Oracle
디스크가 sparse VMDK 디스크립터와 FLAT extent로 구성된 OVF 디렉터리 또는 OVA를 가져오는 호스트 사용자는 해당 extent에 명시된 호스트 경로를 열고 그 바이트를 가져온 디스크로 복사하게 된다. vmdkParseDescriptor 이후, pszBasename이 RTPATH_SLASH로 시작하는 각 extent는 그대로 사용되며, 그렇지 않으면 ../를 따라가는 RTPathJoinA(descriptor dir, pszBasename)가 사용된다. 그런 다음 FLAT 및 HOSTED_SPARSE는 해당 전체 경로로 vmdkFileOpen을 호출한다. streamOptimized(일반적인 VirtualBox 내보내기, VMDK 매직)는 단일 파일이며 이 경로 탐색을 거치지 않는다. 가져오기는 여전히 sparse 지정자를 허용한다.
| ID | 아직 CVE 없음 |
| 분류 | 파일 읽기 (sparse VMDK FLAT/sparse extent 경로) |
| 도달 범위 | 로컬(호스트) UI:R (피해자가 악성 어플라이언스를 가져옴) |
| CWE | CWE-22 |
| CVSS | 높음: 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를 배포한다. sparse VMDK 디스크립터(# Disk DescriptorFile, createType="monolithicFlat")를 인용된 basename이 ../../somewhere/secret 또는 /path/secret인 FLAT extent 옆에 둔다. 이를 가져오는 운영자는 가져오는 UID로 해당 호스트 경로를 열고 바이트를 대상 디스크로 복사한다. streamOptimized(VMDK 매직 0x564D444B)는 내장된 FLAT 이름을 참조하지 않는다. 이는 VBox UID가 열 수 있는 파일에 대한 읽기이며, authorized_keys에 대한 접미사 없는 쓰기는 아니다.
| 권한 | 방법 + 싱크 | 부여하는 것 | 출처 |
|---|---|---|---|
| 정찰 | 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) |
| 정찰 | 동일한 경로 탐색. pszBasename[0] == RTPATH_SLASH는 그대로 사용됨 (VMDK.cpp 3477-3485). | 절대 호스트 경로가 열리고 복사됨. 실험실 /work/oracle/VBOX-VMDK-SPARSE-EXTENT-WITNESS. | 실험실 입증 (absolute-extent=yes) |
| 정찰 | 디스크립터 디렉터리 아래에 결합된 FLAT disk-flat.vmdk 제어. | 폴더 내에 머무름. 실험실 전체 이름 /work/import/disk/disk-flat.vmdk. 바이트 CONTROL-FLAT-NOT-ORACLE. | 실험실 입증 (control-in-folder=yes) |
| 정찰 | VMDK 매직이 있는 streamOptimized. vmdkDescriptorRead가 vmdkDescriptorReadSparse를 취함. 내장된 ASCII FLAT이 오라클을 지정함. | 내장된 이름을 열지 않음. Dest는 스트림 파일로 유지됨 (STREAMOPTIMIZED-SELF-NOT-ORACLE). | 실험실 입증 (streamoptimized-consults-extent=no) |
| 정찰 | 게스트 시작 후 변환된 볼륨 읽기. | 게스트는 dest에 들어간, 가져오기 UID가 읽을 수 있는 호스트 파일 내용을 봄. | 추론됨 (동일한 복사; 실험실은 게스트를 부팅하지 않음) |
| 가용성 | 이미 존재하는 가져오기 dest, 또는 변환된 디스크의 이후 연결. | dest 디스크의 가용성 덮어쓰기. 내용은 열린 호스트 파일이 됨. | 추론됨 (dest의 동일한 쓰기) |
| 닫힘 | streamOptimized VMDK (일반적인 VirtualBox 내보내기) | 매직 분기. 단일 파일. 내장된 FLAT 이름은 열리지 않음. | 닫힘 |
| 닫힘 | Windows 드라이브 문자 절대 경로 (C:\...) | pszBasename[0] == RTPATH_SLASH를 놓칠 수 있음. 코드는 절대 경로 검사를 해킹이라고 부름 (@todo implement proper path absolute check). | 닫힘 |
| 닫힘 | 접미사 없는 쓰기 (authorized_keys, crontab) | 쓰기 잔여물이 아님. Extent 열기는 지정된 호스트 경로의 읽기임. | 닫힘 |
| 닫힘 | 호스트 커널, 게스트-호스트, 다른 VM, VBoxSVC 메모리 | 이 잔여물이 아님. 복사에 VM 시작이 필요 없음. 가져오기와 동일한 UID. | 닫힘 |
OVA는 스파스 디스크립터가 디스크에 올라간 후 동일한 경로 탐색임: tar 멤버가 디스크립터와 (선택적) 폴더 내 FLAT을 제공하고, extent basename이 이스케이프된 열기를 제공함. 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 이후, extent basename은 ../를 축약하거나 절대 경로를 거부하지 않고 결합됨:
/* 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를 호출하고 이미 열린 파일을 extent로 유지합니다. 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 extent 조인, vmdkFileOpen, streamOptimized 매직 분기의 소스 하네스. Docker compose, 루프백 127.0.0.1:19250, VirtualBox 바이너리 없음. 디스크립터 디렉터리 /work/import/disk. 오라클 /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을 거부합니다. 또는 디스크립터 디렉터리 하위에서만 extent를 엽니다(RTPATHABS_F_STOP_AT_BASE / realpath-under-base). pszBasename[0] == RTPATH_SLASH를 완전한 절대 경로 검사로 간주하지 마십시오.
f2792cf44f663989818507e36d3db5f978523c5e)VMDK.cpp vmdkDescriptorReadSparse 3312, vmdkDescriptorReadAscii extent join 3472-3547, vmdkDescriptorRead 3576-3589ApplianceImpl.cpp g_pszVMDKSparseURI 61, 78ApplianceImplImport.cpp i_importOneDiskImage 4343-4408GNU Affero GPL v3.0. LICENSE를 참조하십시오. 루프백 실험실 전용입니다. 보증하지 않습니다.