Threat Research

It's Still Patch Tuesday - FortiGuard Labs Discloses Microsoft Office Word Double Free Vulnerability

By Kai Lu | December 08, 2015

Overview

From the Yes, You Really Should Upgrade Department, FortiGuard Labs has discovered a third Microsoft Office Vulnerability that is rolled into today's Patch Tuesday updates. For a bit of variety, this is a double free vulnerability in Word 2007 and 2010.

The vulnerability occurs when Word fails to validate that a pointer was already released before attempting to release it again, causing conditions that attackers could leverage to achieve remote code execution scenarios. The underlying problem involves an internal structure that gets released without resetting the address to NULL. This causes Word to release the pointer twice on certain resource consumption cases when it is running out of memory.

That's where the variety ends, however, as this vulnerability exists due to an error while the vulnerable software attempts to open a specially crafted Microsoft Word file. And yes, it could lead to remote code execution.

Analysis

As noted, based on our analysis, this is a double-free vulnerability. Closer inspection of the assembly code shows the crash:
 
543a77d8 e8b3300000      call    verifier!AVrfpDphReportCorruptedBlock (543aa890)
543a77dd 8b4d08          mov     ecx,dword ptr [ebp+8]
543a77e0 8b91ac000000    mov     edx,dword ptr [ecx+0ACh]
543a77e6 83e210          and     edx,10h
543a77e9 0f85e2000000    jne     verifier!AVrfpDphFindBusyMemoryNoCheck+0x171 (543a78d1)
543a77ef 8b450c          mov     eax,dword ptr [ebp+0Ch]    
//eax is 0xf0f0f0f0, it’s the second parameter of this function
543a77f2 83e820          sub     eax,20h                                //eax is 0xf0f0f0d0
543a77f5 8945dc          mov     dword ptr [ebp-24h],eax
543a77f8 8b4d0c          mov     ecx,dword ptr [ebp+0Ch]
543a77fb 83e928          sub     ecx,28h
543a77fe 81e100f0ffff    and     ecx,0FFFFF000h
543a7804 894de0          mov     dword ptr [ebp-20h],ecx
543a7807 c745fc00000000  mov     dword ptr [ebp-4],0
543a780e c745c400000000  mov     dword ptr [ebp-3Ch],0
543a7815 8b55dc          mov     edx,dword ptr [ebp-24h]
543a7818 813abbbbcdab    cmp     dword ptr [edx],0ABCDBBBBh ds:002b:f0f0f0d0=???????? 
//crash occurs here
 
We need to trace the value of [ebp+0Ch]. From the stack call trace, we set a breakpoint as follows:
 
6b7d3fd6 ff730c          push    dword ptr [ebx+0Ch]
6b7d3fd9 ff37            push    dword ptr [edi]
6b7d3fdb e8ffe8fcff      call    MSPTLS!FsDestroyMemory (6b7a28df)     //set breakpoint here.
6b7d3fe0 53              push    ebx
6b7d3fe1 ff37            push    dword ptr [edi]
6b7d3fe3 e8f7e8fcff      call    MSPTLS!FsDestroyMemory (6b7a28df)    
6b7d3fe8 8b45f8          mov     eax,dword ptr [ebp-8]
6b7d3feb 5f              pop     edi
6b7d3fec 5b              pop     ebx
6b7d3fed c9              leave
6b7d3fee c20800          ret     8
 
In the debugger WinDdbg, we use the following command to set the breakpoint:
bu MSPTLS!LsLwMultDivR+0x25bf4 ".printf \"call:\\n\"; dd ebx;"
 
After the breakpoint is hit several times, we can find the following information.
 
0:000> g
call:
7ffdee40  f0f0f0f0 f0f0f0f0 f0f0f0f0 f0f0f0f0
7ffdee50  a0a0a0a0 a0a0a0a0 00000000 00000000
7ffdee60  add9d6a9 0001dca7 04e700c0 5468dfa8
7ffdee70  00000000 00000000 00000000 00000000
7ffdee80  00000000 00000000 00000000 00000000
7ffdee90  00000000 00000000 00000000 00000000
7ffdeea0  00000000 00000000 00000000 00000000
7ffdeeb0  00000000 00000000 00000000 00000000
eax=00000000 ebx=7ffdee40 ecx=352b1524 edx=01fffa34 esi=1092ef60 edi=1092ef60
eip=6b7d3fdb esp=00189170 ebp=00189188 iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
MSPTLS!LsLwMultDivR+0x25bf4:
6b7d3fdb e8ffe8fcff      call    MSPTLS!FsDestroyMemory (6b7a28df)
 
So the value of [ebx+0Ch] is 0xf0f0f0f0. It is the second parameter of the function MSPTLS!FsDestroyMemory. The value 0xf0f0f0f0 is finally passed to the function verifier!AVrfpDphFindBusyMemoryNoCheck.
 
When we enable page heap, the debug info appears as below:
 
0:000> !heap -p -a 7ffdee40  
    address 7ffdee40 found in
    _HEAP @ 4e70000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        7ffdee18 0009 0000  [00]   7ffdee40    00010 - (free DelayedFree)
        546cb456 verifier!AVrfpDphNormalHeapFree+0x000000b6
        546c9cf3 verifier!AVrfDebugPageHeapFree+0x000000e3
        774dda05 ntdll!RtlDebugFreeHeap+0x0000003c
        77431c0e ntdll!RtlpFreeHeap+0x00000c3e
        77430498 ntdll!RtlFreeHeap+0x00000268
        8abc065 mso!Ordinal1743+0x00002e41
        7fcb6ed mso!MsoFreePv+0x0000003a
        6b73fbd6 MSPTLS!LssbFIsSublineEmpty+0x000001bb
        6b7a28f3 MSPTLS!FsDestroyMemory+0x00000014
        6b7d3f7f MSPTLS!LsLwMultDivR+0x00025b98
        6b7b4166 MSPTLS!LsLwMultDivR+0x00005d7f
        6b7b4bb6 MSPTLS!LsLwMultDivR+0x000067cf
        6b7a313d MSPTLS!FsDestroyMemory+0x0000085e
        6b795432 MSPTLS!FsQueryTableObjFigureListWord+0x000002a0
        6b7be58e MSPTLS!LsLwMultDivR+0x000101a7
        6b7beea2 MSPTLS!LsLwMultDivR+0x00010abb
        6b7bf005 MSPTLS!LsLwMultDivR+0x00010c1e
        6b7bf26f MSPTLS!LsLwMultDivR+0x00010e88
        6b7a59a5 MSPTLS!FsDestroyMemory+0x000030c6
        6b7d2d58 MSPTLS!LsLwMultDivR+0x00024971
        6b7b0b85 MSPTLS!LsLwMultDivR+0x0000279e
        6b7d371d MSPTLS!LsLwMultDivR+0x00025336
        6b7d38ef MSPTLS!LsLwMultDivR+0x00025508
        6b7d3c5a MSPTLS!LsLwMultDivR+0x00025873
        6b7b0e19 MSPTLS!LsLwMultDivR+0x00002a32
        6b7b15b6 MSPTLS!LsLwMultDivR+0x000031cf
        6b79ec92 MSPTLS!FsTransformBbox+0x00006b53
        6b79eed6 MSPTLS!FsTransformBbox+0x00006d97
        6b791255 MSPTLS!FsCreateSubpageFinite+0x00000099
        3205e864 wwlib!DllCanUnloadNow+0x005cbdd0
        3205e6a7 wwlib!DllCanUnloadNow+0x005cbc13
        6b7b326a MSPTLS!LsLwMultDivR+0x00004e83
 
From the above analysis, we can see an object starts at memory address 0x7ffdee40 and its size is 0x10, but it has actually been freed. ntdll!RtlFreeHeap will free the object 0xf0f0f0f0 that is obtained from [ebx+0Ch], making this a typical double-free vulnerability.

Mitigation

All users of Microsoft Office 2007 and 2010 are encouraged to upgrade to the latest version of this software. Additionally, organizations that have deployed Fortinet IPS solutions are already protected from this vulnerability with the signature MS.Office.WWLIB.Pointer.Handling.Memory.Corruption. Additional information can be found at http://technet.microsoft.com/security/bulletin/MS15-131 and https://www.mitre.org/.