Monday, July 10, 2017

0patching the Quick Brown Fox of CVE-2017-0283


By Luka Treiber, 0patch Team.

Among many other things, last Patch Tuesday brought a fix for an RCE vulnerability named "Windows Uniscribe font processing heap-based memory corruption in USP10!MergeLigRecords".  A couple of days later Mateusz Jurczyk of Google Project Zero published a report with PoC attached. Out of the eight vulnerabilities reported at the same time in that Windows library I chose to patch this one for being the most severe.


Reproduction

Opening font files from the PoC.zip package in Windows Font Viewer displayed the "quick brown fox text" in weird constellations but without a crash. With no exact PoC instructions given this was the procedure that worked for me on Windows 7 x64:
  1. unpack the PoC
  2. install signal_sigsegv_313372b5_210_42111ccffd2e10aba8b5e6ba45289ef3.ttf (or any other TTF from the package) on the system
  3. run Notepad
  4. select Format->Font...>[Font] 4000 Tall and [Script] Arabic
immediately a crash occurs at

(1410.378): Unknown exception - code c000041d (!!! second chance !!!)
msvcrt!memcpy+0x1c0:
000007fe`fd651444 8a040a          mov     al,byte ptr [rdx+rcx] ds:00000000`025230e8=??

The callstack: it matches the one from report

msvcrt!memcpy+0x1c0
USP10!MergeLigRecords+0x7f
USP10!LoadTTOArabicShapeTables+0x5f8
USP10!LoadArabicShapeTables+0x148
USP10!ArabicLoadTbl+0xf0
USP10!UpdateCache+0xf5


Analysis of the PoC

It is usually worth to take a look at PoC and try to understand its payload first before diving into debugging, and thus save a lot of time by knowing what data patterns to look for in the application's memory. So I searched the Internet for the original TTF file the PoC was derived from. I quickly found one and started diffing the two files in order to locate malformed font attributes. Comparison showed a common structure of the files. However, it became clear that an automatic fuzzer was used and too many attributes were polluted with suspicious values to sift through by hand. That task was definitely not a time-saver so I had to give it up.


Analysis of the official patch

Extracting and analyzing the official patch is the next reasonable thing to do after a Patch Tuesday. So let's see how this goes.

The vulnerable version 1.626.7601.23688 of usp10.dll got replaced by the patched 1.626.7601.23807. The files are both of approximately the same size (788KB) and when compared using BinDiff a match of 733 functions is found. Among those are also the ones from the crash call stack above. It makes sense to check differences in those functions first as the patch is often a sanity check on input data inserted before a vulnerable call. The first one - USP10!MergeLigRecords from the immediate crash context - is identical but the next one - USP10!LoadTTOArabicShapeTables - shows some interesting changes in the function graph. Left is the old (vulnerable) and right is the new (patched) version of usp10.dll




We can see that the vulnerable call MergeLigRecords is enclosed in a loop.



Within that loop the only significant change in the patched version is the gray cmp-jnz block that has been added to the patched DLL version. Could this be the patch? With limited analysis done so far it is hard to say what the data in comparison (rsp+var_9C) means, but it is clear that by introduction of that block the criteria to reach the problematic call is more refined than in the old version. This is also a behavior I would expect of a patch.

The only way to make sure is to debug. So we start WinDbg and attach it to notepad.exe on a vulnerable system. We set three breakpoints. One at the vulnerable MergeLigRecords, one before the call to ttoGetTableInfo, and one after. The ttoGetTableInfo call is interesting because it takes two struct parameters - TTOOutput and TTOInput. The gray if block that follows right after, checks if one of the TTOOutput attributes (rsp+var_9C) is 4 and in case of a mismatch exits the loop. So what we're interested in is where/if rsp+var_9C changes inside ttoGetTableInfo and how it is related to the crash inside MergeLigRecords. Before we hit [F5] in WinDbg and click-through the PoC we also need to locate a match for the rsp+var_9C attribute from the patched version in the vulnerable code.




We see that, conveniently, a reference to the same attribute can be found in the old LoadTTOArabicShapeTables named as rsp+var_A4 (it resolves to @rsp+34 in the snippets below).

Now we can observe our checkpoints in WinDbg

0:002> bu0 @!"usp10"+1e32f "dw @rsp+34 L1";
0:002> bu1 @!"usp10"+1e334 "dw @rsp+34 L1";
0:002> bu2 @!"usp10"+1e3f3;
0:002> g

In the first two passes, the value of var_A4 is 0004 and does not change. Also the USP10!MergeLigRecords call executes without a crash.

USP10!LoadTTOArabicShapeTables+0x52f:
000007fe`fd59e32f e8bcfd0000      call    USP10!ttoGetTableInfo (000007fe`fd5ae0f0)
0:000> g
00000000`001edd14  0004
USP10!LoadTTOArabicShapeTables+0x534:
000007fe`fd59e334 85c0            test    eax,eax
0:000> g
Breakpoint 2 hit
USP10!LoadTTOArabicShapeTables+0x5f3:
000007fe`fd59e3f3 e8b8010000      call    USP10!MergeLigRecords (000007fe`fd59e5b0)
0:000> g
00000000`001edd14  0004
USP10!LoadTTOArabicShapeTables+0x52f:
000007fe`fd59e32f e8bcfd0000      call    USP10!ttoGetTableInfo (000007fe`fd5ae0f0)
0:000> g
00000000`001edd14  0004
USP10!LoadTTOArabicShapeTables+0x534:
000007fe`fd59e334 85c0            test    eax,eax
0:000> g
Breakpoint 2 hit
USP10!LoadTTOArabicShapeTables+0x5f3:
000007fe`fd59e3f3 e8b8010000      call    USP10!MergeLigRecords (000007fe`fd59e5b0)
0:000> g


In the third pass, var_A4 gets changed by the ttoGetTableInfo call from 0004 to 0001 and MergeLigRecords crashes the app.

00000000`001edd14  0004
USP10!LoadTTOArabicShapeTables+0x52f:
000007fe`fd59e32f e8bcfd0000      call    USP10!ttoGetTableInfo (000007fe`fd5ae0f0)
0:000> g
00000000`001edd14  0001
USP10!LoadTTOArabicShapeTables+0x534:
000007fe`fd59e334 85c0            test    eax,eax
0:000> g

Breakpoint 2 hit
USP10!LoadTTOArabicShapeTables+0x5f3:
000007fe`fd59e3f3 e8b8010000      call    USP10!MergeLigRecords (000007fe`fd59e5b0)
0:000> p
(14a8.189c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
msvcrt!memcpy+0x1c0:
000007fe`fd651444 8a040a          mov     al,byte ptr [rdx+rcx] ds:00000000`03bf5018=??

At this point we can conclude that the gray cmp-jnz block would've prevented the crash so we found a patch candidate and can make a 0patch of it.


Patching

So far we've assembled all required pieces to build one - it's all in the gray block in above diff. And below is the resulting .0pp file I made.

MODULE_PATH "C:\Windows\System32\usp10.dll"
PATCH_ID 273
PATCH_FORMAT_VER 2
VULN_ID 2536
PLATFORM win64

patchlet_start
PATCHLET_ID 1
PATCHLET_TYPE 2
PATCHLET_OFFSET 0x0001e32f
PIT USP10!0x2e0f0      ; import USP10!ttoGetTableInfo
JUMPOVERBYTES 5
N_ORIGINALBYTES 1

 code_start
  call PIT_0x2e0f0     ; call USP10!ttoGetTableInfo
  cmp word[rsp+34h], 4 ; var_A4
  je skip              ; inverse condition from original patch
  or eax, 01h          ; set piggyback condition
  skip: 
 code_end
patchlet_end

When turning the official patch into a 0patch I used a "jump condition piggy-backing" technique already described in a previous post (only this time It is the quick brown fox I'm piggy-backing). Conveniently the official patch is right next to a jump (jnz) that exits the problematic loop so this is also the location for our 0patch. I placed it before the original jnz. Due to lack of space (jnz is only 2 bytes long while we always need 5 to jump to our patch code) I had to place it before the ttoGetTableInfo call that 0patch Agent will substitute with the 5 byte jump. The first instruction in the patch is therefore the substituted original call to ttoGetTableInfo. What follows it is the check from the official patch. First var_A4 is compared to 4 to check if the loop can continue, otherwise eax that holds the result of ttoGetTableInfo, is set to 1 so the test eax,eax instruction from original code that follows the patch will set a jump flag (zf=0) for the jnz that will exit the loop.

After compiling this .0pp file with 0patch Builder, the patch gets applied and the PoC crashes no more. Our team tested it also against the other TTF files from the PoC.zip package and all of them seem to be disarmed. It is worth noting, however, that this patch only covers the execution route discovered in the Reproduction section above. In the diff of LoadTTOArabicShapeTablesthere there is one more cmp-jnz gray block added to the patched usp10.dll that exits a similar loop to the one covered above. But since there is no public PoC available that would trigger that branch of execution we won't include it in a 0patch. The only safe way for 0patch to work is to cover testable execution paths.

Now, if you haven't so far, install 0patch Agent  and check the PoC to test it for yourself. Next time you see a quick brown fox jumping, make sure that you have 0patch Agent enabled.

Monday, June 19, 2017

A Quick Analysis of Microsoft's ESTEEMAUDIT Patch

And why CVE-2017-0176 and CVE-2017-9073 are probably not the same thing

By Mitja Kolsek, 0patch Team

As you may know, we at 0patch wrote a micropatch for Equation Group's ESTEEMAUDIT exploit last month. It took us quite a while to reproduce the issue until we figured out that the attack only works against computers joined in a Windows domain, but after that, writing a patch was fairly simple. The image below shows its source code and the "Exploit Attempt Blocked" dialog that gets shown when ESTEEMAUDIT attack is detected and blocked.

Our patch is really simple: we check whether the data received from the remote smart card (imitated by ESTEEMAUDIT) is larger than 80h, which is the size of the destination buffer in gpkcsp.dll. If the received data is larger - and with ESTEEMAUDIT it is - we first alert our locally running 0patch agent (which pops up the alert) and then reduce the size of received data to 80h to prevent buffer overflow. This effectively blocks the attack without disrupting legitimate functionality by introducing just 4 machine instructions into the original code.

 
 

About a month later, Microsoft published their official update for ESTEEMAUDIT and several other vulnerabilities despite originally indicating that they would only provide these updates to customers with extended support. This is good: official vendor updates are the preferred way to fix vulnerabilities, and 0patch aims to provide most value when fixing issues that have no official fixes, or to provide protection from critical vulnerabilities to organizations in their security update gap.

Naturally, we were interested in how Microsoft fixed this vulnerability and compare their fix to ours. Enter IDA Pro and BinDiff; after a few minutes, we could compare the two side-by-side.




With fixed code on the left, and vulnerable code on the right, it's not-surprisingly obvious that Microsoft's patch also introduces the same check we did, at the exact same location. The main difference between our fixes is that while we just cut the received data to valid length, they spawn an error if the data is too long, and abandon the connection.

This makes sense: an official patch should provide troubleshooting info, wile a micropatch should just close the hole with minimum code.

But surprise: BinDiff shows another change.




Elsewhere in the code, Microsoft added another similar check, also checking for the received data length exceeding 80h - and responding with an error if so.

They obviously reviewed their code and noticed that a similar bug exists after another DoSCardTransmit call, and fixed it as well. Note that this second bug is not exploited by ESTEEMAUDIT, but would likely be found by interested parties based on the first one. Microsoft and other decent software vendors routinely search their code for vulnerabilities similar to those they learn about (either internally or externally), and proactively fix them.

This second bug, however, begs the question: Are there any other similar bugs there?

There are 66 calls to DoSCardTransmit in gpkcsp.dll, and we briefly looked at them. We were interested in cases where the received buffer would be copied to some other buffer. There actually was one such case, apart from those patched by Microsoft, as shown on the image below.




Again, the latest gpkcsp.dll is on the left side, and apparently no data length check was added to it. The code is suspiciously similar to the vulnerable code, but it really all depends on the size of the destination buffer at ds:[edx+ebx]. We had no time to look further into this but we hope Microsoft did and found it to be non-exploitable.

By the way, the ESTEEMAUDIT vulnerability was assigned CVE-2017-9073 but Microsoft associates its fix with CVE-2017-0176. This causes some confusion and makes people wonder whether the two CVEs are duplicates. Based on the above analysis of Microsoft's fix, it seems most accurate to say that CVE-2017-9073 is a subset of CVE-2017-0176, the former being only the ESTEEMAUDIT vulnerability and the latter also including the second similar issue that Microsoft also patched.

@mkolsek
@0patch

Monday, May 15, 2017

0patching the "Worst Windows Remote Code Execution Bug in Recent Memory" CVE-2017-0290


Building up our Skills and Speed for the Future WannaCry Attacks

By Mitja Kolsek, 0patch Team

Like many other stories of the past week, mine begins with this tweet.



Natalie Silvanovich and Tavis Ormandy of Google Project Zero found a pretty nasty bug in Microsoft Malware Protection Engine, allowing an attacker to execute arbitrary code as LocalSystem on any Windows computer running any Microsoft anti-malware product such as Security Essentials or Windows Defender by simply having that computer access a malicious file. Attack vectors were abundant, from emailing the file or sending it via any other channel like Skype or Messenger, to having it hosted on a malicious web site or uploading it to an IIS web server.

Unlike many other stories of the past week, mine is not about how Natalie and Tavis found this bug, how they reported it to Microsoft or how the fact that they found and reported it was made known to the public. Rather, it is about the bug itself, its root cause, and - of course - about writing a micropatch for it.

But first: why would we want to write a micropatch for a vulnerability that would quickly get automatically fixed on all Windows computers anyway? As you may know, Microsoft was super fast in fixing this bug and made an update available literally over the weekend. Furthermore, the Malware Protection Engine is implemented as a dynamic-load library mpengine.dll, and Microsoft designed their anti-malware products smartly enough to not require a computer restart - the old DLL is simply unloaded, and the new one loaded.

So why write a micropatch? Well, not every computer gets updated automatically: while automatic application of updates is configured by default, admins can change that if they want to control what gets applied when. And enterprise admins like to have such control, allowing them to test new code before deploying it to computers throughout their organization. Just imagine the updated mpengine.dll having a flaw that prevented users from accessing legitimate files.

Another reason for writing this micropatch was to learn, as we haven't patched a security product before - and one can expect to stumble upon something new here (and stumble I did, as you will see). The final reason was to teach, to share some knowledge with those of you who want to analyze vulnerabilities yourselves and learn how to write micropatches.


Reproducing CVE-2017-0290

The first step in analyzing a vulnerability is to reproduce its exploitation. The Project Zero report provides a downloadable proof-of-concept file, which has a .zip extension, but is really an HTML-lookalike file that comprises a tiny exploit bit and a lot of random HTML content that makes sure the engine processes the file.

Reproducing on 64-bit Windows 8.1 was trivial - just downloading and saving the file was enough to make the Windows Defender service crash, instantly turning from this:



 to this:





After the crash, the Application Event Log contained an Error event about this crash, revealing the crashing module being mpengine.dll, and the crash location being at offset 0x21745a. (You will find a different crash address in Google's report because they were working on a 32-bit computer.)




Note that I was using mpengine.dll version 1.1.13701.0, which is the last vulnerable version before the fixed 1.1.13704.0. It is always good to do your analysis on the last vulnerable version in order to minimize the difference with the fixed version - you will thank yourself when diffing these versions.


Analyzing CVE-2017-0290

With the bug successfully reproduced, the path was clear towards analysis. Here, the Google report was a great start, as Natalie and Tavis have clearly gained substantial understanding of what goes on in the crash case. The most important detail for me was that it was a type confusion error, specifically with some function expecting a string object but getting a number object (which resulted in calling a string vtable function where there really was no vtable).

This was important because when a bug is a type confusion error, a typical fix is to add the missing check for the correct type. And such a fix is usually easy to recognize when observing the difference between vulnerable and fixed code.

Which brings us to IDA. The image below shows the function that crashed - the exact access violation location was the mov rax, [rcx] instruction (see the red box) at address 0x75A31745A, which is at offset  0x21745a from mpengine.dll's default base address.




When a vendor patch is available, diffing the vulnerable and the patched version usually provides useful information and allows you to understand the bug, and the patch, better. Diffing can be a time-consuming operation though first for the computer and then for you, and with large binaries (mpengine.dll is 12MB) you can get a lot of matched functions, and finding where the code logic is different - as opposed to where the code is different - can be somewhat frustrating.

So I went on to diff the two versions of mpengine.dll, the vulnerable 1.1.13701.0 and the patched 1.1.13704.0. There were 38440 matched functions, which, in scientific terms, is an awful lot. What I could do with these results was compare the above crashing function between the two versions. If I was lucky, the patch would be there and I could go home early.




Nope. Both functions are logically identical, which means that the flaw (and the patch) is somewhere higher on the call stack. At this point one could diff all functions that call this function, but there are about 50 of them - and if all of those turned out to be identical as well, such approach could turn into an exponential mission impossible. (Not to mention that IDA may not see all callers.)
 
Now about the call stack: you will notice that I haven't used a debugger up to this point, and the reason is that Windows Defender is a protected service and as such tries very hard to protect itself from tampering. You cannot attach a debugger to a protected process, even if you're a local administrator. And it's not easy to un-protect a protected service either: while its protected status is defined by the LaunchProtected registry value (in our case under HKLM\SYSTEM\CurrentControlSet\Services\WinDefend), you cannot change that value for Windows Defender while Windows Defender is running as it prevents you from "attacking" it.

Fortunately, we have a way to stop Windows Defender - by crashing it with the PoC. So what I did was crash Windows Defender, rename its LaunchProtected registry value, restarted the computer (the protected status of services is read only at system startup), then configured Windows Error Reporting to generate dump files for crashing processes. (I only created the LocalDumps key and the DumpFolder value containing "C:\dumps" in it.)

After crashing Windows Defender again, I got its mini dump file in C:\dumps, and it contained a full call stack for the access violation. I was only interested in locations from mpengine.dll:

mpengine!FreeSigFiles+0x11ea9a 
mpengine!FreeSigFiles+0x12046f 
mpengine!FreeSigFiles+0x111e81 
mpengine!FreeSigFiles+0x111d9e 
mpengine!FreeSigFiles+0x125eaa 
mpengine!FreeSigFiles+0x3de1d  
mpengine!FreeSigFiles+0x3dbf5  
mpengine!FreeSigFiles+0x125eaa 
mpengine!FreeSigFiles+0x117ade 
mpengine!FreeSigFiles+0x120146 
mpengine!FreeSigFiles+0x113d76 
mpengine!FreeSigFiles+0xcce7f  
mpengine+0x54a99               
mpengine+0x865e1               
mpengine+0x50f3f               
mpengine+0x50d1f               
mpengine+0x8c208               
mpengine+0x8bf47               
mpengine!FreeSigFiles+0x174a3  
mpengine+0x13b7d               
mpengine!FreeSigFiles+0x1535a  
mpengine!_rsignal+0x243        
mpengine!_rsignal+0xe7  
  

The top one we already know - it's the access violation location in the crashing function that we diffed just moments ago. So I proceeded with the second address, FreeSigFiles+0x12046f, and located it in IDA. It was, as expected, after a call to the crashing function. I then took the address of the function containing that address, and viewed the diff with its patched version.




Now we're talking! This looks like a typical added check that exits a function if something is not right. (The patched version is on the left.) The upper red block is added code that takes rdi (the object) and passes it to a call to some function, and if the result of that function is 4, the execution continues as before, otherwise the return value (al) is set to 0 in the lower red block, and the function exits. The function that gets called from the upper red block seems to determine the type of the object and returns its type code. Reviewing other calls to this function I found a very obvious implementation of JavaScript's typeof operator, which confirmed that type code for string is actually 4.

This is clearly the patch I was looking for. It was simple, it did exactly what I was expecting it to do, and it was in the code path of our crash.


Micropatching CVE-2017-0290

My goal at this point was to create a micropatch that would inject the same patch logic into the vulnerable version of mpengine.dll. In a perfect world, I could use literally the same code that I found in the patched version, and inject it in the same place - but in this world a compiler likes to use different registers and different implementation of the same logic in two subsequent builds. So I had to re-implement the patch logic from the original patch.

Let's look at the vulnerable function in IDA.




The above image shows the vulnerable function and a good location for injecting our code. The location is selected so that it allows us to jump from our patchlet code directly to the function epilogue (the lowest block of code).

Here is the patch code for 64-bit mpengine.dll version 1.1.13701.0:


;0patch for CVE-2017-0290 in 64-bit mpengine.dll version 1.1.13701.0

MODULE_PATH "C:\Analysis\CVE-2017-0290\mpengine.dll_64bit_1.1.13701.0\mpengine.dll"
PATCH_ID 271
PATCH_FORMAT_VER 2
VULN_ID 2436
PLATFORM win64


patchlet_start
 PATCHLET_ID 1
 PATCHLET_TYPE 2
 PATCHLET_OFFSET 0x218E10

 ; We'll need the GetTypeOf function and the location of function epilogue
 PIT mpengine.dll!0x218940,mpengine.dll!0x218E9A

 ; Note that GetTypeOf taints the following registers:
 ; rdx - always
 ; rcx - only in case of an exception
 ; rax - expected, this is the return value
 
 code_start

  push rcx          ; We need to preserve rcx, as it's still used after our patchlet code
                    ; while GetTypeOf taints rdx, we don't need to preserve it
  mov rcx, r9       ; r9 points to the object
  call PIT_0x218940 ; GetTypeOf object
  pop rcx           ; restore rcx
  cmp eax, 4        ; is the object of type string?
  jz OK             ; It is? Very well, continue...

  xor al, al        ; It isn't? Exit this function without doing anything, return 0
  call PIT_ExploitBlocked ; Show "Exploit attempt blocked"
  jmp PIT_0x218E9A  ; Jump to function epilogue
 
  OK:

 code_end
patchlet_end


What this single-patchlet patch, inserted at the shown point in code, does is - just as the original patch - call GetTypeOf on the object (whose address is in register r9) and see if its type code is 4 (string). If it is, it continues execution of original code where it was injected . Otherwise, it sets the return code (register al) to 0 and jumps to function epilogue.

Note that in order to avoid any negative side effects, I had to (1) review the GetTypeOf function to see which registers it may taint and whether that could impact the code after our injected patch (it taints rdx and rcx, but rdx holds nothing valuable at our injection point), and then (2) store rcx on the stack before calling GetTypeOf function because rcx holds some value that is still being used after our injected patch.

I also wrote the same patch for the last vulnerable 32-bit version of mpengine.dll. If you have 0patch Agent installed, patches ZP-271 and ZP-272 should already be downloaded to your computer, waiting for any occurrence of the vulnerable mpengine.dll getting loaded.


The Irony of Protected Services


To restore the original system configuration, I turned Windows Defender back to a protected service, and... shoot, the patch stopped getting applied. It quickly became clear that we can't inject our loader into the protected Windows Defender because only binaries signed by Microsoft are allowed to get loaded. (It's a bit more complex than that but close enough.) This is Windows Defender protecting itself against local malware - even with admin privileges - trying to compromise it.

The irony is that a Windows anti-malware protection prevents our security product from fixing a vulnerability in Windows Defender, while the exploit for the same vulnerability can freely execute arbitrary code in Windows Defender. (Hmm, perhaps we should leverage this exploit to get our code running inside Windows Defender and thereby fix it.) 

So while we're exploring options for extending our reach towards patching protected services, patches ZP-271 and ZP-272 for Malware Protection Engine will only get applied on Windows 7 and Windows Vista, which don't have protected services.  


Experimenting with Micropatches for CVE-2017-0290


If you want to experiment with these micropatches, you'll need two things:
  1. A 32-bit or 64-bit Windows 7 computer running Windows Defender. While you could also do the testing on newer Windows versions, you would have to un-protect the Windows Defender service in order to proceed. 
  2. Vulnerable mpengine.dll. If your Windows Defender doesn't happen to have this exact version (unlikely, due to automatic updates), you can get it here:
    1. 32-bit mpengine.dll version 1.1.13701.0 for 32-bit Windows
    2. 64-bit mpengine.dll version 1.1.13701.0 for 64-bit Windows
First of all, stop the Windows Defender service via elevated Services console.

Then browse to C:\ProgramData\Microsoft\Windows Defender (folder permissions don't originally allow you to open it so Windows will ask you for elevation, after which it will add your account to the folder ACL). Open folder Definition Updates, and notice one or more subfolders with GUID-like names starting with curly braces. Open each of these folders to find the one containing mpengine.dll. Rename the existing mpengine.dll into something else, then save the vulnerable mpengine.dll there.

Start the Windows Defender service.

Download the proof-of-concept file and store it in some empty temporary folder.

Launch the Windows Defender console via the Control Panel, and Custom-Scan the above folder. Notice that Windows Defender service crashes.

Now install 0patch Agent on the computer. If you don't already have it, download a free copy and register it with your free 0patch account.

Finally, restart the Windows Defender service and re-scan the temporary folder. This time, you'll see an "Exploit Attempt Blocked" popup instead of Windows Defender crashing.

If you want to build our patches yourself, you can download their source code and build them using 0patch Agent for Developers.


While this vulnerability has already been automatically fixed on most computers, it turned out to be an interesting learning experience to micropatch it. I hope this post will help future micropatchers jump-start their research.

While I was writing this post, the world got pierced by the WannaCry ransomware worm exploiting a known vulnerability that had an official patch available for Windows operating systems which Microsoft supported at the time. Many hospitals and other critical infrastructure components were taken offline, partly also because they were stuck with unsupported OSs such as Windows XP. They have very rational and complex reasons for being on such outdated systems in 2017, and undoubtedly they will have similar reasons next year and the year after. One of our goals with 0patch is to provide protection for such end-of-support systems while users scramble to update them (and have the same problem almost immediately afterwards). Defending against modern attackers will require rapid response, and this exercise with CVE-2017-0290 - although likely of low value to users - was an example of building up skills and speed. The world will need a lot of 3rd-party patch developers though, so all existing and prospective security researchers are warmly welcome to join us.

@mkolsek
@0patch





Wednesday, March 29, 2017

0patching the "Immortal" CVE-2017-7269

A Remote Code Execution Bug on 60,000 Officially Unpatchable Servers

By Mitja Kolsek, 0patch Team

Two days ago, an interesting exploit by Zhiniang Peng and Chen Wu was published on GitHub. It's a simple Python script that you launch against any 32-bit Windows Server 2003 with WebDAV functionality enabled, and it executes calc.exe on that server. Needless to say, this exploit could easily be modified to download a malicious executable to the server and launch it, and we confirmed it can also be used against 64-bit servers. To fully compromise a server, the exploit would have to escalate its privileges from NETWORK SERVICE user to LOCAL SYSTEM, where tricks like this one or this one might come handy.

Now, what makes this exploit so interesting?

  1. According to Shodan, there are a little over 600,000 publicly accessible IIS 6.0 servers on the Internet, most of them likely running on Windows Server 2003. (This doesn't include an unknown number of servers not accessible from the Internet.)
  2. The extended support period for Windows Server 2003 ended 20 months ago, so there is no official security fix for this issue.

Fortunately, most 2003 servers don't have WebDAV functionality enabled, but it is likely enabled on many SharePoint Portal servers and sites that use it for remote Web authoring or similar. Iraklis Mathiopoulos ran a sample probe to determine how many of Internet-connected 2003 servers are WebDAV-enabled and found that approximately 10% of them are. So we seem to have about 60,000 servers out there exposed to this freshly published exploit.

Sure, some will say that everyone should have stopped using Windows Server 2003 long ago as it doesn't get security patches any more. But owners of these servers each have their own story, their own set of constraints to work within, and their own budgets that they would rather spend on something other than upgrading a server that works.

To help maintainers of Windows Server 2003 computers block almost inevitable attacks under these unfavorable circumstances, we decided to provide them a free solution: a micropatch for CVE-2017-7269, which they can apply on their machines not only without rebooting, but also without even restarting Internet Information Services. (For those new to 0patch, this is how we believe applying security patches should always look like.)

Let me describe the process of analyzing this vulnerability and creating a micropatch.

The first step in our analyses is always reproducing the exploit or proof-of-concept. In this case, it was trivial: exploit.py provided by Peng and Wu was simple and effective, and it reliably launched calc.exe on a local 32-bit Windows Server 2003.




A full-blown exploit is usually not ideal for analyzing the vulnerability; especially in a buffer overflow case, we would prefer the process crashing at its vulnerable location to launching the calculator. So I "dumbed down" the exploit by replacing all of its shell code with A's (0x41 bytes). I also used WinDbg's Global Flags to enable Page Heap on the vulnerable w3wp.exe process in hope to catch the buffer overflow immediately as it occurs.

Sure enough, after attaching to w3wp.exe and launching my simplified poc.py, an access violation was caught due to writing beyond an allocated memory block. The offending instruction was at location httpext!ScStoragePathFromUrl+0x360:

rep movs dword ptr es:[edi],dword ptr [esi]

Those familiar with Intel machine code will recognize rep movs as a memory copying procedure. So apparently the overflow occurs when one buffer is copied into another - which is not large enough. Setting a breakpoint at the beginning of the memory-copying code block revealed that a buffer pointed to by esi (source) contained a 433-wide-character string (i.e., 868 bytes including the trailing zero) "/aaaaaaaAAA...(many A's)...AAA>", which is the exact value of one of the tokens sent in the WebDAV request by poc.py. The destination buffer pointed to by edi, however, was approximately 50% too small to receive the string. This provided an initial hint that it could be a case of using wide (two-byte) characters but allocating a buffer based on the number of characters instead of the number of bytes they take.

Anyway, in order to find where the too-small destination buffer pointed to by edi was allocated, I used this nifty WinDbg extension !heap -p -a edi, which gave:

7c83d6d4 ntdll!RtlAllocateHeap+0x00000e9f
5b7e1a40 staxmem!MpHeapAlloc+0x000000f3
5b7e1308 staxmem!ExchMHeapAlloc+0x00000015
67125df9 httpext!CHeap::Alloc+0x00000017
67125ee1 httpext!ExAlloc+0x00000008
67125462 httpext!HrCheckIfHeader+0x0000013c
6712561e httpext!HrCheckStateHeaders+0x00000010
6711f659 httpext!CPropFindRequest::Execute+0x000000f0
6711f7c5 httpext!DAVPropFind+0x00000047
671296d2 httpext!CDAVExt::DwMain+0x0000012e
67117bc6 httpext!DwDavFSExtensionProc+0x0000003f

...

It seemed like the allocation of our destination buffer occurred in httpext!HrCheckIfHeader as a result of calling CStackBuffer::resize.

push    [ebp-434h]
lea     ecx, [
ebp-430h]
call    ?resize@?$CStackBuffer@G$0BAE@@@QAEPAGI@Z
test    eax, eax
jz      loc_155A2


So I set a breakpoint at the top of this code block to see what this resize was all about. It turned out that the local variable [ebp-434h] holds the length (in characters) of the input string, and the above code wants to resize an existing buffer to be able to hold this entire string.

My suspicion was confirmed: instead of specifying the number of bytes to allocate, the above resize call gets the number of characters - making the resulting buffer much too small. Looking around the above code, I found a similar code block where this calculation is done correctly, which further confirmed my analysis.

At this point, it was easy to decide how to patch: instead of pushing [ebp-434h] to stack as an argument to the resize function, we should push that same value multiplied by two and further increased by 2, to accommodate for the string-teminating zero. Since I didn't want to modify the local variable [ebp-434h] as it is also being used elsewhere, I decided to replace the push [ebp-434h] instruction with the following:

mov     eax, dword [ebp-434h]
lea     eax, [eax+eax+2]
push    eax


So I wrote a .0pp file for this and built a 0patch using our 0patch Builder (which, by the way, anyone can download as part of 0patch Agent for Developers), then I relaunched poc.py to see if my micropatch fixed the bug.

To my surprise, w3wp.exe still had an access violation in the same place. After checking that I didn't snafoo the patch, I traced the flaw again in the same way as before, only to discover that another, almost identical, incorrect buffer allocation takes place elsewhere in the code. Specifically, in httpext!CParseLockTokenHeader::HrGetLockIdForPath.

This second flaw was logically identical to the first one, and could be patched with effectively the same patch code using an additional patchlet. It was time to give poc.py another try and see how IIS reacts to it with the two patchlets applied.

Triumphantly, IIS returned "HTTP/1.1 207 Multi-Status" instead of reporting internal server error, and it did the same when the original exploit.py was launched against it. This was it, the bug was fully patched.

In conclusion, let's see the source code of this micropatch.


;target: Windows Server Standard 2003 R2 32bit, httpext.dll version 6.0.3790.4518 32bit
MODULE_PATH "C:\WINDOWS\system32\inetsrv\httpext.dll"
PATCH_ID 269
PATCH_FORMAT_VER 2
VULN_ID 2287
PLATFORM win32

patchlet_start
 PATCHLET_ID 1
 PATCHLET_TYPE 2
 PATCHLET_OFFSET 0x00015451
 JUMPOVERBYTES 6 ; eliminate the original "push dword ptr [ebp-434h]"

 code_start

   mov     eax, dword [ebp-434h]
   lea     eax, [eax+eax+2]
   push    eax

 code_end
patchlet_end

patchlet_start
 PATCHLET_ID 2
 PATCHLET_TYPE 2
 PATCHLET_OFFSET 0x0001574b
 JUMPOVERBYTES 6 ; eliminate the original "push dword ptr [ebp-22Ch]"

 code_start

   mov     eax, dword [ebp-22Ch]
   lea     eax, [eax+eax+2]
   push    eax

 code_end
patchlet_end


You can see that the patch comprises two patchlets, both containing the same three machine code instructions, just at different offsets into the vulnerable httpext.dll and with different offsets to the relevant stack-based local variable. Extremely lightweight, extremely unlikely to cause unwanted side effects, and extremely reviewable - just the way micropatching is supposed to be.

If you have 0patch Agent installed on your Windows Server 2003, patches ZP-269 and ZP-270, for 32-bit and 64-bit server, respectively, should already be present and applied. If not, you can download a free copy of 0patch Agent to protect your server from CVE-2017-7269. Note, however, that these patches are only applicable to a fully updated server with Service Pack 2 installed, as they were made specifically for 32-bit and 64-bit httpext.dll version 6.0.3790.4518. (Check your httpext.dll version in C:\Windows\System32\inetsrv.)

Finally, you should know that we're still in beta so keep an eye on your server and report any unusual events to us at support@0patch.com. Also let us know if you have some other version of httpext.dll and we'll try to port the patch for you.

@mkolsek
@0patch

Thursday, March 9, 2017

0patching another 0-day: Internet Explorer 11 Type Confusion (CVE-2017-0037)


By Luka Treiber, 0patch Team.

[Update 3/27/2017: After Microsoft has patched this issue, security researcher Alisa Esage posted a proof of its exploitability on Twitter. It is therefore clear that it was possible to both (1) set rax to a attacker-controlled address, and (2) bypass the Control Flow Guard check.]

A week has passed since my last post so it seems about time to release another 0patch into the vacuum between regular Microsoft Update Tuesdays. It's been an interesting week because our 0patch platform (with open beta in progress) got an infusion of new users providing a lot of useful feedback.

This time I present you with a patch for IE11, providing protection for a vulnerability more severe than the previous one. One that is said to potentially allow for remote code execution. Again I based my analysis on a bug report provided by Google Project Zero, who automatically derestricted it after 90 days deadline. This time Ivan Fratric holds the credit.

The PoC (which can be extracted from the top of Ivan's report) is a short HTML file in which - upon opening in IE11- JavaScript dynamically reformats StyleSheet properties of an HTML table in a way that causes type confusion, ending in a crash. Inspecting the crash with Application Verifier enabled and WinDbg attached I got the same results as reported:

(430.1a4c): Access violation - code c0000005 (!!! second chance !!!)
MSHTML!Layout::MultiColumnBoxBuilder::HandleColumnBreakOnColumnSpanningElement+0xa4:
000007fe`ddeeba17 48833800        cmp     qword ptr [rax],0 ds:00000078`00000070=????????????????


I executed !heap -p -a @rbp to acquire the call-stack of corrupt object's creation. It showed that the illegal rax address originated in 

Array<int>::Create

There was no indication of a typical memory corruption such as a buffer overflow or a use-after-free directly related to the crash which could be analyzed and patched in an almost standard way (see our previous blog posts). I therefore concluded that a less deterministic and more tedious analysis was necessary to crack this bug. What was needed was a set of probes derived from the PoC that separate a correct execution flow from an illegal one. Those probes could then be traced in WinDbg and trace-dumps compared. What I found was that
  • the boom()call causes a crash only if triggered by an event separate from page load, e.g., a click or a timer event,
  • instead of "aaaaaaaaaaaaaaa", mediaText can be set to a legitimate value such as print, handheld, projection, etc. and the browser will still crash and
  • statically defined media (inside a css definition) does not produce a crash.
Attaching to the probes I traced the life-cycle of the said Array<int> down to the crash as well as the differences between various situations where mediaText and th1.align are set. In my limited time I could compare several combinations of execution flow traces of said probes, but ended up with no solid understanding of where the illegal parsing behavior kicks in. Time was not on my side so I chose to resort to an easier solution: functionality amputation. If your fingernail causes you to stumble, cut it off ...

Based on my findings above this means disablement of mediaText setter. But first let's see what mediaText is about. According to W3C it is responsible for getting and setting a collection of media queries. By using media queries, presentations can be tailored to a specific range of output devices without changing the content itself. So basically we're about to interfere with web page layout. If you look at the examples given by W3C, all of them use static media definitions which the patch I'm about to propose does not affect because it will disable only functions exposed to JavaScript that the published PoC relies on. Whether it is worth protecting against a potential remote execution threat in exchange for possible page styling errors is for you to choose (0patch Agent allows disabling of the patch if you cannot live with it). Now let's see how the patch works.

Below is the content of my 0patch source file.  It defines two patchlets for module mshtml.dll enclosed between patchlet_start - patchlet_end directives. Patchlet locations were obtained by tracking every possible setter on a CSSMediaList object accessible from JavaScript. I found two such locations:
  • media.mediaText setter that maps to CFastDOM::CMediaList::Trampoline_Set_mediaText 
  • media.appendMedium method that maps to CFastDOM::CMediaList::Trampoline_appendMedium
I patched both setters so that their function bodies are skipped entirely (using the JUMPOVERBYTES directive) and their result is set to SUCCESS via xor rax,rax.

;target OS: Windows 7 64bit
;

RUN_CMD C:\Program Files\Internet Explorer\iexplore.exe C:\0patch\Patches\CVE-2017-0037\poc.html
MODULE_PATH "C:\Windows\System32\mshtml.dll"
PATCH_ID 265
PATCH_FORMAT_VER 2
VULN_ID 2140
PLATFORM win64


patchlet_start
 PATCHLET_ID 1
 PATCHLET_TYPE 2

 PATCHLET_OFFSET 0x00f79cc0
 JUMPOVERBYTES 211;
 
 code_start
   xor rax,rax
; return success
 code_end
patchlet_end

patchlet_start
 PATCHLET_ID 2
 PATCHLET_TYPE 2

 PATCHLET_OFFSET 0x00fa3f80
 JUMPOVERBYTES 197
 
 code_start
   xor rax,rax ; return success
 code_end
patchlet_end

After compiling this .0pp file with 0patch Builder, the patch gets applied and IE11 browser survives the PoC without a crash.

If you have 0patch Agent installed, patches ZP-265 through ZP-268 should already be present on your machine. If not, you can download a free copy of 0patch Agent to protect yourself from exploits against the presented issue while waiting for Microsoft's official fix. Note that when Microsoft’s update fixes this issue, it will replace the vulnerable mshtml.dll and our patch will automatically stop getting applied as it is strictly tied to the vulnerable version of the DLL. We have deployed this patch for the following platforms: Windows 10 64bit, Windows 8.1 64bit, Windows 7 64bit and Windows 7 32bit.

Patching this 0day was a good opportunity to demonstrate how patching process in our 0patch Team works. We rarely release patches that would replace official vendor fixes. In general we aim to bridge the gap between a release of vendor update and the time this update gets installed on vulnerable machines. Note that in case of the presented patch we're not talking only about 5 days until the next Patch Tuesday -  for many companies the gap is caused by weeks or months of testing before official update batch can be applied to their networks.

So we rather release a simple temporary patch that blocks an attacker than try to create a perfect patch. A much thorougher and better analysis of this bug can and will be done by Microsoft. Browsers are certainly among the most complex applications so with my black box analysis tools and a limited time-frame I don't fool myself that I could get to the bottom of all the weird things an HTML apparatus does. On the other hand Microsoft developers have the source code, the right tools and knowledge to properly fix this bug and probably wont even blink while getting it done.

Feel free to use 0patch Agent with this patch to protect yourself from attacks against CVE-2017-0037 until Microsoft provides an official fix (which we absolutely recommend you apply). Just remember that we're still in beta ;-)

Tuesday, February 28, 2017

0patching a 0-day: Windows gdi32.dll memory disclosure (CVE-2017-0038)

My first 0-day fixed (and I am not even a Microsoft developer)

By Luka Treiber, 0patch Team.

I've been fishing around the web for my next target to patch when something got caught into my net. Then along came Mitja and asked:
M:What's the catch?
-Well, zero...
M:Oh, that's a shame...
-Yeah, but not if it's a zero-day

As you've probably noticed, the last Patch Tuesday didn't make it. Consequently a number of 0-days are getting published, with CVE-2017-0038 being the first one on the list. But don't worry, every cloud has a silver lining. I had some free time last week to look into the matter and as a result I can give you the very first 0patch for a 0-day.

CVE-2017-0038 is a bug in EMF image format parsing logic that does not adequately check image dimensions specified in the image file being parsed against the amount of pixels provided by that file. If image dimensions are large enough the parser is tricked into reading memory contents beyond the memory-mapped EMF file being parsed. An attacker could use this vulnerability to steal sensitive data that an application holds in memory or as an aid in other exploits when ASLR needs to be defeated.

I have to kindly thank Mateusz Jurczyk of Google Project Zero for a terse and accurate report that allowed me to quickly grasp what the bug was about and jump on to 0patching it.

Mateusz's PoC worked as advertised - by launching an instance of IE 11 and dropping poc.emf onto it, this is the result I got:




The image had to be zoomed in to the max in order to see the intimidating heap data leaking through the colorful pixels. And it did leak consistently: reloading the PoC resulted in a different image on each reload.

In order to see the pixel values I put poc.emf onto an HTML canvas and printed the pixel values with JavaScript. Diffing the results after consecutive PoC reloads showed that the only pixel that didn't change was the one in the lower left corner (if you look really closely at the screenshot above you will find a red smudge right there).

In other words:

FF 33 33 FF

This is consistent with the report (one only needs to look closely enough). So the only pixel that originates from the actual data provided by the EMF file is that one (represented by the 4 bytes) - everything else is heap data read from out of bounds of the image pixel data.

Now let's go on to patching. Before we do that we need to understand where the vulnerable code is. Luckily the next thing that the report conveniently reveals is the name of the vulnerable function MRSETDIBITSTODEVICE::bPlay. This is important because the PoC produces no crash or exception that could be caught by a debugger for an in-depth analysis. With that piece of info in hand we can attach WinDbg to iexplore.exe and set a breakpoint

bp MRSETDIBITSTODEVICE::bPlay

According to the report this is where all the trouble is. It says cbBitsSrc is not checked against "the expected number of bitmap bytes" - the number which is calculated from cxSrc and cySrc image dimensions.

Here we need a little help from MSDN:
  • cxSrc
    Width of the source rectangle, in logical units.

  • cySrc
    Height of the source rectangle, in logical units.

  • cbBitsSrc
    Size of source bitmap bits.

After feeding WinDbg with symbols for EMRSETDIBITSTODEVICE type (explanation follows later) the explanation from the report finally got clear.



When processing the PoC EMF file, the EMRSETDIBITSTODEVICE structure (detailed in the lower right pane of the screenshot above) passed to the MRSETDIBITSTODEVICE::Play function as the first argument (rcx register that gets stored to rbx, marked in blue) contains cbBitsSrc set to 4, which does not match the 0x10 * 0x10 image dimensions defined by cxSrc and cySrc (these amount to 256 pixels or 1024 bytes).

So to fix the flaw a check has to be added before any data gets stolen. What principally needs to be done is adding a check whether cbBitsSrc is smaller than cxSrc * cySrc * 4 before any image pixels get copied around. An appropriate spot seems to be right before the first series of checks that validate the EMRSETDIBITSTODEVICE attributes (see cmp - jg pairs in the above code screenshot that end with a jmp to function exit in case any of the checks fail). However, selecting the exact patch location is not just about where to logically fit the modifications that we want to apply. The way patching works is that a jump is made from original to patch code and then back. At the patch location in original code a jmp instruction is written (consuming 5 bytes of original instruction space) that redirects execution to a memory block designated for patch instructions. The original instructions that were replaced by the jmp instruction are relocated to the end of that patch code block followed by a final jmp instruction directing execution back to original code right after the patch location. So there are some additional requirements that need to be met:
  • instructions at the patch location need to be relocatable (e.g., no short jumps);
  • at the patch location there must be either a single instruction or several instructions that belong to the same execution flow (cross-references must not point anywhere in-between them).
With this in mind I selected the exact patch location. In order to write as little patch code as possible I set the patch location at the first branch instruction that jumps to the function exit (avoiding the processing of image data) so I could piggy-back on it. On the code screenshot above, the patch location is marked in red while the repurposed jump instruction glows pink as a piggy. The result of pvClientObjGet call is checked against 0 at the patch location, followed by jne in order to jump to function exit (if rax is 0). The same jne that serves this logic can help our patch code exit the function: we only need to set rax to 0 if cbBitsSrc is smaller than cxSrc * cySrc * 4. 

It might seem desirable to select 000007fe`feeae3b8 as patch location at the first glance, but test rax,rax takes only 3 bytes so patching would also eat into the jne (which is not relocatable) because of the said 5-byte requirement. At the currently selected location, however, patching affects two 3-byte instructions - mov rsi,rax and test rax,rax - which are both relocatable.

Having selected the patch location we can finally write the actual patch. Below is the content of a .0pp patch file ready to be compiled with 0patch Builder that is included in 0patch Agent for Developers - usage of which we already discussed in a previous post.

At the beginning of the code_start section there is the cxSrc * cySrc * 4 calculation that gets stored in rcx. Both multiplications are followed by an overflow check so we don't end up with a product that seems within bounds but was produced by overlong factors. In case invalid image dimensions are detected, a call to a special function of our 0patch Agent is made in order to display an "Exploit Blocked" popup, and most importantly the rax register is set to 0 so that the following test rax,rax instruction can set the jump condition for the pink jne (resulting in the function exiting).

;target platform: Windows 7 x64
;

RUN_CMD C:\Program Files\Internet Explorer\iexplore.exe C:\0patch\Patches\ZP-gdi32\poc.emf

MODULE_PATH "C:\Windows\System32\gdi32.dll"
PATCH_ID 259
PATCH_FORMAT_VER 2
VULN_ID 2135
PLATFORM win64

patchlet_start
 PATCHLET_ID 1
 PATCHLET_TYPE 2
 PATCHLET_OFFSET 0x0004e3b5

 ;NOTE: We checked that rcx is free to use.
 ; We don't care if rsi gets spoiled by block_it because in that case
 ; it will not be used by anyone any more


 code_start

   imul ecx, dword[rbx+28h], 04h ; cxSrc * 4 (each pixel is represented by 4 bytes)
   jc block_it ; if overflow
   imul ecx, dword[rbx+2ch] ; * cySrc
   jc block_it ; if overflow
   cmp ecx,dword[rbx+3ch] ; cbBitsSrc < cxSrc * cySrc * 4
   jbe skip
  block_it:
   call PIT_ExploitBlocked ; show "Exploit Blocked" popup

   xor rax,rax ; setting jump condition for the original jne after the patch

  skip:

 code_end
patchlet_end

By the way, the EMRSETDIBITSTODEVICE structure member offsets relative to rbx were obtained by dumping type structure using WinDbg's dt command:

0:034> dt symbollib!EMRSETDIBITSTODEVICE
       +0x000 emr              : tagEMR
       +0x008 rclBounds        : _RECTL
       +0x018 xDest            : Int4B
       +0x01c yDest            : Int4B
       +0x020 xSrc             : Int4B
       +0x024 ySrc             : Int4B
       +0x028 cxSrc            : Int4B
       +0x02c cySrc            : Int4B
       +0x030 offBmiSrc        : Uint4B
       +0x034 cbBmiSrc         : Uint4B
       +0x038 offBitsSrc       : Uint4B
       +0x03c cbBitsSrc        : Uint4B
       +0x040 iUsageSrc        : Uint4B
       +0x044 iStartScan       : Uint4B
       +0x048 cScans           : Uint4B

But since the type information is not available in WinDbg by just loading symbols from Microsoft's Symbol Server, the following workaround was needed. I compiled a bare-bone DLL project with only EMRSETDIBITSTODEVICE x; instance declaration as custom source. Then just before launching iexplore.exe I added the DLL to the AppInit_DLLs registry value so it got loaded into the process (thanks to this trick).

After compiling this .0pp file with 0patch Builder, the patch gets applied and instead of the rainbow image an empty image is displayed in the browser and an "Exploit Blocked" popup shows up.

Here is a video I captured that summarizes the described process.


So this is my first 0-day fixed. While not the most severe issue, I get shivers thinking that instead of the rainbow image, a malicious page could steal credentials to my online banking account or grab a photo of me after last night's party from my browser's memory.

If you have 0patch Agent installed, patches ZP-258 through ZP-264 should already be present on your machine. If not, you can download a free copy of 0patch Agent to protect yourself from exploits against the presented issue while waiting for Microsoft's official fix. Note that when Microsoft’s update fixes this issue, it will replace the vulnerable gdi32.dll and our patch will automatically stop getting applied as it is strictly tied to the vulnerable version of the DLL. We have deployed this patch for the following platforms: Windows 10 64bit, Windows 8.1 64bit, Windows 7 64bit and Windows 7 32bit.

If you would like to write patches like this yourself, do not hesitate to download our 0patch Agent for Developers and give it a try (we made the .0pp files available for download so you can build them yourself). We'll also happily accept any feedback.

Now onward to writing the next 0-day 0patch.