Thursday, November 23, 2017

Microsoft's Manual Binary Patch For CVE-2017-11882 Meets 0patch

by Luka Treiber, the 0patch Team

Last Monday evening Embedi published the PoC referred to in their report and on Tuesday we released a micropatch for the vulnerability. Here is the analysis.

The PoC is in form of an RTF file that, if opened in Microsoft Word, immediately pops up calc.exe. To accomplish this, Embedi overflowed a string buffer on the stack with an overlong font name applied to an equation text.

As shown in their WinDbg screenshot, the overlong font name contains a command string to be executed followed by padding A's until a trailing return address to a WinExec call at offset 2Ch that is supposed to execute the command string. Apparently the WinExec call address, located at font string offset that is already out of bounds of the designated buffer, replaces a legitimate return address on stack so when the vulnerable function returns, the payload gets executed instead.

What was Microsoft's official patch? As already said in our previous post, the diff of EqnEdt32.exe between versions 2017.8.14.0 and 2000.11.9.0 showed only 5 modified functions. Running the PoC with WinDbg attached showed that it executes one of the patched functions, sub_0041160F. There were 5 changed blocks of code in that function, but it turns out the relevant patch that blocks the PoC is the topmost one.

This patch consists of an added boundary check (top square on the left) and buffer truncation code (bottom square on the left)  to a vulnerable memcpy operation that overwrote a stack buffer as previously mentioned. The conditional is placed after counting bytes to be copied from arg_0 to var_28 and makes sure that if the source string is too long, only 0x20 bytes are copied and zero-terminated.

However, this is not the biggest difference applied to the vulnerable code block. The most code reorganization and, we believe, effort had to be put into the middle square where the developer replaced the compiler's memcpy implementation on the right with a more compressed alternative to gain space for injecting the aforementioned security check.

Based on all these findings we wrote our own micropatch:

; CVE-2017-11882 patch for Equation Editor EQNEDT32.EXE 2000.11.9.0
MODULE_PATH "C:\Analysis\CVE-2017-11882\EQNEDT32.EXE"
VULN_ID 3084



  cmp     ecx, 21h
  jb      skip
  mov     ecx, 20h
  call PIT_ExploitBlocked





  xor eax, eax
  stosb ; zero-terminate the string



With this micropatch we did the same thing as Microsoft, only we had no hassle finding the space to inject our code. It is quite ingenious how they managed to compress the code around the patch offset in order to make room for the patch code that required additional 10 bytes. We too need space at the patch offset in order to inject a jmp to our micropatch, however, our technology takes care of automatically injecting these 5 bytes and relocating the original code somewhere else. There are certain requirements that the patch location has to meet (see our 0patch Developer Manual for details), but this is far less constraining than compacting code around the offset like Microsoft had to do.

Our micropatches for this vulnerability have been labeled ZP-313 and ZP-314 (there are two slightly different versions of EqnEdt32.exe) and cover all Microsoft Office versions from 2007 to 2016 and 365. As always, if you have 0patch Agent installed, these 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-2017-11882.

(By the way, ZP-313 and ZP-314 have replaced the now-revoked micropatch for this issue we had released on Tuesday because we wanted to add the zero-termination code and thus fully mirror the official patch. In case you didn't know how micropatch revocation works, it's just as seamless as everything else: the revoked patch simply stops being applied, and the new one starts getting applied instead. Again, users don't notice anything.)

It was a surprising and an interesting revelation that official software vendors/maintainers also occasionally resort to manual binary patching. Moreover, our analysis of the official patch has shown that in such cases it is harder to directly patch the binary than to use in-memory micropatching. Lastly it may even turn out to be infeasible to patch some bugs in binary files because the code may already be fully optimized for space and the technique seen in Microsoft's CVE-2017-11882 patch would require and unacceptable amount of effort. In cases like that micropatching can turn out to be more agile than traditional patching.

This being said, all that remains is the pleasure of presenting a video of our agile micropatch in action :)

Friday, November 17, 2017

Did Microsoft Just Manually Patch Their Equation Editor Executable? Why Yes, Yes They Did. (CVE-2017-11882)

And They Did an Absolutely Stellar Job

by Mitja Kolsek, the 0patch Team

[Update 11/21/2017]  Today Embedi published their proof-of-concept exploit, which allowed us to see where exactly Microsoft's manual patch blocks it. Contrary to this article's original claim that CVE-2017-11882 was patched in function 4164FA while six other buffer overflow checks we found were for some other attack vectors, it is actually one of those six checks that blocks Embedi's exploit. This article has been slightly corrected to reflect that. In addition, we were now able to create a micropatch for Equation Editor that also blocks all exploits targeting the vulnerability found by Embedi. All Internet-connected computers with a registered 0patch Agent running have already received this micropatch and have it automatically applied whenever Equation Editor is launched. [End update 11/21/2017]

A Pretty Old Executable

The recent Patch Tuesday brought, among other things, a new version of "old" Equation Editor, which introduced a fix for a buffer overflow issue reported by Embedi.

The "old" Equation Editor is an ancient component of Microsoft Office (Office now uses an integrated Equation Editor), which is confirmed by looking at the properties of the unpatched EQNEDT32.EXE:

We can see that File version is 2000.11.9.0 (implying being built in 2000), while Date modified is in 2003, which matches the time of its signature (signing modifies the file as the signature is attached to it.) Furthermore, the TimeDateStamp in its PE header (3A0ACEBF), which the compiler writes into the executable module when building it, indicates that the file was built on November 9, 2000 - exactly matching the date in the above version number.

We're therefore safe to claim that the vulnerable EQNEDT32.EXE has been with us since 2000. That's 17 years, which is a pretty respectable life span for software!

So now a vulnerability was reported in this executable and Microsoft spawned their fixing procedure: they reproduced the issue using Embedi's proof-of-concept, confirmed it, took the source code, fixed the issue in the source code, re-built EQNEDT32.EXE, and distributed the fixed version to Office users, who now see version 2017.8.14.0 under its properties.

At least that's how it would work for most other vulnerabilities. But something was different here. For some reason, Microsoft didn't fix this issue in the source code - but rather by manually patching the binary executable.

Manually Patching an EXE?

Really, quite literally, some pretty skilled Microsoft employee or contractor reverse engineered our friend EQNEDT32.EXE, located the flawed code, and corrected it by manually overwriting existing instructions with better ones (making sure to only use the space previously occupied by original instructions).

How do we know that? Well, have you ever met a C/C++ compiler that would put all functions in a 500+ KB executable on exactly the same address in the module after rebuilding a modified source code, especially when these modifications changed the amount of code in several functions?

To clarify, let's look at BinDiff results between the fixed (2017.8.14.0, "primary") and vulnerable version (2000.11.9.0, "secondary") of EQNEDT32.EXE:

If you're diffing binaries a lot, you'll notice something highly peculiar: All EA primary values are identical to EA secondary values of matched functions. Even the matched but obviously different functions listed at the bottom are at the same address in both EQNEDT32.EXE versions.

As we already noted on Twitter, Microsoft modified five functions in EQNEDT32.EXE, namely the bottom-most five functions listed on the above image. Let's look at the most-modified one first, the one at address 4164FA. The patched version is on the left, the vulnerable one on the right.

This function takes a pointer to the destination buffer and copies characters, one by one in a loop, from user-supplied string to this buffer. It is also the very function that Embedi found to be vulnerable in their research; namely, there was no check whether the destination buffer was large enough for the user-supplied string, and a too-long font name provided through the Equation object could cause a buffer overflow.

Microsoft's fix introduced an additional parameter to this function, specifying the destination buffer length. The original logic of the character-copying loop was then modified so that the loop ends not only when the source string end is reached, but also when the destination buffer length is reached - preventing buffer overflow. In addition, the copied string in the destination buffer is zero-terminated after copying, in case the destination buffer length was reached (which would leave the string unterminated).

Let's look at the code in its text form (again, patched function on left, vulnerable on right):

As you can see, whoever patched this function not only added a check for buffer length in it, but also managed to make the function 14 bytes shorter (and padded the resulting gap before the adjacent function with 0xCC bytes for style points :). Impressive.

Patching The Callers

Moving on. If the patched function got an additional parameter, all those calling it would have to change as well, right? There are exactly two callers of this function, at addresses 43B418 and 4181FA, and in the patched version they both have a push instruction added before the call to specify the length of their buffers, 0x100 and 0x1F4 respectively.

Now, a push instruction with a 32-bit literal operand takes 5 bytes. In order to add this instruction to these two functions while staying within the tight space of the original code (whose logic must also remain intact), the patcher did the following:

For function at address 43B418, the patched function temporarily stores some value - which it will need later on - in ebx instead of a local stack-based variable, which releases enough bytes for injecting the push call. (By the way, additional evidence of manual patching is that while the local variable is no longer used, space for it is still made on the stack; otherwise sub esp, 0x10C would turn into sub esp, 0x108.)

For the other caller, function at address 4181FA, the patched function mysteriously has the push instruction injected without any other modifications to the code that would introduce the needed extra space.

As you can see on the above image, the push instruction is injected at the beginning of the yellow block, and all original instructions in that block are pushed down 5 bytes. But why does this not overwrite 5 bytes of the original code somewhere else? It's as if there were 5 or more unused bytes already in existence just after this block of code that the patcher could safely overwrite.

To solve this mystery, let's look at the code in its text form.

Surprise, the vulnerable version actually had an extra jmp loc_418318 instruction at the end of the modified code block. How convenient! This allows the code in this block to be moved down 5 bytes, making space for the push instruction at the top.

Coincidence? Perhaps, but it looks an awful lot like this code block got manually modified before in the past, whereby it got shortened for 5 bytes and its last instruction (jmp loc_418318) was left there.

Additional Security Checks

What we've covered so far was related to Embedi's published research and CVE-2017-11882, but is not what blocks Embedi's exploit. The new version of EQNEDT32.EXE has two additional modified functions at addresses 41160F and 4219F0. Let's have a look at them.

In the patched executable, these two functions got a bunch of injected boundary checks for copying to what appear to be 0x20-byte buffers. These checks all look the same: ecx (which is the counter for copying) is compared to 0x21; if it's greater than or equal to that, ecx gets set to 0x20. All these checks are injected right before inlined memcpy operations. Let's look at one of them to see how the patcher made room for the additional instructions.

As shown on the above image, a check is injected before the inlined memcpy code. Note that in 32-bit code, memcpy is typically implemented by first copying blocks of 4 bytes using the movsd (move double word) instruction, while any remaining bytes are then copied using movsb (move byte). This is efficient in terms of performance, but whoever was patching this noticed that some space can be freed by only using movsb, and perhaps sacrificing a nanosecond or two. After doing so, the code remained logically identical but now there was space for injecting the check before it, as well as for zero-terminating the copied string. Again, an impressive and clever hack (and there was still an extra byte to spare - notice the nop?)

There are six such length checks in two modified functions, and just one of them is directly responsible for blocking Embedi's exploit. We believe that Microsoft noticed some additional attack vectors that could also cause a buffer overflow and decided to proactively patch the other five memcpys and the patched function we covered earlier.

Final Touches

After patching the vulnerable code and effectively manually building a new version of Equation Editor, the patcher also corrected the version number of EQNEDT32.EXE to 2017.8.14.0, and the TimeDateStamp in the PE header to August 14, 2017 (hex value 5991FA38) - which is just 10 days after Microsoft acknowledged receipt of Embedi's report. (Note however that due to the manual nature of setting these values it's possible that code has been modified after that date.)

[Update 11/20/2017] Another thing Microsoft also patched in EQNEDT32.EXE was the "ASLR bit", i.e., they set the IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE flag in the PE optional header structure:

This is good. Enabling ASLR on EQNEDT32.EXE will make it harder to exploit any remaining memory corruption vulnerabilities. For instance, Embedi's exploit would not work with ASLR because it relied on the fact that the call to WinExec would always be present at the same memory address; this allowed them to simply put that address on stack and wait for the ret to do all the work.

Interestingly, Microsoft decided not to also set the IMAGE_DLLCHARACTERISTICS_NX_COMPAT ("DEP") flag, which would prevent code execution from data pages (e.g., from stack). They surely had good reasons, but should any additional vulnerabilities be found and exploited in EQNEDT32.EXE, the exploit will likely include execution of data on stack or heap. [End update 11/20/2017]


Maintaining a software product in its binary form instead of rebuilding it from modified source code is hard. We can only speculate as to why Microsoft used the binary patching approach, but being binary patchers ourselves we think they did a stellar job.

This old Equation Editor is now under the spotlight, and many researchers are likely to start fuzzing it for additional vulnerabilities. If any are found, we'll probably see additional rounds of manual binary patches in EQNEDT32.EXE. While Office has had a new Equation Editor integrated since at least version 2007, Microsoft can't simply remove EQNEDT32.EXE (the old Equation Editor) from Office as there are probably tons of old documents out there containing equations in this old format, which would then become un-editable.

Now how would we micropatch CVE-2017-11882 with 0patch? It would actually be much easier: we wouldn't have to shrink existing code to make room for the injected one, because 0patch makes sure that we get all the space we need. So we wouldn't have to come up with clever hacks like de-optimizing memcpy or finding an alternative place to temporarily store a value for later use. This freedom and flexibility makes developing an in-memory micropatch much easier and quicker than in-file patching, and we believe software vendors like Microsoft could benefit greatly from using in-memory micropatching for fixing critical vulnerabilities.

Oh by the way, Microsoft also updated Office's wwlib.dll this Patch Tuesday, prompting us to port our DDE / DDEAUTO patches to these new versions. 0patch Agent running on your computer will automatically download and apply these new patches without interrupting you. If you don't have 0patch Agent installed yet, we have good news for you: IT'S FREE! Just download, install and register, and you're all set. 



P.S.: If you happen to know the person(s) who did the binary patching of EQNEDT32.EXE, please send them a link to this blog post. We'd like them to know how much we admire their work. Thanks! 

Thursday, November 9, 2017

0patching a Pretty Nasty Microsoft Word Type Confusion Vulnerability (CVE-2017-11826)

by Mitja Kolsek, the 0patch Team

In September 2017, Qihoo 360 Core Security detected an in-the-wild attack that leveraged an Office 0day vulnerability now known as CVE-2017-11826. The attack employed an RTF document with embedded DOCX Word documents, whereby one of them exploited the vulnerability to cause type confusion in the OOXML parser, Microsoft's parser for Office Open XML File Formats. Additional noteworthy analyses of this vulnerability subsequently came from McAfee and Kaspersky.

Yang Kang, Ding Maoyin and Song Shenlei of Qihoo 360 Core Security reported this issue to Microsoft, which fixed it in their October security update.

This vulnerability is particularly easy to exploit, as it only requires the user to open a malicious RTF document in Word (which is the default RTF editor when installed), and isn't mitigated by Word's Protected View. It is actually surprising that it's not getting exploited more widely, as attackers know very well that many organizations need weeks or months to apply software updates.

Once we got the exploit file* we could start the analysis. We first minimized the exploit file by removing unnecessary payload and effectively turning it into a crash PoC. Turning a working exploit (one that reliably executes malicious code) into a crash case is an important step for us because in contrast to malware analysts, we're not interested in what malware does when it gets control, but only how it gets control. Making an exploit crash instead of execute its code generally leads us closer to the vulnerability that gets exploited - and closer to writing a patch for it. It's also easier to test a patch, once you have one, with a simple and quick test case.

* Exercise caution with this exploit file - it may run malware on your computer. (Password is aiongnostes1004.)


Opening the crash PoC in Word 2010 crashes immediately with a call to an illegal address:

This looks like a call to a vtable function, and since we already learned from Kaspersky above that we're dealing with a type confusion issue, it's likely that we're looking at a case of code processing an object of some expected type with the address at ecx+4 supposedly pointing to a valid function, while the object is actually of a different type.

Type confusion flaws are not the easiest kind to patch if you don't have the source code. While the fix is usually in the form "if type != EXPECTED_TYPE goto GET_OUT_OF_HERE", it's not trivial to figure out where the said type resides in the object without looking around the code where else the same type may be used. Once you have that figured out, it's relatively simple to determine the EXPECTED_TYPE by observing the type value with legitimate test cases and comparing that to the value when you process the PoC. Finding a suitable GET_OUT_OF_HERE location also needs some figuring out: you want the patched code to escape the flaw gracefully without leaving a corrupted state or cutting off some legitimate functionality. So sometimes this can get time consuming - but in this case, we had the official fix so we could peek into what Microsoft did to correct this flaw.

Diffing the patched wwlib.dll with the latest vulnerable one revealed very few changes. In fact, the only noteworthy change was in the exact function containing the above call that crashes. Let's look at the diff:

The patched function is on the left, the vulnerable on the right (click the image to magnify). It's easy to see that the patched function introduced a branch before the grey-marked code in the vulnerable function. And it looks exactly like "if type != EXPECTED_TYPE goto GET_OUT_OF_HERE": it starts with a check for a specific value, and if there is no match, execution is diverted to some new code (marked "Safe exit code" above), which avoids the call that crashed.

The only surprise is that instead of seeing a comparison of some type variable with some type constant (usually a small number, resulting from an enum clause in the source code), we see a comparison with a function address:

cmp ds:[eax+0x48], 0x31E94A4A

Note that 0x31E94A4A is actually an address of some function in wwlib.dll, which gets stored to the address pointed to by eax+0x48 a couple of blocks earlier in the same patched function. So what Microsoft's patch seems so do is check the validity of the object not by inspecting its type (perhaps there is no type ID in the structure at all), but by inspecting the address of a function pointed to by the object. Why not - as long as it works. No one in the world knows this code better than Microsoft's developers and if they thought this was the best possible fix, they're probably right.


Without further analysis, we can clone the same logic to the vulnerable code. The only thing we add is the "Exploit Attempt Blocked" dialog in case the object type is found to be incorrect. And here is the result:

What Do You Do Now?

We wrote a CVE-2017-11826 micropatch for 32-bit Word 2010's wwlib.dll version 14.0.7182.5000. While it's generally simple, and often fully automatable, to port a micropatch to other module versions, we prefer to do that on demand for now. So if you're running any affected Office version and for any reason can't apply Microsoft's official update (yet) but would like to be protected from this highly exploitable vulnerability, do let us know at We'll port the micropatch to your version and make it available for everyone else too.

If you are a security researcher and have a non-public proof-of-concept for some vulnerability, consider either writing a micropatch for it (using 0patch Agent for Developers) or sharing the PoC with us so we can create a micropatch together. You'll see it's almost as fun to thoroughly break someone's exploit as it is to write one ;)



Friday, November 3, 2017

Office DDE Exploits and Attack Surface Reduction

by Mitja Kolsek, the 0patch team

Windows 10 Fall Creators Update brought a powerful security capability: Windows Defender Exploit Guard. Among its many features and mitigations, the one that sounded most interesting to us was the Attack Surface Reduction (ASR) - especially for its announced ability to block DDE-based attacks:

DDE-based attacks have been very popular lately. They are misusing a DDE-related feature whereby Office gets tricked into launching a malicious executable via a DDE or DDEAUTO field, the latter only requiring the user to confirm one non-security notice.

You may also know that we have created a free micropatch for Word that prevents DDE fields from launching any executables - thereby enforcing the behavior specified in official Microsoft documentation, effectively blocking DDE attacks.

We therefore wanted to see how ASR does its magic. So we installed the Fall Creators Update and Office 2010, and followed Microsoft's instructions to enable the "Block Office applications from creating child processes" rule. We tested how DDE-based attacks are blocked, looked around a bit to see what could go wrong, and compared the said mitigation to our micropatch.

You can see the whole process in the video below, but the main takeaways are these:

  1. Most importantly, we confirmed that ASR does block DDE attacks in Word.
  2. Unfortunately, ASR only applies to Word, Excel, PowerPoint and OneNote, so Outlook-based DDE attacks are not blocked. (Perhaps Outlook will be added at a later time?)
  3. Also unfortunately, the ASR rule in question breaks some legitimate functionality. We found, for instance, that  it prevents Adobe Reader from being launched via Word's legitimate "Create PDF/XPS Document" functionality. There is another case (not shown in video) with Word being unable to launch "System Info" from the About dialog. Legitimate Word add-ins may want to launch processes too, and will be blocked.
  4. In comparison, a real fix (in this case, our micropatch) only blocks the dangerous process-launching while leaving all other functionalities intact; it also automatically works in Outlook. Naturally, an actual code fix is always better than a generic mitigation.
  5. Nevertheless, exploit mitigations have one big advantage compared to patches: they can stop or slow down attackers exploiting unknown vulnerabilities. A patch can only fix a known bug.

In conclusion, ASR (with all its rules) is a very powerful tool and while one must exercise caution with its blocking of potentially legitimate functionality, it can significantly limit the attacker. So by all means use it if you can, but also apply patches for known vulnerabilities!

You can't use ASR, unfortunately, on non-Windows-10 systems, or on Office 2007, which has just reached its end of support but is likely still used in many places. 

Stay safe!