Recently McAfee Labs discovered an interesting bug in Windows’ OLE implementation, which Microsoft patched this week. Now that the patch is available, we can discuss this vulnerability, which resides in the OleRegEnumVerbs() function of ole32.dll.
During our research we found that a stack corruption vulnerability in ole32!OleRegEnumVerbs can be triggered if we embed any OLE1 object into an Office document and try to load it. Whether a class identifier (CLSID) represents an OLE1 class can be determined from the registry.
As we see in the registry editor, HKEY_CLASSES_ROOT\CLSID\{00030000-0000-0000-C000-000000000046} represents an OLE1 object. Hence this CLSID can be used to trigger the bug.
This CLSID was embedded in a Word document. We observed the app crash when an attempt was made to load that OLE object. The stack trace on Windows 8.1 appeared like this:
Using windbg we can see the crash occurred inside the OleRegEnumVerbs() function with the exception code STATUS_STACK_BUFFER_OVERRUN. From this exception code, we can tell this is a stack corruption.
To find the root cause, we took a look at the disassembly of OleRegEnumVerb(). The first thing we see is a call to the CoIsOle1Class() function and the CLSID being passed to it.
According to the Microsoft Developer Network, the CoIsOle1Class() function verifies whether the CLSID passed to it represents an OLE1 object. In this case the CSID we feed into this function does represent an OLE1 object, so the program reaches the following code:
Here we see two calls: ProgIDFromCLSID() and StringCchCopyExW(). In this scenario we are interested in the StringCchCopyExW() call. The developer network tell us the StringCchCopyExW() function basically copies one string to another.
Ret_value = StringCchCopyExW(szKey, 0x100u, psz, &pwszBase, &cchRemain, 0);
In the preceding call:
szKey is the destination buffer
0x100 is the size of the destination buffer
psz is the source string (RegionUsageHeap)
pwszBase is the address of a pointer to the end of szKey
cchRemain is the number of unused characters in szKey
After this call succeeds, the program reaches following code, which is where the bug lies:
As we see, the code subtracts psz from pwszBase. Here pwszBase belongs to the stack, and psz belongs to the heap. Thus the value of pwszBase will less than psz, and the subtraction result (saved into ebx) becomes negative. At runtime, we can see value of ebx becomes 0xf9d93e2c, which points to kernel land.
0:000>? 0x002d9844 – 0x06545a18
Evaluate expression: -103203284 = 0xf9d93e2c
This bug occurs most likely because the developer made a typo. The developer’s intention probably was ebx = pwszBase – szKey, instead of ebx = pwszBase – psz.
Later we see another call to OpenClassesRootKeyExW().If the call is successful, the program tries dereference the corrupted pointer in the stack and write 0x00 there. Thus we see the host application crash.
Under certain circumstance, when the exploit attempt is combined with other vulnerabilities, this flaw can lead to remote code execution.
Vulnerability disclosure timeline
- January 16: McAfee labs reports issue to Microsoft Security Response Center
- February 1: MSRC confirms issue.
- April 12: Microsoft releases patch as part of MS16-044.