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"
PATCH_ID 313
PATCH_FORMAT_VER 2
VULN_ID 3084
PLATFORM win32
patchlet_start
PATCHLET_ID 1
PATCHLET_TYPE 2
PATCHLET_OFFSET 0x0001164C
code_start
cmp ecx, 21h
jb skip
mov ecx, 20h
call PIT_ExploitBlocked
skip:
code_end
patchlet_end
patchlet_start
PATCHLET_ID 2
PATCHLET_TYPE 2
PATCHLET_OFFSET 0x00011661
code_start
xor eax, eax
stosb ; zero-terminate the string
code_end
patchlet_end
MODULE_PATH "C:\Analysis\CVE-2017-11882\EQNEDT32.EXE"
PATCH_ID 313
PATCH_FORMAT_VER 2
VULN_ID 3084
PLATFORM win32
patchlet_start
PATCHLET_ID 1
PATCHLET_TYPE 2
PATCHLET_OFFSET 0x0001164C
code_start
cmp ecx, 21h
jb skip
mov ecx, 20h
call PIT_ExploitBlocked
skip:
code_end
patchlet_end
patchlet_start
PATCHLET_ID 2
PATCHLET_TYPE 2
PATCHLET_OFFSET 0x00011661
code_start
xor eax, eax
stosb ; zero-terminate the string
code_end
patchlet_end
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 :)
No comments:
Post a Comment