[Reversemode Advisory] VMware Products - GPF Denial of Service
VMWARE PRODUCTS
VMWARE MEMORY MANAGER - GPF DENIAL OF SERVICE
Rubén Santamarta <ruben@xxxxxxxxxxxxxxx>
07.05.2007
Affected products:
All VMware products with a hypervisor are affected
+ VMware WorkStation 5.5.3 and earlier
+ VMware Player 1.0.3 and earlier
+ VMware Server 1.0.2 and earlier
+ VMware ACE 1.0.2 and earlier
Introduction
Vmware Virtualization products are affected by a design flaw which can
lead to a local DoS vulnerability within the Guest OS. The flaw is due
to improper handling of GPF in Windows Guest Operating Systems (x86) .
Flaw
x86 processors running Protected Mode generate a General Protection
exception (#GP) on any attempt to load an invalid segment selector in
certain segment registers like FS,DS,GS or ES.
Using documented Win32 API any user-mode thread can modify its own
context in such a way that the Kernel will try to load a specially
crafted invalid segment selector, pointing to the LDT, in FS (pop fs)
just before returning to user-mode.
On a physical,meaning opposite to virtual, machine this attempt triggers
a General Protection Fault which is handled internally by KiTrap0D.
KiTrap0D looks for this type of invalid instructions and sanitizes the
wrong selector.
Let's see:
Ntoskrnl.exe
Windows XP SP2
_KTRAP_FRAME
+0x000 DbgEbp : Uint4B
+0x004 DbgEip : Uint4B
+0x008 DbgArgMark : Uint4B
+0x00c DbgArgPointer : Uint4B
+0x010 TempSegCs : Uint4B
+0x014 TempEsp : Uint4B
+0x018 Dr0 : Uint4B
+0x01c Dr1 : Uint4B
+0x020 Dr2 : Uint4B
+0x024 Dr3 : Uint4B
+0x028 Dr6 : Uint4B
+0x02c Dr7 : Uint4B
+0x030 SegGs : Uint4B
+0x034 SegEs : Uint4B
+0x038 SegDs : Uint4B
+0x03c Edx : Uint4B
+0x040 Ecx : Uint4B
+0x044 Eax : Uint4B
+0x048 PreviousPreviousMode : Uint4B
+0x04c ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD
+0x050 SegFs : Uint4B
+0x054 Edi : Uint4B
+0x058 Esi : Uint4B
+0x05c Ebx : Uint4B
+0x060 Ebp : Uint4B
+0x064 ErrCode : Uint4B
+0x068 Eip : Uint4B
+0x06c SegCs : Uint4B
+0x070 EFlags : Uint4B
+0x074 HardwareEsp : Uint4B
+0x078 HardwareSegSs : Uint4B
+0x07c V86Es : Uint4B
+0x080 V86Ds : Uint4B
+0x084 V86Fs : Uint4B
+0x088 V86Gs : Uint4B
KiTrap0D
{...}
.text:0040A116 mov eax, [ebp+68h] ; Eip faulting
.text:0040A119 mov eax, [eax] ; opcode
.text:0040A11B mov edx, [ebp+60h] ; TrapFrame
.text:0040A11E add edx, 38h ; TrapFrame.SegDs
.text:0040A121 cmp al, 1Fh ; Opcode 1F = POP DS
.text:0040A123 jz loc_40A224
.text:0040A129 add edx, 0FFFFFFFCh ; TrapFrame.SegES
.text:0040A12C cmp al, 7 ; Opcode 07 = POP ES
.text:0040A12E jz loc_40A224
.text:0040A134 add edx, 1Ch ; TrapFrame.SegFS
.text:0040A137 cmp ax, 0A10Fh ; Opcode 0FA1 = POP FS
.text:0040A13B jz loc_40A224
.text:0040A141 add edx, 0FFFFFFE0h ; TrapFrame.SegGS
.text:0040A144 cmp ax, 0A90Fh ; Opcode 0FA9 = POP GS
.text:0040A148 jz loc_40A224
{...}
.text:0040A224 loc_40A224:
.text:0040A224 xor eax, eax ; Sanitizing invalid selector
.text:0040A226 mov [edx], eax ;TrapFrame.Seg(D,E,F,G)S=0
However, Vmware assumes a non-null and initialized LDT. Hence, Vmware
prioritizes a #PF deprecating the GPF, so a wrong segment selector
pointing to the LDT is generating a Page Fault instead of the proper
GPF. Please,note that Windows allocates LDT(s) from non-paged memory.
The final result is that the VMM is delivering a PF instead of a GPF to
the Guest OS. When the Guest's Kernel receives that PF, it will bugcheck
due to a physical memory error.
Workaround
Under certain circumstances this flaw cannot be reproduced. On the other
hand, analyzing this behaviour a workaround comes to light.
Explanation:
This flaw can be mitigated initializing the LDTR register with the
KGDT_LDT selector. This task cannot be directly performed from
user-mode since “lldt” is a privileged instruction. However,
elaborating the correct path using native API we can do it.
1.NtSetLdtEntries -> 2. PsSetLdtEntries -> 3.KiLoadLdtr
Ring3/Ring0 Ring0 Ring0
Let's see:
Ntoskrnl.exe
Windows XP SP2
NTSTATUS
__stdcall
NtSetLdtEntries(ULONG Selector1,
LDT_ENTRY LdtEntry1,
ULONG Selector2,
LDT_ENTRY LdtEntry2)
PAGE:00555E57
PAGE:00555E57 Selector1 = dword ptr 8
PAGE:00555E57 LdtEntry1 = LDT_ENTRY ptr 0Ch
PAGE:00555E57 Selector2 = dword ptr 14h
PAGE:00555E57 LdtEntry2 = LDT_ENTRY ptr 18h
PAGE:00555E57
PAGE:00555E57 mov edi, edi
PAGE:00555E59 push ebp
PAGE:00555E5A mov ebp, esp
PAGE:00555E5C pop ebp
PAGE:00555E5D jmp _PsSetLdtEntries@24 ;
PsSetLdtEntries(x,x,x,x,x,x)
PAGE:00555E5D _NtSetLdtEntries@24 endp
{...}
int
__stdcall
PsSetLdtEntries(int,int,PVOID P,int,int,int)
{...}
.text:0047170E ; __stdcall Ke386SetLdtProcess(x, x, x)
.text:0047170E _Ke386SetLdtProcess@12 proc near ; CODE XREF:
PsSetLdtEntries(x,x,x,x,x,x)+107#p
.text:0047170E ;
PsSetLdtEntries(x,x,x,x,x,x)+14C#p ...
.text:0047170E var_8 = dword ptr -8
[...]
.text:00471780 call _KiLoadLdtr@0 ; KiLoadLdtr()
.text:00441892 ; __stdcall KiLoadLdtr()
.text:00441892 _KiLoadLdtr@0 proc near ; CODE XREF:
Ke386SetLdtProcess(x,x,x)+72#p
.text:00441892 push esi
.text:00441893 push edi
.text:00441894 mov eax, large fs:124h ;
PCR.PcrData.CurrentThread
.text:0044189A mov eax, [eax+44h] ; CurrentProcess
.text:0044189D lea esi, [eax+20h] ;
KPROCESS.LdtDescriptor
.text:004418A0 xor dx, dx
.text:004418A3 cmp word ptr [esi], 0
.text:004418A7 jz short loc_4418B9
.text:004418A9 mov edi, large fs:3Ch ; PCR.GDT
.text:004418B0 add edi, 48h ; GDT+KGDT_LDT
.text:004418B3 movsd ; Copy descriptor
.text:004418B4 movsd
.text:004418B5 mov dx, 48h ; KGDT_LDT
.text:004418B9
.text:004418B9 loc_4418B9: ; CODE XREF:
KiLoadLdtr()+15#j
.text:004418B9 lldt dx ;
Initializing ldtr
.text:004418BC pop edi
.text:004418BD pop esi
.text:004418BE call _KiFlushDescriptors@0 ;
KiFlushDescriptors()
.text:004418C3 retn
.text:004418C3 _KiLoadLdtr@0 endp
Disclosure Timeline
10.01.2007 – Initial vendor notification.
13.01.2007 – Vendor response. Vulnerability confirmed.
07.05.2007 – Coordinated Disclosure.
Exploits
This update is specially recommended for malware research labs or
Honeynets since malware can easily exploit this flaw in order to avoid
virtualized enviroments.
No exploits are released. Ethical security companies can contact for
requesting samples : contact@xxxxxxxxxxxxxxx
Special thanks to Mario Ballano for providing additional exploit code.
References
http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2007-1877
www.vmware.com
http://www.reversemode.com/index.php?option=com_remository&Itemid=2&func=fileinfo&id=49
(PDF)
-----
Reversemode
Advanced Reverse Engineering Services
http://www.reversemode.com | http://corporate.reversemode.com