VMware Workstation PVSCSI LFH Escape (VMware-vmx on Windows 11)
Tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
버그 해부: fixed-size realloc + 분산된 OOB 쓰기
PVSCSI_FillSGI는 게스트의 scatter/gather 엔트리를 내부 배열로 복사한다. 초기에는 512 엔트리 정적 버퍼(0x2000)로 시작한다. 512를 초과하면 0x4000 바이트로 realloc하고, 기능적 버그 때문에 매 반복마다 realloc이 발생한다.- 재할당 크기는 커지지 않음: 0x4000 / 0x10-바이트 엔트리 = 1024 사용 가능 엔트리. 게스트가 >1024 엔트리를 공급하면, 각 새 엔트리는 방금 할당된 0x4000 청크보다 16바이트 뒤에 기록되어 인접 청크 헤더 또는 객체를 손상시킨다.
- 오버플로우 내용: VMware는
{u64 addr; u64 len}을 저장하는데; 게스트는{u64 addr; u32 len; u32 flags}를 제공한다. 32비트len은 제로 확장(zero-extended) 되므로, 모든 16바이트 OOB 요소의 마지막 dword는 항상 0x00000000 이다.
LFH 제약 & 결정론적 “Ping-Pong” 배치
- 0x4000 할당은 Windows 11 LFH에 배치된다 (버킷당 16개 청크, 0x10-바이트 메타데이터와 keyed checksum). 이후에 헤더 checksum이 맞지 않는 청크를 건드리면 프로세스가 종료되므로, 손상된 헤더는 절대 재사용되어서는 안 된다.
- LFH는 랜덤한 free 청크를 반환하지만 가장 최근에 해제된 청크를 포함하는 버킷을 우선한다. 두 개의 무료 슬롯만 강제하려면:
- 할당기를 정렬하기 위해 모든 무료 0x4000 청크를 할당; 32 SVGA shaders를 스프레이하여 B1과 B2 버킷을 채운다.
- B1에서 하나의 고정된 shader(Hole0)만 남기고 나머지를 해제해 B1을 활성 상태로 유지; B1에 15 URBs를 할당한다.
- B2에서 하나의 shader(PONG)를 해제한 다음 즉시 Hole0을 해제한다. LFH는 두 개의 사용 가능한 슬롯 PING (B1) 과 PONG (B2) 사이에서 번갈아 할당한다.
- 1025번째 반복은 PONG 뒤의 헤더를 손상시키며(이후 절대 접근하지 않음); 1026번째 반복은 PING 뒤의 URB 첫 16바이트를 건드려(메타데이터 우회로 안전) 적용된다. 레이아웃을 안정적으로 반복하기 위해 자리 표시자 shaders로 PING/PONG을 회수(reclaim)한다.
Reap Oracle: 연속된 홀 표시
- UHCI URB는 FIFO 큐에 존재하며 완전히 reaped 되면 해제된다. 제약된 16바이트 덮어쓰기 때문에
actual_len은 항상 0이 되어 마커를 제공한다. - URB를 순서대로 reap; 0으로 된
actual_len이 보이면 즉시 해제된 슬롯을 식별 가능한 shader로 채운다. 이를 반복하면 이후 인접성 기반 프리미티브를 위해 Hole0–Hole3을 알려진 순서의 네 개 연속 청크로 매핑할 수 있다.
제한된 쓰기를 임의 덮어쓰기로 전환하기 (coalescing 남용)
PVSCSI는 인접 엔트리를 AddrA + LenA == AddrB 조건으로 병합(coalesce)하고, 이후 엔트리를 위로 compact 한다.
- 두 단계 오버플로우: PING(홀수 인덱스)에서 시작해 coalescing을 건너뛰도록 일찍 종료시킨 뒤; PONG(짝수 인덱스)에서 다시 트리거하여 갭을 채우고 fake S/G 엔트리를 포함한 스프레이된 shader로 계속 쓰기를 진행한다.
- Vacuum + payload:
[1023..2047]엔트리를{addr=0,len=0}로 설정하면 coalescing이 이들을 하나로 압축해 논리적 홀을 만든다. 그 이후 shader에 배치된 페이로드 엔트리들은 위로 이동되어 이전 메모리로 들어가 피해 URB 내부에 위치하게 된다. - 인접성 체크 우회:
LenA=0으로 설정하면 조건이AddrA==AddrB가 된다. 다음과 같은 쌍을 구성하라:
{addr = X, len = 0}
{addr = X, len = Y}
coalescing은 이를 {addr=X,len=Y}로 합친다. 짝수 인덱스의 제로-사이즈 요소는 제약된 오버플로우에서 나오고; 홀수 인덱스 값은 shader에 존재한다. 결과: 강제된 제로 dword에도 불구하고 임의의 16바이트 패턴을 만들 수 있다.
Hybrid URB infoleak via coalescing side-effects
- 연속된 청크를 배치:
[Hole0 (free/PING), URB1 (target), URB2 (valid, actual_len=0), URB3 (leak target)]. - URB1을 연속된 fake 엔트리(크기
0xFFFFFFFF)로 채우고 URB2는 최소한으로 건드린다. Coalescing은 이들을 하나로 합치고; 합계0xFFFFFFFF * 0x401는 URB1의actual_len오프셋 상위 dword를 0x400으로 설정한다. - 압축(compaction)은 뒤따르는 데이터를 위로 복사하여 URB2의 헤더를 URB1로 끌어온다. 이제 URB1은 유효한 헤더(파이프/리스트 포인터),
actual_len=0x400, 그리고 이미 URB2 버퍼 끝에 위치한 데이터 포인터를 갖게 된다. - URB1을 reap하면 URB3 바로 앞에서 시작하는 0x400 바이트를 복사하여 URB3의 헤더/자기참조를 포함한 OOB read를 일으키고, 이는 절대 힙 주소를 드러내어 이후 위조 구조물에 대한 ASLR을 무력화한다.
Post-leak primitives (no re-triggering the bug)
- Hole0을 차지하는 shader 내부에 URB 구조체를 위조한 다음 coalescing의 “move up“을 이용해 URB1을 위조 데이터로 교체한다.
- URB를 지속화:
URB1.next = Hole0으로 설정하고 refcount를 증가시킨다; URB1을 reap하면 Hole0-기반의 fake URB가 FIFO 헤드에 놓인다. 이후 프리미티브는 Hole0의 재할당만으로 이루어진다. - Arbitrary read: 원하는
data_ptr와actual_len을 가진 fake URB를 만들고 reap하여 호스트 메모리를 게스트로 복사한다. - Arbitrary write (32-bit): pipe가 제어된 메모리를 가리키는 fake URB를 만들고 UHCI의 TDBuffer writeback을 악용해 임의 주소에 선택한 dword를 저장한다.
- Arbitrary call: USB pipe 콜백을 덮어쓴다; 호스트는
RCX+0x90에 제어된 데이터와 함께 호출한다.WinExec를 동적으로 해결(게스트 측에서 Kernel32 읽기)하고vmware-vmx내부의 CFG-유효 가젯으로 피벗하여RCX+0x100에서 인자를 로드한 뒤WinExec("calc.exe")로 전달한다.
LFH timing side-channel to learn the initial bucket offset
- 결정론적 Ping-Pong은 LFH의 free-청크 오프셋(16 슬롯 중 어느 슬롯이 먼저 히트될지)을 알아야 한다. VMware 백도어 명령어(
inl %%dx, %%eax)와 동기화된 VMware Tools 명령vmx.capability.unified_loop및 0x4000-바이트 문자열을 사용하면, 호출당 두 개의 0x4000 할당을 강제한다. gettimeofday로 8번의 호출(16 할당)을 타이밍 측정하면, LFH가 새 버킷을 생성할 때 일관된 스파이크가 하나 나타난다. 한 번 더 할당을 추가해 반복하면: 스파이크가 같은 인덱스에 머물면 오프셋은 홀수, 이동하면 짝수; 그렇지 않으면 노이즈 때문에 재시작.- 주의:
unified_loop는 고유 문자열을 해제 불가능한 리스트에 저장하여 O(n) 조회 오버헤드와 노이즈 증가를 초래하므로, 사이드채널은 빠르게 수렴해야 한다.
References
Tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.


