Wednesday, May 30, 2018

0patching Foxit Reader Buffer... Oops... Integer Overflow (CVE-2017-17557)

by Luka Treiber, 0patch Team


https://0patch.com


In April, Steven Seeley of Source Incite published a report  of a vulnerability in Foxit Reader and PhantomPDF versions up to 9.0.1 that could allow for remote code execution on a target system. Public release of this report was coordinated with an official vendor fix included in the April's Foxit Reader and PhantomPDF 9.1. release.

According to our analysis the PoC attached to the report triggers a heap-based buffer overflow in a Bitmap image data copy operation inside ConvertToPDF_x86.dll module using an overlong biWidth attribute.

When dropping SRC-2018-0009.bmp into Foxit Reader we immediately got a crash and inspected it by hooking WinDbg with Page Heap enabled.


(3250.3480): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Program Files (x86)\Foxit Software\Foxit Reader\Plugins\Creator\x86\ConvertToPDF_x86.dll -
eax=00000004 ebx=00000000 ecx=00000008 edx=15db5ef8 esi=15db9f38 edi=15dc2000
eip=5f5f9d17 esp=1866f904 ebp=1866f920 iopl=0         nv up ei pl nz na po cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010203
ConvertToPDF_x86!CreateFXPDFConvertor+0x1f42e7:
5f5f9d17 8807            mov     byte ptr [edi],al          ds:002b:15dc2000=??



It first looked like a typical buffer overflow, where a missing boundary check allows data to be written over the edge of destination buffer addressed by edi. (Note: the crash offset is marked in red.)






But the loop of the copy operation is constrained by checking biWidth (at esi+54h) which is read from Bitmap image header. So why is there an access violation despite this check?

When inspecting that buffer's properties something stuck out: an unusually small buffer size was reported by !heap to have been allocated, specifically just 4 bytes (UserSize in the WinDbg output below).


0:012> !heap -p -a edi
    address 15dc2000 found in
    _DPH_HEAP_ROOT @ 157e1000
    in busy allocation ( DPH_HEAP_BLOCK:  UserAddr  UserSize -  VirtAddr  VirtSize)
                               15ce264c:  15dc1ff8         4 -  15dc1000      2000
    65688e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
    7748103e ntdll!RtlDebugAllocateHeap+0x00000030
    7743abe2 ntdll!RtlpAllocateHeap+0x000000c4
    773e34a1 ntdll!RtlAllocateHeap+0x0000023a
    5f564b50 ConvertToPDF_x86!CreateFXPDFConvertor+0x0015f120
    5f6de073 ConvertToPDF_x86!CreateFXPDFConvertor+0x002d8643
    5f6ddead ConvertToPDF_x86!CreateFXPDFConvertor+0x002d847d
    5f6de124 ConvertToPDF_x86!CreateFXPDFConvertor+0x002d86f4
   *5f5f9975 ConvertToPDF_x86!CreateFXPDFConvertor+0x001f3f45
    5f5d8598 ConvertToPDF_x86!CreateFXPDFConvertor+0x001d2b68



Inspecting SRC-2018-0009.bmp in a hex editor revealed that biWidth is set to a huge value of 40000001h - a remotely controllable attribute in case the image used in conversion to PDF was obtained from the attacker. So if biWidth was used in calculation of destination buffer size before buffer allocation, that calculation was probably prone to integer overflow in order to result in so much lower a value (4).

Besides heap block properties, !heap also printed out the buffer allocation call stack. We inspected that and indeed we found an overflow-prone buffer size calculation right before the orange-marked return address in the above call stack. The code graph below shows only a part of the vulnerable execution path, but the omitted code is very similar so it suffices for our explanation. There are three code blocks; edi represents biWidth read from image data in the first block, in the third block eax is the destination buffer size to be allocated, ecx represents biBitCount (number of bits per pixel).





There are 3 instructions that can overflow in the last code block:

  1. imul eax, ecx - in case of SRC-2018-0009.bmp, eax=40000001h and ecx=4 so this is the operation that overflows (result is 00000001`00000004h but eax can only hold the lower DWORD - 00000004h)
  2. add eax,ebx - addition of 1Fh to a potentially huge number held by eax could overflow in case previous multiplication didn't overflow
  3. add eax,edx - addition of up to 1Fh (edx is and-ed to 1Fh beforehand) to a potentially huge number held by eax could overflow

As already said, this is not the only vulnerable code block before the destination buffer allocation. Depending on biBitCount value that can hold at most 20h two other similar buffer size calculations can occur. In order to fix all of them, many checks would have to be inserted so we decided for a more compact solution. Given that all constraints to the buffer size calculation are known - buffer size can not theoretically exceed 0xffffffff, biBitCount can be at most 20h and two potentially added values are at most 1Fh -, the maximum valid biWidth could be calculated beforehand as follows:

(0xffffffff-0x1f-0x1f)/0x20 = 0x07fffffe

However, one of the vulnerable blocks does not properly handle signed values so this also needs to be taken into account by halving the maximum buffer size to 0xffffffff/2 = 0x7fffffff. Once we do that, the add eax,edx instruction can't overflow because edx is the sign extension (mind the cdq instruction) and will always be 0. So the final constraint calculation goes like this:

(0x7fffffff-0x1f)/0x20 = 0x03ffffff

Knowing this, a single check can be placed right before biWidth is first used - at the first block of the code graph above - that makes sure only biWidth values lower than 0x03ffffff can pass. If this condition is not met, we can set biWidth to 0 so the subsequent jle would raise a handled exception and abort further processing of a malformed image. Here is the patch code that does this:


; CVE-2017-17557 patch for Foxit Reader 9.0.1 
MODULE_PATH "C:\0patch\Patches\CVE-2017-17557\ConvertToPDF_x86.dll"
PATCH_ID 1000031
PATCH_FORMAT_VER 2
VULN_ID 3556
PLATFORM win32

patchlet_start
PATCHLET_ID 1
PATCHLET_TYPE 2
PATCHLET_OFFSET 0x2098d9
JUMPOVERBYTES 3
N_ORIGINALBYTES 2

code_start
    mov edi, [esi+54h]      ; original instruction replaced by jump to this
                              patchlet
    cmp edi, 03ffffffh      ; is edi<(7fffffffh-1fh)/20h?
    jb skip                 ; if so, everything's okay 
    call PIT_ExploitBlocked ; otherwise, we had an integer overflow - 
                              show the popup
    xor edi,edi             ; and annulate biWidth so the subsequent logic 
                              will throw a handled exception
    skip:
    ;test    edi, edi       ; original instruction displaced to the trampoline
code_end
patchlet_end


When this patch is applied to Foxit Reader's memory, the first two instructions from the top code block above (mov edi, [esi+54h] and test edi, edi, making up exactly 5 bytes) are replaced by a 5-byte jump to the patch code, forcing us to repeat the first instruction (mov edi, [esi+54h]) at the beginning of our patch code if we want to inject our code between the two instructions. The second instruction (test edi, edi) is automatically placed after the patch code by 0patch Loader because JUMPOVERBYTES 3 directs it to only omit the first instruction (3 bytes) while keeping the remaining 2-byte instruction.

This video shows our micropatch in action.




This micropatch has already been published and distributed to all installed 0patch Agents. If you're using Foxit Reader or Foxit PhantomPDF version 9.0.1.1049, you can download our free 0patch Agent, create a free 0patch account and register the agent to that account to immediately receive this micropatch and have it applied to your Foxit software.

If you're using some other version of Foxit Reader and would like to have micropatches for it, please contact us at support@0patch.com.


Tuesday, May 15, 2018

Windows Updates Broke Your Networking? Free Micropatches To The Rescue (CVE-2018-8174)

A Single-Instruction Micropatch For a Critical Remote Execution Issue

by Mitja Kolsek, 0patch Team

Last week, Microsoft issued an update resolving (among others) a critical remote code execution issue in VBScript Engine named CVE-2018-8174, exploit for which has previously been detected in the wild.

Unfortunately, Microsoft's update breaks networking on some computers (details below), prompting users to avoid their application. Windows updates are "all or nothing" these days, so users can't just remove a defective KB and enjoy the protection provided by other KBs issued on the same Patch Tuesday. Fortunately, micropatching provided by 0patch is the exact opposite of that, addressing each vulnerability individually. Let's start with the exploit and the underlying vulnerability.   

It appears the exploit has been caught by at least two security firms, Kaspersky and 360, and they both issued detailed analyses of the infection chain and, more importantly for us, the vulnerability itself [Kaspersky's analysis, 360's analysis]

The vulnerability is triggered by this simple proof-of-concept provided by Kaspersky:


Dim ArrA(1)
Dim ArrB(1)

Class ClassVuln
    Private Sub Class_Terminate()
        Set ArrB(0) = ArrA(0)
        ArrA(0) = 31337
    End Sub
End Class

Sub TriggerVuln
    Set ArrA(0) = New ClassVuln
    Erase ArrA
    Erase ArrB
End Sub

TriggerVuln


By simply saving the above code to poc.vbs and double-clicking it on a Windows computer without May 2018 updates installed, we trigger the vulnerability and get wscript.exe to crash in oleaut32.dll's VariantClear function .


Access Violation in OLEAUT32.DLL's VariantClear due to accessing an unallocated memory address

 

Let's see what goes on here. We create two fixed-size arrays ArrA and ArrB with one element each.
A ClassVuln object is created and assigned to the first element of the ArrA array, then the ArrA array is erased. There is just one element in the array, namely the ClassVuln object, and Erase sets ArrA(0) to Nothing, which removes all references to the object and triggers its destruction.

Our object has a weird method called Class_Terminate. This is a class event that's not officially supported in VBScript anymore but apparently still works and gets called upon object's destruction. (If you're wondering why unsupported functionality still works it's probably because removing it would break an unknown number of production scripts that are using it, and cause much more headache than keeping it and removing it from documentation.)

In our Class_Terminate, the first element of ArrB is set to ArrA(0) - but wait, ArrA(0) is the very object being destroyed, and you can imagine where this is heading. This assignment increases the reference ("lock") count for the object, but the following instruction (ArrA(0) = 31337) decreases the same reference count, which will lead to the object being actually destroyed.

However, after being destroyed, there will still be a reference to this object in ArrB(0), which is called a "dangling pointer," i.e., a pointer to a memory block that has already been freed. In this case the object was allocated on the heap, so now ArrB(0) has a reference to some location on the heap, and those versed in exploiting "use after free" issues have a nice starting point to make use of this reference.

We're not interested in exploiting this issue, however, but in patching it. To do that, we first need to understand the vulnerability.

Kaspersky researchers pointed their fingers at the VBScriptClass::Release function, which only checks the object reference count before calling VBScriptClass::TerminateClass (this executes our Class_Terminate code), and doesn't account for the case where Class_Terminate would increase the object reference count. So even though the reference count was increased (by Set ArrB(0) = ArrA(0)), the object still gets destroyed.

We're not sure that this is the (entire) root cause, although we would probably try to fix the issue using this avenue if we didn't have Microsoft's official patch that contains information on how they fixed it.

After applying the May 2018 Windows updates, executing the PoC has a different result:


Patched Windows show a runtime error

The error states: "Object required: 'ArrA(...)'" in line 6, indicating that the assignment of ArrA(0) is not possible as ArrA is not an object (anymore).

First we decided to compare code execution between the patched and the unpatched version using WinDbg's wt (trace and watch data) command. Fortunately symbols are available for oleaut32.dll so the traces looked fairly identical up to the point where the patched version "derailed" from the unpatched version's path towards crashing. It turned out the fork happened in function vbscript!AssignVar, executed as a result of assigning ArrA(0) to ArrB(0). In this function (which hasn't been modified by the patch), a test is being made on the vt (variant type) member of a VARIANT structure, which in our case denotes the ArrA(0) element. And it turns out on the unpatched computer, vt is 9 (VT_DISPATCH) while on the patched computer, it is 0 (VT_EMPTY).

This means someone must have changed the value of vt from 9 to 0 along the way. In order to find out who did that, we placed an access breakpoint to the address of vt sometime earlier in the execution where it was still 9 on the patched computer.

Bingo! We found a "mov word [rdi], bp" instruction in our old friend, the VariantClear function, which sets our vt to 0. (rdi points to the VARIANT structure, and ebp is 0 throughout the function.)

It was time for BinDiff. We compared the patched and the last unpatched version of oleaut32.dll (which is where the crash occurs), and looked at the modified functions. Unsurprisingly, VariantClear was slightly modified in several places (orange blocks on the image below). Three of these blocks set the vt (variant type) member of a VARIANT structure to 0, which means VT_EMPTY, or an empty object.



Left: unpatched code; Right: patched code





Our PoC executes the middle orange block, and that block contains - in its patched version - the instruction that sets vt to 0.

So we created a micropatch that injects a logically identical instruction to the vulnerable code. Since the vulnerable code uses rbx as the pointer to the VARIANT, this is what we needed to inject:

mov word [rbx], 0

And this is the source code for our micropatch:


; Patch for CVE-2018-8174 in oleaut32.dll version 6.1.7601.23775 64bit
MODULE_PATH "c:\windows\system32\oleaut32.dll"
PATCH_ID 321
PATCH_FORMAT_VER 2
VULN_ID 3568
PLATFORM win64

patchlet_start
 PATCHLET_ID 1
 PATCHLET_TYPE 2
 PATCHLET_OFFSET 0x000011bf

 code_start

  mov word [rbx], 0 ; Set VARIANT's vt to 0 (VT_EMPTY)

 code_end

patchlet_end


Sure enough, applying this micropatch stopped the wscript.exe from crashing and made its behavior identical to the officially patched version:

The old version with our micropatch has an identical reaction to our PoC as the new version.


Our micropatches for this vulnerability have been labeled ZP-320 and ZP-321 for 32-bit and 64-bit version of oleaut32.dll respectively, and are applicable on Windows 7 and Windows 2008 Server updated up to April 2018 Windows updates. Why only these versions? Well, updates KB4103718 and KB4103712 are reportedly causing networking problems on some computers, which prompts users to delay their application - remaining vulnerable to the issue we have micropatched here. We have reports of Windows 7 and Windows 2008 Servers being affected, but if you or someone you know is experiencing this issue on other Windows versions, just ping us and we'll quickly port these micropatches.

As always, if you have 0patch Agent installed, the above-mentioned micropatches should already be present and applied on your system. If not, you can download a free copy of 0patch Agent to protect your system from CVE-2018-8174 at least until Microsoft resolves the functional problems with their updates.
 

Cheers!

@mkolsek
@0patch



Friday, March 30, 2018

Security Patching is Hard - Survey Results 2017


https://0patch.com/files/SecurityPatchingIsHard_2017.pdf

by Stanka Salamun, 0patch Team

Are you tired of constant inflow of software updates that require your attention and time? Well, you are not alone. While timely security patching plays an important role in providing a secure enterprise IT environment, dealing with patches as they are released at an unmanageable rate, seems to be an overwhelming task. 

We are presenting our first Security Patching is Hard - Survey Results 2017, revealing struggles and obstacles companies and individuals deal with when they try to be up to date with security patching. The survey was inspired by security experts that opened a debate over their patch fatigue after the Equifax leak.

For the first impression on survey results check out the infographic of the key takeaways.



Security Patching is Hard - Survey Results 2017




There is one obvious message from our research: the process of software patching should be simplified. 

For a dive into the facts and numbers behind the security update gap, download the report.  It reveals the main reasons for the patching fatigue, the impact of legacy software and how the relationship with software vendors influences the pace of applying security updates.


https://0patch.com/files/SecurityPatchingIsHard_2017.pdf
 


Monday, February 19, 2018

Two Interesting Micropatches For 7-Zip (CVE-2017-17969 and CVE-2018-5996)

by Luka Treiber, 0patch Team

Based on the vulnerability report from Dave we developed micropatches for heap buffer overflow CVE-2017-17969 and insufficient exception handling CVE-2018-5996 in 7-Zip version 16.04.


CVE-2017-17969

By diffing source code of the patched version 18.00 and the vulnerable version 16.04 we found the following changes related to CVE-2017-17969 (highlighted lines mark patched code).


001: // ShrinkDecoder.cpp

163:     lastSym = sym;
164:     unsigned cur = sym;
165:     unsigned i = 0;
166:     
167:     while (cur >= 256)
168:     {
169:       _stack[i++] = _suffixes[cur];
170:       cur = _parents[cur];
171:       // don't change that code:
172:       // Orphan Check and self-linked Orphan check (_stack overflow check);
173:       if (cur == kEmpty || i >= kNumItems)
174:         break;
175:     }
176:     
177:     if (cur == kEmpty || i >= kNumItems)
178:       break;
179:



We disassembled 7z.dll version 16.04 and found the above changes affect two offsets - 0x000a5ab4 and 0x000a5abb (both marked in red):




We then created micropatch code resembling source code lines 173 - 174 and 177 - 178 by using two patchlets, the first one extending (piggybacking on) an existing conditional statement (the end of the while loop - jnb loc_100A5A9C) and the second one introducing an additional conditional statement:

; CVE-2017-17969 patch for 7z.dll 16.04 
MODULE_PATH "C:\0patch\Patches\7zip\16.4\7z.dll"
PATCH_ID 316
PATCH_FORMAT_VER 2
VULN_ID 3295
PLATFORM win32

patchlet_start
PATCHLET_ID 1
PATCHLET_TYPE 2
PATCHLET_OFFSET 0x000a5ab4
JUMPOVERBYTES 5
N_ORIGINALBYTES 5

;piggybacking jnb 
;3D 00 01 00 00                       cmp     eax, 100h
;73 CE                                jnb     short loc_100AAF28
;if (cur == kEmpty || i >= kNumItems)
;    break;
code_start
    cmp eax, 100h
    jne skip1  ;cur != kEmpty?
    STC             ;set piggyback condition for jnb to NOT jump
    call PIT_ExploitBlocked
    jmp end
  skip1:
    cmp esi, 2000h
    jb skip2  ;i < kNumItems?
    STC             ;set piggyback condition for jnb to NOT jump
    call PIT_ExploitBlocked
    jmp end
  skip2:
    cmp eax, 100h ;original code
  end:
code_end
patchlet_end

patchlet_start
PATCHLET_ID 2
PATCHLET_TYPE 2
PATCHLET_OFFSET 0x000a5abb
PIT 7z.dll!0xa5bc4
JUMPOVERBYTES 0
N_ORIGINALBYTES 5

code_start
    cmp eax, 100h
    je block        ; cur == kEmpty?
    cmp esi, 2000h
    jge block       ; i >= kNumItems?
    jmp skip
  block:
    call PIT_ExploitBlocked
    jmp PIT_0xa5bc4 ; break
  skip:
code_end
patchlet_end



CVE-2018-5996

The source code patch for CVE-2018-5996 introduced the following changes (highlighted lines mark patched code):


001: // Rar3Decoder.h
194:   bool m_IsSolid;
195:   bool _errorMode;

001: // Rar3Decoder.cpp

089: CDecoder::CDecoder():
090:   _window(0),
091:   _winPos(0),
092:   _wrPtr(0),
093:   _lzSize(0),
094:   _writtenFileSize(0),
095:   _vmData(0),
096:   _vmCode(0),
097:   m_IsSolid(false),
098:   _errorMode(false)
099: {
100:   Ppmd7_Construct(&_ppmd);
101: }

827: HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress)
828: {
829:   _writtenFileSize = 0;
830:   _unsupportedFilter = false;
831:   
832:   if (!m_IsSolid)
833:   {
834:     _lzSize = 0;
835:     _winPos = 0;
836:     _wrPtr = 0;
837:     for (int i = 0; i < kNumReps; i++)
838:       _reps[i] = 0;
839:     _lastLength = 0;
840:     memset(m_LastLevels, 0, kTablesSizesSum);
841:     TablesRead = false;
842:     PpmEscChar = 2;
843:     PpmError = true;
844:     InitFilters();
845:     _errorMode = false;
846:   }
847: 
848:   if (_errorMode)
849:     return S_FALSE;
850: 
851:   if (!m_IsSolid || !TablesRead)
852:   {
853:     bool keepDecompressing;
854:     RINOK(ReadTables(keepDecompressing));
855:     if (!keepDecompressing)
856:       return S_OK;
857:   }

890:   return S_OK;
891: }

929:   catch(const CInBufferException &e) { _errorMode = true; return e.ErrorCode;}
930:   catch(...) { _errorMode = true; return S_FALSE; }


When developing a micropatch for this vulnerability, we had to patch the CDecoder class that had to be extended by a new member - the _errorMode variable. This was the first time we attempted something like that with 0patch. So we either had to make room for the new variable (increase the allocated object memory block) or find existing unused space within the object's memory layout. By searching for cross references to CDecoder member variables (in offset range around the m_IsSolid variable 1c6d - 1c7c) we found offsets 1C6Fh, 1C79h, 1C7Ah, 1C7Bh to be unused. Based on this we selected and assigned the first one of the available offsets - 1C6Fh - to the new _errorMode variable.

Our micropatch contains five patchlets that correspond to five code offsets in 7z.dll that had to be patched:

  • Patchlet 1: We micropatched offset 0x000a0388 (the CDecoder::CDecoder constructor) with code resembling line 195 of RarDecoder.h and line 98 of Rar3Decoder.cpp.





  • Patchlets 2 and 3: We micropatched offsets 0x000a25bf and 0x000a25de with  code resembling lines 845 and 848-849.



  • Patchlets 4 and 5: We micropatched  offsets 0x000a22ee and 0x000a22f6 with code resembling changes to lines 929-930.


This is the 0pp file implementing these patchlets:


; CVE-2018-5996 patch for 7z.dll 16.04 
MODULE_PATH "C:\0patch\Patches\7zip\16.4\7z.dll"
PATCH_ID 315
PATCH_FORMAT_VER 2
VULN_ID 3296
PLATFORM win32

; added variables:
;  _errorMode (this+1C6Dh)
;
patchlet_start
PATCHLET_ID 1
PATCHLET_TYPE 2
PATCHLET_OFFSET 0x000a0388
JUMPOVERBYTES 0
N_ORIGINALBYTES 5

code_start
  mov [esi+1C6Fh], bl ; _errorMode=0 //ebx set to 0 at offset a030a
code_end
patchlet_end

patchlet_start
PATCHLET_ID 2
PATCHLET_TYPE 2
PATCHLET_OFFSET 0x000a22ee
JUMPOVERBYTES 0
N_ORIGINALBYTES 5

code_start
  mov  [esi+1C6Fh], bl ; _errorMode=0 //ebx set to 0 at offset a2278
code_end
patchlet_end

patchlet_start
PATCHLET_ID 3
PATCHLET_TYPE 2
PATCHLET_OFFSET 0x000a22f6
PIT 7z.dll!0x000A2452
JUMPOVERBYTES 0
N_ORIGINALBYTES 5

code_start
  cmp [esi+1C6Fh],bl ; _errorMode=0 //ebx set to 0 at offset a2278
  jz skip
  call PIT_ExploitBlocked
  jmp PIT_0x000A2452
 skip:
code_end
patchlet_end
patchlet_start
PATCHLET_ID 4
PATCHLET_TYPE 2
PATCHLET_OFFSET 0x000a25bf
JUMPOVERBYTES 0
N_ORIGINALBYTES 5

code_start
  mov  eax, [ebp+08h]      ; catch(const CInBufferException &e) {
  mov byte [eax+1C6Fh], 1  ;  _errorMode = true;
                           ;  return e.ErrorCode;}
code_end
patchlet_end

patchlet_start
PATCHLET_ID 5
PATCHLET_TYPE 2
PATCHLET_OFFSET 0x000a25de
JUMPOVERBYTES 0
N_ORIGINALBYTES 5

code_start
  mov  eax, [ebp+08h]      ; catch(...) { 
  mov byte [eax+1C6Fh], 1  ;  _errorMode = true; 
                             ;  return S_FALSE; }
code_end
patchlet_end
 

These two micropatches have already been published and distributed to all installed 0patch Agents. If you're using 32-bit 7-Zip version 16.04, you can download our free 0patch Agent, create a free 0patch account and register the agent to that account to immediately receive these micropatches and have them applied to your 7-Zip executable.

If you're using some other version of 7-Zip and would like to have micropatches for it, please contact us at support@0patch.com.



Tuesday, January 16, 2018

Micropatching Brings The Abandoned Equation Editor Back To Life

How We Security-Adopted a Terminated Software Product

by Mitja Kolsek, the 0patch Team




Intro

A few days ago Microsoft's update removed Equation Editor from Microsoft Office, the official reason being "security issues with its implementation." Most Office users couldn't care less about this removal, but if you've been happily using Equation Editor to edit Word documents with mathematical formulas just days ago, you suddenly can't do that anymore. You will still see your formulas in the document but you won't be able to edit them. Instead you'll get this:





We have no idea how many users are affected, but Twitter user @glyph raises an interesting point that those who work with Equation Editor may be tempted to forego this Office update - and by extension all future Office updates -, which will leave them vulnerable to exploits published in the future.   



Worse even, affected users may decide to migrate back to unsupported versions of Office that don't receive security updates at all. This user, for instance, reports going back to Office 2000 on his Windows 10 computer. Office 2000 stopped receiving security updates in 2009.

Microsoft suggested affected users can "edit Equation Editor 3.0 equations without security issues" with Wiris Suite's MathType, a commercial application that costs $97 ($57 academic). They did not specify the basis upon which the phrase "without security issues" was provided, but MathType seems to have a clean public security record so far. Which doesn't say much as that was also true for Equation Editor until someone opened its hood.

We haven't tested MathType and can't tell how easy it is to start using it instead of Equation Editor with existing Word documents, but we don't particularly like the idea of suddenly deleting from users' computers a tool they might be using, and sending them to a store to buy a replacement.

Microsoft's unwillingness to continue supporting Equation Editor is understandable. Their manual patching of its recently discovered vulnerability reveals that, for whatever reason, their standard patching process cannot be applied to Equation Editor, and a deviation like that can be expensive. Furthermore, while they aren't new to manually patching executables, such patching can sometimes be fairly difficult to do. When you patch executable files directly, you may have to come up with a different clever space-saving hack for each patch, which can sometimes be very difficult and time-consuming. For instance, Microsoft's manual patches of Equation Editor required the patch author to invent a way to get some free space in the code for additional patch logic by de-optimizing a memory-copying routine.

So when Microsoft was faced with 8 (eight!)* new vulnerabilities in Equation Editor reported after their manual patch (one also reported by us), they gave up on the idea of continuing manual support for it.

We, on the other hand, haven't.

You see, it's much easier for us to create and support binary patches for a given executable module than it is for Microsoft. Why? Because we have a micropatch delivery agent (0patch Agent) that not only instantly downloads micropatches, but also injects them into running processes on the computer while automatically making room for the added code. So we don't have to invent a new way of making room for every micropatch we make, and can therefore focus on the patch itself. We also deliver our micropatches to agents every hour, and they are as trivial to revoke and un-apply as they are to apply. As much as we hate to repeat ourselves, this is how we believe security patching should look like in this century.

That said, we've already issued our micropatch for CVE-2018-0802, and it's been applied to all computers running 0patch Agent where the latest version of Equation Editor is still present. We're also teaming up with other security researchers who have found vulnerabilities in Equation Editor to micropatch those issues too. We urge everyone who finds additional security issues in Equation Editor to share their findings with us and help up create micropatches for them.

[Update 2/20/2018: We've just issued a micropatch for another Equation Editor vulnerability, CVE-2018-0798. Big thanks to the 360 Vulcan Team for their help with that!]


Bringing Equation Editor Back To Life


So you've installed Office Updates from January 9th 2018 and Equation Editor got removed from your computer. Specifically, the update deleted five files (including EQNEDT32.EXE) from the EQUATION folder, leaving the 1033 subfolder and EEINT.DLL inside it intact. It also unregistered Equation Editor as a local COM server by deleting CLSID {0002CE02-0000-0000-C000-000000000046} from registry. Note that Office 2016 still has several files in the EQUATION folder after the update, and in some cases, a 0-byte EQNEDT32.EXE file is left on the system.

The location of the EQUATION folder depends on both the Office version and whether it's 32-bit or 64-bit Office. These are the default locations:

  • 32-bit Office 2007, 2010 and 2013 on 32-bit Windows: C:\Program Files\Common Files\microsoft shared\EQUATION
  • 32-bit Office 2007, 2010 and 2013 on 64-bit Windows: C:\Program Files (x86)\Common Files\microsoft shared\EQUATION
  • 64-bit Office 2007, 2010 and 2013: C:\Program Files\Common Files\Microsoft Shared\EQUATION
  • 32-bit Office 2016 and 365 on 32-bit Windows: C:\Program Files\Microsoft Office\root\VFS\ProgramFilesCommonX86\Microsoft Shared\EQUATION
  • 32-bit Office 2016 and 365 on 64-bit Windows: C:\Program Files (x86)\Microsoft Office\root\VFS\ProgramFilesCommonX86\Microsoft Shared\EQUATION
  • 64-bit Office 2016 and 365: C:\Program Files\Microsoft Office\root\VFS\ProgramFilesCommonX64\Microsoft Shared\EQUATION

The following images depict the before-and-after of the EQUATION folder when applying the January 2018 Office update.


Office 2010: Content of the EQUATION folder before the update


Office 2010: Content of the EQUATION folder after the update



In order to get Equation Editor back while continuing to receive future Office security updates you need to do two things:

  1. Restore deleted Equation Editor files.
  2. Re-register Equation Editor as a local COM server.
  3. Install free 0patch Agent to keep Equation Editor patched against known vulnerabilities.

Obviously, you don't technically need the last step to get Equation Editor working again, but you don't want to be vulnerable to trivial inexpensive attacks that can be delivered in any Word document you ever receive. So just to be clear, we don't recommend performing steps A and B if you don't also perform step C.


A. Restore deleted Equation Editor files

(Disclaimer: The following is not an official Microsoft-supported procedure and is not guaranteed to work or to not have unwanted side effects. In addition, future Office updates may bring additional blocking of Equation Editor and disable its use. You're doing this at your own risk.) 

Unfortunately uninstalling the Office security update that removed Equation Editor doesn't bring the deleted files back. This leaves you with two options: (a) find a copy of Office you haven't updated yet, or (b) reinstall Office from your original media and apply all updates up to and including November 2017 updates. Once you do any of these, you will find these files in the EQUATION folder (possibly along some other files in Office 2016):

  • EQNEDT32.CNT - help file index
  • EQNEDT32.EXE - Equation Editor executable
  • eqnedt32.exe.manifest - Equation Editor manifest file
  • EQNEDT32.HLP - help file
  • MTEXTRA.TTF - MathType font file

Make sure you have EQNEDT32.EXE version 2017.8.14.0, which is the latest version provided by Microsoft.

What you don't want to do is download the missing files from the Internet, as that is not only a potential violation of your license, but also a great way to get malware on your computer. So don't do that.

Once you have the above Equation Editor files at hand, copy them to the EQUATION folder from which they have been removed on a computer with all updates (including the January 2018 Office update) installed. You will need to have administrative permissions for this, and you may be prompted to overwrite an existing 0-byte EQNEDT32.EXE, which seems to be left on some systems.



B. Re-register Equation Editor as a local COM server

Registering a local COM server requires creating a valid CLSID registry key with required subkeys and values. To make it easier for you, we prepared a template .REG file that you can edit and import in your registry. To do so, follow these instructions:

  1. Download EquationEditor.reg.
  2. Edit EquationEditor.reg (right-click on it and select "Edit"), find in it the path to EQNEDT32.EXE, and change it to the actual path in the EQUATION folder on your computer where you restored the files in step A. IMPORTANT: The path should use double back slashes instead of single ones (just like in our sample reg file above), so make sure to duplicate all back slashes in your path.
  3. Import the modified EquationEditor.reg to registry by first launching the Registry Editor (regedit.exe) as Administrator, then selecting File-Import... in its menu and browsing to your EquationEditor.reg file.

Voila, if everything went well, you can now edit your equation objects in Equation Editor again, and save them back to Word files. Note that it sometimes takes up to a few minutes for this registry change to come into effect; until it does, opening an equation object will result in the "Microsoft Equation is not available" error.

If Equation Editor complains that it's missing a font, reinstall MTEXTRA.TTF.

Important: you will be able to - and are highly encouraged to - keep applying official Office updates after completing this procedure to keep future vulnerabilities in other parts of Office patched. The whole point of this blog post is to help you keep Equation Editor while keeping your Office Applications updated.

But you're not done yet! Now you have to get your Equation Editor patched. On to step C.


C. Install 0patch Agent

0patch provides free micropatches for Equation Editor (and many other software products). To install it, download and launch the installer, create a free 0patch account and register the agent to that account. You will immediately receive all Equation Editor micropatches - [Updated 2/20/2018] one for CVE-2018-0802 and one for CVE-2018-0798, but as we receive details on the other vulnerabilities, we'll issue additional micropatches.


Expected Questions

These are some of the questions we anticipate and would like to answer in advance.


Q: Why are you doing this? Equation Editor is a 17-year-old pile of insecure code and should die!

In today's "Move fast and break things" world we're accustomed to the idea that software must be perpetually and frequently replaced with new versions. In fact, much of the global software business is built on "incentivizing" users to buy a new version of a product that works just fine for them. Of course the underlying hardware is improving, and new attacks are being invented, so software code effectively does get worse in time even if it doesn't change a bit, but let's hold back for a moment.

"17-year-old code" sounds borderline outrageous to many, but we often forget that there are products we want to keep for 20 years or more. Say, medical devices. If an MRI machine running a  reasonably new, well tested operating system costs $500k, and its hardware can be serviced for 20 years, do we really want to throw it out after 10 years because it stops getting security updates from the OS vendor? Heck no. What we actually want is for it to remain immutable as much as possible for 20 years, and not get any software changes that aren't necessary for its function and security. This is hard to grasp if you're used to replacing half of your operating system every month.

Clearly, Equation Editor is not a life-critical piece of equipment and seems relatively cheap to replace. It does, however, allow for a nice demonstration how an abandoned software product can be "security-adopted" by a 3rd party, allowing its continued use without exposing one's environment to cheap public exploits.


Q: Isn't Equation Editor full of vulnerabilities and risky to use even if you patch the publicly known issues?

It's impossible to say whether any software product is "full of vulnerabilities" or not without thoroughly inspecting it. Nine vulnerabilities having been found in it in quick succession is easily explained by the fact that before Embedi decided to look under the hood, Equation Editor was shielded by a veil of obscurity. Once they've pointed out how its attack surface can be reached from a Word document, it became an easy toy to play with and apparently attracted many researchers. The additional eight vulnerabilities were most likely all low-hanging fruit, i.e., easy to find. But once we patch them, will it be easy to find the next one? No one knows, and if anyone claims to know, kindly ask them for evidence.  


Q: How long are you planning to provide patches for Equation Editor?

With the details we currently have about the known vulnerabilities in Equation Editor, it seems it should be easy for us to micropatch them. Should anyone find additional vulnerabilities in it (and since it's been removed from Office, very few will bother searching), we'll try to micropatch that too. It could happen, although unlikely, that a design vulnerability is found which would be extremely difficult to micropatch, or would require an unreasonable amount of effort on our part. In such case we too will abandon our security support. We hope this will not happen.


Q: How will we receive subsequent micropatches for Equation Editor?

As long as 0patch Agent on your computer has access to the Internet, all subsequent micropatches for Equation Editor will be automatically delivered to your computer and immediately, automatically applied to Equation Editor when it gets launched. If you happen to be using Equation Editor when a new micropatch arrives, the micropatch will get applied to it without disturbing you (i.e., you won't even have to relaunch Equation Editor). 


Outro

There you go. Let us know how this works for you - share your experience, questions and possible concerns in the comments below.

Note that we can only provide support for our micropatches (email to support@0patch.com) and not general technical support for Equation Editor. If you encounter any issues with Equation Editor that you haven't seen before, first disable 0patch Agent and see if the issue is still there. If disabling the Agent resolves the issue, please report it to us, otherwise contact Microsoft.


Cheers!

@mkolsek
@0patch


* The initial public perception after the January Patch Tuesday was that Equation Editor had a single reported vulnerability (CVE-2018-0802) when in fact it was eight of them. However, there have been no public details available on these additional issues as of this writing.