Thursday, February 21, 2019

No Source Code For a 14-Year Old Vulnerable DLL? No Problem. (CVE-2018-20250)

Why It Makes Sense To Micropatch a Vulnerability When Official Fix Is Available

by Mitja Kolsek, the 0patch Team

Yesterday, Checkpoint published a detailed vulnerability report about a serious vulnerability in WinRAR (reportedly used by 500+ million users) which allowed a malicious archive, when extracted, to create an arbitrary file in a chosen location on user's computer. This includes,for instance, user's Startup folder where said file would get executed when the user logged in to Windows again.
Nadav Grossman, the researcher who found the vulnerability and wrote the report, nicely described    
the flow of his analysis, including the problems he stumbled into, and tools he used to analyze the vulnerability. Anyone interested in analyzing vulnerabilities, or in details of this particular one, is advised to read his report.

The vulnerability (CVE-2018-20250) was present in WinRAR's extracting of ACE archives, whereby said extracting was actually done using a dynamic library UNACEV2.DLL written by e-merge GmbH, maintainer of WinACE software. This DLL, interestingly, hasn't changed since 2005 - which actually attracted Nadav's attention.

At the time the report was published, WinRAR producer RARLAB was already offering a fixed version of  WinRAR (5.70 beta 1) on their download page, and their fix was very simple: being unable to fix the vulnerability, they dropped support for ACE format. (You might remember Microsoft doing something similar with the 17-year old Equation Editor last year.)

To Micropatch Or Not To Micropatch?

For us at 0patch, a vulnerability like this is inherently interesting: it allows for a remote code execution, it potentially affects millions of users, and the product doesn't auto-update so it is likely to be present for a long time. And while we've micropatched a bunch of 0days lately, 0patch is primarily meant to bridge the security update gap by fixing vulnerabilities that may already have an official fix.

In deciding whether to micropatch this one, we came up with the following supporting arguments:

  1. This vulnerability is a perfect candidate for malicious phishing campaigns. "Please review the attached purchase order PO.rar."
  2. WinRAR is a really widely used product. Maybe it doesn't actually have 500 million users but still.
  3. No auto-update means that most users will never update it. In fact, unless one has actually read about this vulnerability (surely most users haven't) and feels threatened by it, why would one take the time to update?
  4. Some users may actually need the ACE format support. Granted, there is still WinACE, but in contrast to WinRAR, its maintainer seems long gone.
  5. From defensive perspective, blocking exploits of this vulnerability is not as simple as rejecting files with .ace extension, as a malicious file can also be renamed to .rar or .zip (or likely any other supported extension) as long as it's extracted with WinRAR. The user can't even tell that a ZIP file is actually an ACE file.
  6. Some of 0patch users are probably also users of WinRAR. By creating a micropatch, we will protect them without them even being aware of this WinRAR vulnerability, or the fact that we micropatched it. (Letting users not worry about patches and not disturbing them with patching is a core concept of 0patch.)
  7. Admins with multiple 0patch Agents on users' computers would like the fact that whichever version of WinRAR, even if old and vulnerable, their users use or "temporarily" install, they will be protected against this issue.
  8. Other products than WinRAR may be using this particular version of UNACEV2.DLL, and our micropatch would protected from a similar attack too, without us even knowing what these products are.

As you suspected, we decided to go ahead.


Fortunately, Nadav's analysis provided most of the details we needed (big thanks, Nadav!) and a potential solution was fairly obvious. If you look at Figure 15 in his report and the accompanying text, you'll see that the exploit causes the execution through a branch that allows the malicious file path to remain a relative path by prepending it with... well, an empty string. So the idea was to always force the execution through the other branch, which prepends the malicious path with the target directory.

This way, instead of allowing malicious paths like:




to pass unmodified, they would become (when extracted to C:\temp):




These are both invalid paths and an application can't create a file using them.

One question remained open, however: Do any legitimate use cases need the code branch we were planning to "amputate"? Such use case would include intentionally extracting a file to a location specified with full path on user's computer; which would be considered a vulnerability of equal severity as the issue we're fixing here. So we concluded that removing this branch is an acceptable approach, and wrote this single-instruction micropatch:

MODULE_PATH "..\AffectedModules\UNACEV2.DLL_2.6.0.0_32bit\UNACEV2.DLL"
VULN_ID 4852


 JUMPOVERBYTES 10 ; We remove mov and call


  mov eax, 0 ; making sure to proceed via the "absolute path" branch,
             ; not the "empty string" branch



When the micropatch is applied, extracting a malicious ACE archive results in a number of warnings as shows below, and files aren't extracted.

Here's a video showing our micropatch in action:


By micropatching this vulnerability in a 14-year old closed-source DLL we demonstrated how suitable in-memory micropatching is for quickly fixing a critical vulnerability, even when fixing it in source code is literally impossible.

One nice side-effect of micropatching a third-party DLL is that while our micropatch was targeted at WinRAR, it actually protects all products using this particular version of UNACEV2.DLL from a similar attack. The DLL will be patched no matter who loads it. If you come across one, do let us know!

As always, if you have our Agent installed and registered, this micropatch is already on your computer - and applied to WinRAR whenever it loads UNACEV2.DLL (enable popups via 0patch Console to see when that happens). Otherwise, you can register a free 0patch account and install 0patch Agent to get this micropatch applied to your WinRAR.

Nevertheless - if you don't need support for ACE format in WinRAR, we recommend you update WinRAR to a fixed version (currently 5.70 beta 1). There may be other vulnerabilities there in UNACEV2.DLL which are more likely to be found now that it's been put in the spotlight.



Monday, February 11, 2019

Sorry, Adobe Reader, We're Not Letting You Phone Home Without User's Consent (CVE-2019-7089)

by Mitja Kolsek, the 0patch Team

[Update 2/12/2019: Just one day after we had issued this micropatch, Adobe released an update of Adobe Reader DC that fixed the vulnerability. We strongly recommend all users of Adobe Reader to apply Adobe's update, at which point our micropatch will automatically no longer get applied.]

Today we'll look at a fairly simple vulnerability in Adobe Reader DC that allows a PDF document automatically send an SMB request to attacker's server as soon as the document is opened. The vulnerability was published by Alex Inführ along with a proof-of-concept in a detailed report on Alex's blog and hasn't been patched at the time of this writing. [Update 2/12/2019: the vulnerability was subsequently assigned CVE ID CVE-2019-7089.]

This vulnerability, similar to CVE-2018-4993, the so-called Bad-PDF reported by CheckPoint in April last year, allows a remote attacker to steal user's NTLM hash included in the SMB request. It also allows a document to "phone home", i.e., to let the sender know that the user has viewed the document. Obviously, neither of these is desirable.

At the time of this writing, the latest version of Adobe Reader DC, 2019.010.20069, is affected but older versions are likely in the same boat too.


To understand the problem, let's start with the above-mentioned Bad-PDF (CVE-2018-4993). The malicious PDF included a certain element that triggered automatic loading of another PDF from a remote share. Until Adobe Reader got patched, this happened without the user noticing anything, or being able to prevent it.

Adobe patched this issue by adding a security warning that was shown to the user before making the request to a remote share:

Security warning added to fix the Bad-PDF issue.

This warning allowed the user to decide whether to allow the potentially malicious document to "phone home" or not.

Now on to the issue at hand: it is functionally identical (for attacker), just in a different place. While Bad-PDF used an /F entry to load a remote file, this issue exploits loading a remote XML style sheet via SMB. Interestingly, if the document tries to do so via HTTP, there is a security warning there:

Attempting to load a remote style sheet via HTTP triggers a warning.

However, when using a UNC path (the type of path that denotes a resource in a shared folder), the loading occurs without a warning

The Micropatch

The Reader already implies the correct behavior by showing a security warning on loading a remote style sheet via HTTP, so we decided to add our own security warning for loading style sheets via UNC as well.

We started by locating the point where the HTTP-loading and UNC-loading execution paths diverge, and patch-in a warning for UNC paths. Finding said divergence point was relatively easy using Process Monitor: we caught CreateFile events on both HTTP and UNC loads, then compared their call stacks to see where the two execution paths said good-bye to each other. This turned out to be in function sub_208B3C53, the relevant code block of which is shown here:

Both HTTP- and UNC-based style sheet loads reach the above code block, whereby an HTTP-based load never returns from the first call marked in red (it triggers an exception that Reader handles somewhere else), and a UNC load is implemented inside the second call marked in red.

As you can see from the comments in the code, we found where the file path resides before the second call (this required a little digging on the stack at that point). We verified it by changing said path on-the-fly in debugger to make sure the path-loading code actually uses that, and then we were ready to inject our patch.

There exists a handy Windows function called PathIsUNCA, which is already being used by Reader elsewhere to check whether a path is a UNC path (the "A" at the end denotes an ASCII path in contrast to a wide-char path). So we decided to first call this function to see if we have a UNC path, and then if we do, issue a prompt to the user. To do the latter, we used another well-known Windows function MessageBoxA. Based on user's response, we would then allow the UNC path to be loaded or not. The only thing to decide at this point was how to implement the "not", i.e., how to prevent the UNC path from loading if the user decided not to trust the document.

In such cases, we always want to keep things simple and minimize possible surprises. We therefore decided to simply empty the path string by putting a zero at its beginning, resulting in Reader trying to load an empty path. It does complain that it can't load it though but the exploit is blocked and, frankly, we're fairly confident that loading style sheets form UNC paths doesn't work at all because as much as we tried, Reader always encountered an error. So maybe UNC style sheets are not a supported use case at all but they did turn out to be a vulnerability.

Here is the source code of our micropatch:

MODULE_PATH "..\AffectedModules\AcroForm.api_19.10.20064.48846_32bit\AcroForm.api"
VULN_ID 4694


 PATCHLET_OFFSET 0x000b3f6b ; Injecting before the call towards loading
                            ; a non-HTTP URL
 PIT Shlwapi.dll!PathIsUNCA,User32.dll!MessageBoxA


  push ecx ; save ecx so we don't corrupt it

  mov eax, dword [eax+10h] ; at this point, the address of path
                           ; is at [eax+10h]+4
  add eax, 4
  push eax
  push eax ; we push the address of path twice as we may need it

           ; in remediation too
  call PIT_PathIsUNCA ; is it a UNC path?
  test eax, eax
  jz skip ; not a UNC path - skip the warning dialog

  push 0x00000134 ; uType = MB_YESNO | MB_ICONEXCLAMATION | MB_DEFBUTTON2
  call get_lpCaption
  db "Security Warning",0
  call get_lpText
  db "This document is trying to access a file on the network. If you trust this document, choose Yes. If you do not trust this document, choose No.",0
  push 0 ; hWnd = NULL
  call PIT_MessageBoxA
  cmp eax, 6 ; Did user click "Yes"?
  je skip ; if so, skip remediation

  ; Remediation: we'll simply delete the entire URL string by putting
  ; a 0 at the beginning
  pop eax ; pop the previously pushed path address
  mov byte [eax], 0 ; put a 0 at the start of path
  push eax ; we need to re-push something because we have a pop in the epilogue

  pop eax ; pop the additional address of path 
  pop ecx ; restore original ecx and continue to execute the call
          ; towards loading the provided URL



With this micropatch in place, opening the malicious document results in the following warning before a request is made to the remote server:

The security dialog that was micropatched into Adobe Reader.

If the user selects "Yes", the remote style sheet is loaded (whereby the SMB request delivers your NTLM hash to the remote server), and if they select "No", Reader complains about not being able to load the style sheet from and empty path. Done.

We asked Alex, the security researcher who found this issue, to test our micropatch and he was kind enough to confirm its efficiency against this attack. (Thanks, Alex, for your help! We encourage all security researchers to collaborate on creating and testing micropatches.)

For the visual types among you, here is a video of our micropatch in action:


As always, if you have our Agent installed and registered, this micropatch is already on your computer - and applied to Adobe Reader whenever it loads AcroForm.api (that only happens when certain documents are opened). Otherwise, you can register a free 0patch account and install 0patch Agent to get this micropatch applied to your Reader.

Note that Adobe might issue an official fix for this issue tomorrow as they release their monthly Reader update, but if not, we'll quickly port the micropatch to the new Reader version to keep the vulnerability patched on your computers. [Update 2/12/2019: Adobe did issue an official fix the next day.]



Tuesday, January 22, 2019

One... Two... Three Micropatches For Three Windows 0days

A Short Micropatching Trilogy

by Mitja Kolsek, the 0patch Team

While we're busy ironing out the wrinkles before 0patch finally exits its adolescence (i.e., Beta) and becomes a fully responsible adult able to pay for its own rent, we did find some time to produce... not one, ... not two, ... but three 0day micropatches in the past few days. That's right, at this very moment you can get three 0days on your Windows computer micropatched for free! All you have to do is register a free 0patch account and install 0patch Agent.

Let's quickly go through each of these 0days and see what they allow attackers to do, and how we micropatched them. Then we can return to the wrinkle-ironing mode and bring you the best patching experience that we possibly can.

0day #1: the "angrypolarbearbug"

This 0day, dubbed "angrypolarberbug" by its author SandboxEscaper who published it last month, allows a local unprivileged process to get any chosen file on the system overwritten with the content of a Windows Error Reporting XML file. The attacker has very little control over the content of this XML file so the demonstration provided by SandboxEscaper was a local denial of service by corrupting a critical system file pci.sys, which prevents the system from booting. One can imagine potentially finding some other file to overwrite that would lead to execution of attacker's code under higher privileges such as SYSTEM or Administrator - but to our knowledge, such example has not been published.

The crux of this vulnerability is in the fact that the C:\ProgramData\Microsoft\Windows\WER\Temp\ folder, where the Windows Error Reporting Service is creating a temporary XML file, has inheritable permissions that include read, write and delete access for Authenticated Users (which includes the local attacker). This means that whenever anyone creates a new file there without specifying its permissions, any process on the system, including a low-privileged malicious process, will be able to replace that file with another file. And that's what SandboxEscaper's proof-of-concept does: it waits for the XML file to appear, and then quickly replaces it with a hard link to the chosen target file (e.g., pci.sys). When Windows Error Reporting Service subsequently re-opens this XML file for writing, it actually opens the linked-to file, and writes to that file.

Our micropatch makes a small change: when Windows Error Reporting Service creates the XML file, it now specifies permissions that are otherwise exactly the same as before, except that Authenticated Users don't have delete permissions on it. This keeps error reporting working while preventing the exploit from deleting the XML file (and thus also from creating a hard link in its place).

We currently have this micropatch for fully updated 64-bit Windows 10 version 1803. (Contact to express your interest in porting to other versions.) Note that this issue doesn't seem to affect Windows 7, where error reporting works a bit differently.

You can see this micropatch in action in the following video.

And here's the source code for this micropatch.

;Micropatch for wer.dll version 10.17134.471
;How it works:
; a vulnerable call CreateFileW responsible for creating a temporary report XML file
; which inherits loose C:\ProgramData\Microsoft\Windows\WER\Temp\ permissions is replaced by
; a call to ConvertStringSecurityDescriptorToSecurityDescriptor which creates a new security
; descriptor from ACE string that gets supplied to a new CreateFileW call.
; The new security descriptor has no DELETE permissions for AuthenticatedUsers group
; on report XML so a regular user can no longer change it to a hard link.

MODULE_PATH "..\AffectedModules\wer.dll_10.17134.471_64bit\wer.dll"
VULN_ID 4657

PIT kernel32.dll!CreateFileW,advapi32.dll!ConvertStringSecurityDescriptorToSecurityDescriptorA,kernel32.dll!LocalFree


  mov qword [rsp+10h], r8 ; dwShareMode
  mov qword [rsp+8h], rdi ; storing a global variable
  mov qword [rsp], rcx    ; lpFileName

  call arg0_StringSecurityDescriptor

  ; args for ConvertStringSecurityDescriptorToSecurityDescriptor
  ; we changed (A;;0x13019f;;;AU) to (A;;GRSD;;;AU) - meaning

  ; AuthenticatedUsers can Read and Delete only
  db "D:(A;;FA;;;BA)(A;;GRGW;;;AU)(A;;0x13019f;;;SU)(A;;0x13019f;;;LS)(A;;0x13019f;;;NS)(A;;0x13019f;;;WR)(A;;0x13019f;;;AC)(A;;0x13019f;;;S-1-15-2-2)",0
  pop rcx ; rcx=arg0_StringSecurityDescriptor
  mov rdx, 01h ; arg1: StringSDRevision=SDDL_REVISION_1
  ;arg2: this arg is part of SECURITY_ATTRIBUTES struct so we have to create this first

                   ; sa requires 18h of space
  sub rsp, 20h     ; but we're allocating 8 more than required nLength to keep stack alignment
  lea r8, [rsp+8h] ;arg2: SecurityDescriptor=&sa.lpSecurityDescriptor
  ;init sa:
  mov dword [rsp],18h    ;sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  mov dword [rsp+10h],1h ;sa.bInheritHandle=FALSE
  xor r9d,r9d ; SecurityDescriptorSize=NULL
  sub rsp, 20h ; allocate homespace

  call PIT_ConvertStringSecurityDescriptorToSecurityDescriptorA
  ;copy CreateFileW args 5,6 and 7 to a new stack frame
  mov rax, [rsp+60h] ; dwCreationDisposition
  mov qword [rsp],rax
  mov rax, [rsp+68h] ; dwFlagsAndAttributes
  mov qword [rsp+8h],rax
  mov rax, [rsp+70h] ; hTemplateFile
  mov qword [rsp+10h],rax
  ;obtain CreateFileW args 1,2,3,4
  mov rcx, [rsp+40h] ; lpFileName
  mov edx, 0C0000000h ; dwDesiredAccess
  mov r8, [rsp+50h] ; dwShareMode
  lea r9,[rsp+20h] ;lpSecurityAttributes
  sub rsp, 20h ; alloc homespace
  call PIT_CreateFileW
  mov [rsp+28h],rax ; store result

  ;free the security descriptor:
  mov rcx,[rsp+48h] ; sa.lpSecurityDescriptor
  call PIT_LocalFree ;LocalFree(sa.lpSecurityDescriptor)
  mov rax,[rsp+28h] ;restore result
  mov rdi,[rsp+68h] ;restore the global variable
  add rsp, 60h      ;restore stack


0day #2: the "readfile" (subsequently assigned

[Update 2/14/2019: Microsoft has fixed this issue with February 2019 Updates and assigned it CVE-2019-0636.]

The "readfile" 0day was also published by SandboxEscaper last month. This one allows an unprivileged process running on a Windows computer to obtain the content of arbitrary file, even if permissions on such file don't allow it read access. The proof-of-concept demonstrates reading the content of another user's desktop.ini file from user's desktop, but the author suggests reading Office history files (and other index or history files with known paths) could reveal further paths to interesting files belonging to other users.

The flaw lies in Windows Installer, more specifically in its advertisement functionality, which can be triggered using the MsiAdvertiseProduct function. We're not going to dive into details here; suffice it to say that when a product (i.e., its MSI installation package) is advertised, Windows Installer (running as SYSTEM) takes this MSI file, parses it, then creates a temporary MSI file in C:\Windows\Installer folder and copies the content of the original MSI file in it. (It does much more with it then but that's irrelevant for this issue.) SandboxEscaper noticed that the original MSI file is opened twice, and that a symbolic link can be made that points to a regular MSI file on the first open, but points to some other file on the second open - which results in the content of the latter file being copied to the temporary MSI file. Due to file permissions on the temporary MSI file, which allow Everyone read access, an attacker can thus trick the Windows Installer Service to copy the content of arbitrary file to the temporary MSI file, and then read that file to obtain said content.

Micropatching this issue required us to familiarize ourselves with the inner working of Windows Installer. It turned out that the function copying the source MSI file into the temporary MSI file already supports setting two different permission sets on the temporary file: (1) inherited permissions, and (2) permissions of the source MSI file. Its behavior in advertising a product uses the inherited permissions (which allow the attacker to read the file), so we used four strategically-placed patchlets to force it to use permissions of the source MSI file instead. With the micropatch in place, product advertisement still works as before, but since the permissions on the temporary MSI file are the same as on the file being copied, the attacker gains nothing from this process.

We currently have this micropatch for fully updated 64-bit Windows 10 version 1803 and fully updated 64-bit Windows 7. (Contact to express your interest in porting to other versions.)

You can see this micropatch in action in the following video.

And here's the source code for this micropatch; four patchlets, each with a single instruction.

MODULE_PATH "..\AffectedModules\msi.dll_5.0.17134.228_64bit.dll\msi.dll"
; Windows 10 version 1803
VULN_ID 4658


 PATCHLET_OFFSET 0x002edb76 ; Injecting after eax is set to FlagsAndAttributes

                            ; in CMsiFileCopy::OpenDestination


   or r12d, 0x8000 ; we set the 15th bit of FlagsAndAttributes,
                   ; which will cause the execution to flow towards using

                   ; source file's ACL




 PATCHLET_OFFSET 0x002edbe9 ; Overwriting code that checks value #12 in 

                            ; MSI record, and setting eax to 1


   mov eax, 1 ; we set eax to 1 to simulate IsNull returning false




 PATCHLET_OFFSET 0x002edd0e ; Overwriting code that checks value #12 in

                            ; MSI record, and setting eax to 1


   mov eax, 1 ; we set eax to 1 to simulate IsNull returning false




 PATCHLET_OFFSET 0x002edd61 ; Overwriting code that checks value #12 in 

                            ; MSI record, and setting eax to 1


   mov eax, 1 ; we set eax to 1 to simulate IsNull returning false



0day #3: the "Windows Contacts arbitrary code execution"

This 0day was published by a ZDI researcher John Page after Microsoft had exceeded ZDI's 90-day window for fixing a reported issue. The issue was initially reported as related to VCF files (which are by default associated with the Windows Contacts application) but Page subsequently added that CONTACT files (also by default associated with Windows Contacts) can be used to achieve the same.

The issue is in the fact that almost any string provided via a VCF or CONTACT file in the web site URL or email value (yes, we figured this one out ourselves :) ends up being used as an argument to a ShellExecute call. While ShellExecute is a handy function for opening URLs in user's default browser, its problem is that before doing that, it tries to "launch" the provided string on the local computer; to illustrate, provided with "", ShellExecute would first attempt to locate and launch a local executable called, and only failing that, it would open in your browser. This behavior has produced many a vulnerability before (see this article for some examples) and will undoubtedly continue to bless us with more in the future. To exploit this issue, the attacker must get the user to open a malicious VCF or CONTACT file and click on the displayed web site or email link, which launches attacker's executable that must also be present on user's computer or a network share.

We analyzed what happens when the web site or email link is clicked, which led us to a SafeExecute function in wab32.dll. This function does some parsing of the URL to accommodate mshelp:// URLs, and then calls ShellExecute. We simply added some logic before this call to make sure that if the URL doesn't start with "mailto:", "http://" or "https://", it gets prepended with "http://" to prevent any possible launching of local executables. We have initially considered adding sanitization in the code that reads the file but then discovered that the code displaying the link is prone to, yes, HTML injection - which made any sanitization too complex and potentially bypassable.

We currently have this micropatch for fully updated 64-bit Windows 10 version 1803 and fully updated 64-bit Windows 7. (Contact to express your interest in porting to other versions.)

You can see this micropatch in action in the following video. The video also nicely demonstrates how a micropatch can be applied to a running process: we enable the micropatch while Windows Contacts is displaying the malicious contact card, and the result of clicking on the link gets changed.

And here's the source code for this micropatch.

;Micropatch for wab32.dll version 6.1.7601.17699
;How it works:
; in SafeExecute an unsanitized pszUrl - a user-controlled parameter is passed to ShellExecute.
; This patch adds a series of checks for valid pszUrl prefixes and eventually,
; if no valid prefix is found, adds a http:// prefix to pszUrl.

MODULE_PATH "..\AffectedModules\wab32.dll_6.1.7601.17699\wab32.dll"
VULN_ID 4656

PIT SHLWAPI.dll!StrCmpNICW,msvcrt.dll!memmove


  ;store registers:
  push rsi
  push rcx
  push rdx
  push r8
  push r8                      ; extra space for prefix variable
  push rax                     ; store pszUrl
  ;check lpFile for valid prefixes:
  call mailto
  db __utf16__('mailto:'),0
  pop rcx                      ; pszStr1 = "mailto:"
  mov rdx, rax                 ; pszStr2 = pszUrl
  mov r8, 07h                  ; nChar
  sub rsp, 20h                 ; homespace
  call PIT_StrCmpNICW
  test rax,rax
  jz skip                      ; if found, exit patch
   call https
   db __utf16__('https://'),0
   pop rcx                     ; pszStr1 = "https://"
   mov rdx, [rsp+20h]          ; pszStr2 = pszUrl
   mov r8, 08h                 ; nChar
   call PIT_StrCmpNICW
   test rax,rax
  jz skip                      ; if found, exit patch
   call http
   db __utf16__('http://'),0
   pop rcx                     ; pszStr1 = "http://"
   mov [rsp+28h], rcx          ; store prefix
   mov rdx, [rsp+20h]          ; pszStr2 = pszUrl
   mov r8, 07h                 ; nChar
   call PIT_StrCmpNICW
   test rax,rax
  jz skip                      ; if found, exit patch
   mov r8, 1024h               ; num
   mov rdx, [rsp+20h]          ; Src = pszUrl
   lea rcx,[rdx+0eh]           ; Dst
   call PIT_memmove            ; moving pszUrl of max 1024h in size to *pszUrl+0eh
   mov rcx, [rsp+20h]          ; Dst = pszUrl
   mov rdx, [rsp+28h]          ; Src = "http://"
   mov r8, 0eh                 ; num
   call PIT_memmove            ; copying http:// to *pszUrl
   ;revert stack:
   add rsp, 20h                ; revert homespace
   pop rax
   pop r8                      ; blank pop
   pop r8
   pop rdx
   pop rcx
   pop rsi



So here they are, three micropatches for three 0days. We don't know if and when Microsoft is going to fix these issues (likely in the following months); meanwhile, if you have our Agent installed and registered, these micropatches are already on your computer and applied to all affected processes. Otherwise, register a free 0patch account and install 0patch Agent to get these micropatches applied. As always, once Microsoft fixes any of these 0days, its associated micropatch will automatically stop applying - in other words, you don't have to worry about future Windows updates.

Again, please note that we haven't ported these micropatches to all supported Windows versions (see each section above for version information); if you're interested in patching your particular version of Windows, don't hesitate contacting us at



Friday, October 12, 2018

Patching, Re-Patching and Meta-Patching the Jet Database Engine RCE (CVE-2018-8423)

Flawed Patches Will Always Happen, But We Can Change How They Get Fixed 

by Mitja Kolsek, the 0patch Team

TL;DR: Microsoft patched CVE-2018-8423 eighteen days after we had micropatched it. Their official patch turned out to be incomplete so we re-micropatched it.

This is a story about a Windows vulnerability that was reported to Microsoft, published as "0day" before the official patch was available, micropatched by us one day later, subsequently patched by Microsoft, found to be incorrectly patched, and now micropatched again over the flawed official patch. Confused? It's actually a nice case study to demonstrate... not how we are smarter than Microsoft (we really aren't) but how micropatching is a much more suitable technology for fixing vulnerabilities on billions of computers than the current de-facto standard of what we call "fat updates".

The story begins with the ZDI reporting a memory corruption vulnerability in Jet Database Engine (subsequently assigned CVE-2018-8423) to Microsoft, which then led to a public 0day drop 135 days later without Microsoft having issued an official fix for it. We at 0patch took ZDI's proof-of-concept exploit and created a free micropatch for our users just 24 hours later. For more details up to that point see our previous blog post.

Now, a few days ago, Microsoft issued their fix for this issue as part their October 2018 Monthly Update. As expected, the update brought a modified msrd3x40.dll binary: this is the binary with the vulnerability, which we had micropatched with 4 CPU instructions (one of which was just for reporting purposes). The version of msrd3x40.dll changed from 4.0.9801.0 to 4.0.9801.5 and of course its cryptographic hash also changed - which resulted in our micropatch for this issue no longer getting applied to msrd3x40.dll. This is a welcome automatic side effect of in-memory patching, unburdening users from doing anything beyond applying the official vendor update once it becomes available. It also nicely demonstrates how traditional "module-replacing" updating can safely co-exist with in-memory micropatching.

Naturally we were curious whether Microsoft's fix was identical to our micropatch. Two months ago, we compared Microsoft's fix with our own micropatch for the famous Sandbox Escaper's 0day and found them to be functionally identical.

So we BinDiff-ed the patched msrd3x40.dll to its vulnerable version and reviewed the differences. At this point we will only state that we found the official fix to be slightly different to our micropatch, and unfortunately in a way that only limited the vulnerability instead of eliminating it. We promptly notified Microsoft about it and will not reveal further details or proof-or-concept until they issue a correct fix.

We have, however, issued a micropatch that corrects Microsoft's patch. Namely, in an ironical twist of fate Microsoft's October update actually re-opened the CVE-2018-8423 vulnerability for 0patch users who were previously protected by our micropatch. This new micropatch, which has already been distributed to all online users by now, resumes their protection. At the time of this writing, it is confirmed to be applicable to fully updated 32-bit and 64-bit Windows 10, Windows 8.1, Windows 7, Windows Server 2008 and Windows Server 2012. We suspect all other affected Windows versions also share the same version of msrd3x40.dll, in which case the micropatch will apply there as well. (We'll update this information as we go.)

We all know that many Windows users and admins don't immediately apply Windows updates as they become available. This begs the question: What will happen if you have 0patch Agent installed and haven't applied the October Windows Updates yet? Obviously, you're currently protected by our micropatch for msrd3x40.dll version 4.0.9801.0, which is getting applied to this module whenever the module gets loaded in any running process. When you decide to apply the October Windows Updates, they will make you restart your computer, after which there will be a new version of msrd3x40.dll there, version 4.0.9801.5. But our new micropatch for it will also already be there installed and waiting in your 0patch Agent, so whenever the new  msrd3x40.dll gets loaded, it will immediately be micropatched in memory. Bottom line: you don't have to do anything!

You can see our micropatch in action in the video clip below. The video shows that after the official vendor fix for CVE-2018-8423 has been applied, the original proof-of-concept published by the ZDI really doesn't work anymore (WScript.exe correctly detects invalid input data and displays an error message), but a slightly modified POC still manages to cause an out-of-bounds write and crashes the process. ("Page heap" must be enabled for the process to actually crash, while memory corruption occurs without that as well.) Finally, the video shows that our micropatch fixes the vulnerability for the modified POC as well.

Now what does this story tell us? A couple of things.

1) In-memory micropatching nicely co-exists with traditional "fat" updating. Not only does a micropatch that is currently getting applied get automatically obsoleted when the target binary is replaced by a new version, but a micropatch for a future binary version can also be patiently waiting for you to apply a vendor update, and automatically start getting applied to it when you do. All without you so much as lifting a finger.

2) Flawed patches will always happen. This time it was Microsoft, next time it will be someone else, and then we will make a flawed micropatch ourselves. The possibility of flawed micropatches is designed into our model though; by now you already know that a micropatch gets distributed to all online agents within 60 minutes of issuance, and gets instantly applied to vulnerable modules on your computer. But in case something went terribly wrong with it and it broke something (like this vendor patch did), we could also have it revoked on all online agents within 60 minutes, causing it to stop applying. Meanwhile, you would be able to manually disable the micropatch via 0patch Console.

3) Micropatching is quick and user-friendly. All of the above - deployment, application, removal, and revocation or a micropatch - happens instantly, without restarting the computer or even having to re-open running applications. Compare this with today's standard approach to patching: first you download a ridiculous amount of bytes, which often forever take disk space on your computer, and then you have to at least restart patched applications (with all the documents you're working on) if not restart the computer, to actually get a handful of code changes applied. When something goes wrong, it takes at least as much time to revert to the pre-patched state, and that's only in the ideal case.

4) In-memory micropatching is a superior method to "fat" updates for fixing most security issues. We're not saying we could entirely do away with the concept or replacing modules on your computer and just keep micropatching it into eternity. No, software products periodically need significant modifications, but that's mostly for functional or user interface-related changes - and these really don't need to come on a monthly basis. Security fixes, however, actually need to be delivered faster if we ever want to outrun the attackers, and applied in a less user-hostile way than what we're all used to experiencing today, ideally so that users won't even notice their vulnerabilities disappearing under their feet. We can envision a product update model that includes annual or semi-annual fat updates, and lots of intermediate micropatches for security issues and occasional functional ones.

Our micropatches, including this current one, are still completely free for everyone, and can be obtained by installing and registering 0patch Agent from We highly welcome your feedback on



Wednesday, October 3, 2018

Words "Patching" and "Instantly" Now in the Same Phrase

A Retrospective of The Last Couple of Months in our Patch Factory

by Stanka Salamun, the 0patch Team

The last couple of months were very exciting for our team. We were good Internet citizens – all together we produced, tested and distributed a few hundred bytes of code for more than 15 micropatches (feel free to sigh and whisper: “so tiny?” 😊), but every byte of that was a precise microsurgical cut with a significant impact to the security of your computers. You probably did not notice any of them, because we strive to make the healing process completely painless for you. It’s time for the world to realize that the terms "patching" and "instantly" finally belong together.

We fixed 4 (yes, four) 0days; right now one of them is still without an official vendor patch, and some were or are exploited in the wild.  One bug that we fixed was initially rejected for patching by the original vendor and another one broke users’ networking.  Some of these “micropatch stars” deserve a bit of additional attention.

Outrunning the attackers at a 0day in Microsoft Jet Database Engine

This one is still a genuine 0day without a CVE.  The Zero Day Initiative published details of an unpatched remotely exploitable vulnerability in all Windows versions due to Microsoft missing their 120-day fixing window.

How long does it take for a vulnerability to be patched after a 0day has been dropped? Our answer is: ideally, one day. Challenge accepted: 7 hours after ZDI has published details on this unpatched remotely exploitable vulnerability in Jet Database Engine, we had a micropatch candidate on Windows 7, and within 24 hours our users had micropatches installed and applied on all supported Windows versions.

One of our goals with 0patch is to make vulnerability patching so fast that attackers won't even manage to develop a reliable exploit for a public vulnerability before it is already patched on most users' computers. What a goal, huh?

There is still a lot of buzz about this bug in the media – you can read about it in The Register, Softpedia  and SecurityWeek.  We also reveal all the dirty technical details in our blog post.

As of this writing, our micropatches for the remotely exploitable "0day" in Jet Database Engine are still THE ONLY patches available for this issue.

We Also Micropatched a Publicly Dropped 0day in Task Scheduler (CVE-2018-8440) Ahead of Microsoft

Being who you are can be a bad thing if you're a system service. This is especially true if you are Windows Task Scheduler service that allows a local unprivileged user to change permissions of any file on the system, and you suffer from a local privilege escalation vulnerability. Bad luck for Task Scheduler: as it was a local bug that required the attacker to be locally logged, Microsoft didn’t feel the need to release an out-of-band update.

But we did.  We created a micropatch and described it in detail. After that we were curious how Microsoft would approach the issue. It turned out their official patch was functionally identical to our micropatch, but we were able to be more agile and less intrusive using a different patching technology.

For this one we earned our appearance in Forbes as they said: “ACROS Security seems to have beaten Microsoft to the punch.”

Famous CVE-2018-8174 – a micropatch instead of the official update that probably broke your network

This was a critical remote code execution issue in Microsoft VBScript Engine, exploit for which has previously been detected in the wild.  The bug became kind of famous because the official Microsoft update broke networking on some computers, prompting users to avoid its application.  As Windows updates are "all or nothing" these days, the users can't just remove a defective KB and enjoy the protection provided by other KBs issued on the same Patch Tuesday, so many of them were left vulnerable. For these users we created a single-instruction micropatch and you can read the whole story here.

CVE-2018-8414 – initially rejected for patching by Microsoft

This vulnerability was reported to Microsoft but deemed non-critical, until attackers started exploiting it. So an official vendor patch was available, but we decided to create a micropatch anyway.

We wanted to prove that micropatches could implement the same logic as official updates, but without the fuss for the users and with minimum changes on the affected system. Many users and admins don't / can't / won't / shan't apply official updates or delay their application for all sorts of reasons. In all these cases micropatching is a reliable, targeted, instantly reversible alternative.

In our video you can view this micropatch in action.

As always, all of these micropatches were automatically deployed on all computers running 0patch Agent within 60 minutes from our publishing.  So if you had 0patch Agent installed, you were among the lucky ones that were immediately protected.

Finally,  a friendly reminder for those who aren't 0patch users yet: our micropatches for the remotely exploitable "0day" in Jet Database Engine are still THE ONLY patches available for this issue. And they're FREE! Everyone is welcome to download free 0patch Agent from  and register a free account to get these micropatches.

If (or when) the official fixes become available, just apply them fearlessly. Our micropatches will automatically stop getting applied because the cryptographic hashes of updated binaries will no longer match the ones associated with the micropatches. You don't have to do anything else; 0patch micropatches are simply stepping aside when they are no longer your best option.

Monday, September 24, 2018

Outrunning Attackers On The Jet Database Engine 0day (CVE-2018-8423)

Micropatching Makes It Possible To Create And Apply Patches Before Attackers Write a Reliable Exploit

by Mitja Kolsek, the 0patch Team




Last Thursday, Zero Day Initiative published details of an unpatched remotely exploitable vulnerability in all Windows versions (discovered by Lucas Leong) due to Microsoft missing their 120-day fixing window. We immediately tested ZDI's proof-of-concept and found the following:

  1. Jet is only supported in 32-bit, which means that a 64-bit application tricked into accessing a malformed data source file will not be exploitable. Indeed, double-clicking ZDI's poc.js on 64-bit Windows results in an error message; in order to launch poc.js on a 64bit machine one needs to use the 32-bit wscript.exe by launching c:\windows\SysWOW64\wscript.exe poc.js.
  2. Obviously, getting a user to launch a .js file is not a convincing attack scenario (such file could already do anything within user's privileges). The good news for attackers is that this attack can be mounted via Internet Explorer, especially since even on 64-bit Windows, Internet Explorer rendering processes are 32-bit. On the upside, we were unable to get the exploit working from a web site because - at least on IE11 - the security setting "Access data sources across domains" is disabled in Internet and Intranet zone, which resulted in a JavaScript error. Launching a malicious poc.html from a local drive (or USB disk) does work, however, whereby the accompanying data source file can be in a shared folder and doesn't need to be delivered with poc.html. Nevertheless, the user then has to press the "Allow blocked content" button, which amounts to a considerable level of social engineering required to execute the attack via Internet Explorer.
  3. A more realistic attack could probably be conceived using a malicious Office document referencing an external malformed Jet data source. We haven't investigated that, however, as our job is not to write exploits but micropatches. (Resourceful attackers will soon reveal their weaponization ideas anyway.)

Vulnerability Analysis

As usually, we started our analysis from the closest observable point of failure and worked backward to the vulnerable code. Ideally, the "closest observable point of failure" is a process crash, and in this case, ZDI's PoC indeed causes a crash in wscript.exe due to an attempt to write past the allocated memory block. So their PoC was perfect for us. (Not surprisingly, it's easier for us to work with a crash case than a full blown calc-popping exploit.) Here's how the crash looks like in WinDbg, with Page Heap enabled and invalid memory access in function TblPage::CreateIndexes:

eax=00002300 ebx=00000002 ecx=00834918 edx=00000000 esi=008360a8 edi=0024d64c
eip=6b881234 esp=0024d4c0 ebp=07ac427c iopl=0         nv up ei pl nz ac po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010212
6b881234 89b48174050000  mov     dword ptr [ecx+eax*4+574h],esi ds:002b:0083da8c=????????

For anyone with some mileage in reverse engineering, the instruction causing the exception indicates that the code is accessing an indexed element in an array containing 4-byte elements, whereby the array starts at ecx+574h and the index is in eax (which contains 2300h). And it's clear that the index is beyond the array's limits.

From a patcher's perspective, this raises the following questions:

1) Where does this index come from? (And does it affect anything else, which would cause a micropatch to simply shift the problem further down the code and prompting another micropatch for that?)

2) Does the array have a fixed size? (Which would mean a simple hard-coded index validation micropatch could suffice.)

In tracking the index value 2300h, we found that eax was read from address esi+24h a few instructions back. We then used !heap to find out who allocated it and set an access breakpoint to see who wrote this value there. That turned out to be function Index::Restore, which is called a couple of instruction earlier in TblPage::CreateIndexes. What happens there is value 2300h is copied to the location we're watching with our access breakpoint from address pointed to by edx. And edx at that moment points to the memory-mapped copy of the malformed data source file.

So we found out that the malformed value 2300h comes directly from the PoC file group1, specifically at offset 1257h. Furthermore, looking around the code for additional uses of this user-provided index, we found one case immediately after the crash location, so whatever we'd do we'd need to make sure that this second use wouldn't also cause problems.

An obvious solution to fixing both uses of the malformed index was to check the index immediately after it gets copied from the memory-mapped file (i.e., right after the call to Index::Restore), and setting it to some safe value in case it was out of bounds. But in order to check the bounds we'd need to know the bounds.

Using !heap on ecx at the point of crash we inspected who allocated the memory block from which the PoC has escaped, and how large that block was. We found it to be a fixed-size block of 778h bytes, most likely a C++ object containing a fixed-size array of 4-byte elements. But how many elements? Let's calculate: the array begins at offset 574h in the memory block, and ends at most at offset 778h-1. The difference between the two means there is at most 204h bytes in the array, and dividing that by 4 (bytes) we get 81h elements, meaning that valid index values are between 00h and (at most) 80h.

Note that we say "at most 80h" - at this point we can't know whether the entire space between offset 574h and the end of the memory block is reserved for the array (although it surely seems so), we just calculated the bounds for preventing the offending instruction from escaping the memory block. And we'll be okay with this for now: we'll prevent an exploit from overwriting heap management data or other objects allocated on the heap, which will take most (if not all) of the leverage from the attacker.

The Micropatch 

So how should the micropatch look like? It would have to be injected right after the call to Index::Restore and check that the user-supplied value that was written to [esi+24h] doesn't exceed 80h. If it did exceed 80h, the patch would have to correct the value at [esi+24h], say by overwriting it with 0 (which is a valid index).  And here is the source code of this micropatch:

; Patch for VULN-4112 in msrd3x40.dll version 4.0.9801.0 32bit
MODULE_PATH "..\AffectedModules\msrd3x40.dll_4.0.9801.0_32bit\msrd3x40.dll"
PATCH_ID 1000010
VULN_ID 4112


   cmp dword [esi+24h], 0x80  ; is the index lower than or equal to 0x80?
   jbe pass                   ; if not, we let it pass
                              ; (jbe means unsigned compare, we don't want to allow
                              ; values like 0x80002300 to be considered negative)
   mov dword [esi+24h], 0     ; otherwise we set it to 0
   call PIT_ExploitBlocked    ; and show the Exploit Blocked popup


We initially wrote this micropatch for Windows 7, and had a candidate ready just 7 hours after ZDI had published their PoC. After attempting to port it to other supported Windows versions, we noticed that almost all of them have the exact same version of msrd3x40.dll - which meant the same micropatch would apply to all these systems. The only Windows version with a different msrd3x40.dll was Windows 10: peculiarly, both DLLs had the same version and exactly the same size, but plenty of small differences between the two (including the link timestamp). The code was exactly the same and in the same place though (probably just a re-build), so we could actually use the exact same source code for the micropatch, just a different file hash.

These two micropatches for a published 0day were then issued less than 24 hours after the 0day was dropped, and distributed to our users' computers within 60 minutes, where they were automatically applied to any running process with vulnerable msrd3x40.dll loaded. Which nicely demonstrates the speed, simplicity and user-friendliness of micropatching when it comes to fixing vulnerabilities. In fact one of our goals with 0patch is to make vulnerability patching so fast that attackers won't even manage to develop a reliable exploit for a public vulnerability, much less launch a campaign with it, before the vulnerability is already patched on most users' computers. What a goal, huh?

How Can You Get These Micropatches, And What To Do Next?

These micropatches are completely free for everyone, and can be obtained by installing and registering 0patch Agent from They will prevent exploitation of this 0day as long as you have the latest Windows updates applied (we did not port them to older Windows updates, but if you have a need for that you can contact us at

Once Microsoft issues their official fix (likely on October Patch Tuesday), you will simply apply that update and these micropatches will automatically get obsoleted without you having to do anything else.



Tuesday, September 11, 2018

Comparing Our Micropatch With Microsoft's Official Patch For CVE-2018-8440

by Mitja Kolsek, the 0patch Team

As expected, Windows Update has just brought the official patch for CVE-2018-8440 today, a patch that would replace our "unofficial" micropatch we've issued 13 days ago.

To quickly refresh your memory, 15 days ago security researcher SandboxEscaper published details and proof-of-concept (POC) for a "0day" local privilege escalation vulnerability in Windows Task Scheduler service, allowing a local unprivileged user to change permissions of any file on the system. The next day, we at 0patch have analyzed the vulnerability and prepared a "micropatch candidate" (a micropatch that blocks the POC but needs to be tested for functional side effects). We published the micropatch for Windows 10 version 1803 the day after, and subsequently ported this micropatch to a number of other Windows versions.

Obviously, correcting someone else's code is not to be taken lightly (especially if that code is running on millions of computers), and not having the source code doesn't make it any easier. However, our team of security researchers and the growing community of experts who want to get their vulnerabilities fixed as quickly and efficiently as possible, are doing just that.

In this particular case, our analysis showed that a call for changing permissions of a file, made from Task Scheduler's code, should have been impersonated - but it wasn't. We corrected that by making a call to RpcImpersonateClient right before the call, and another call to RpcRevertToSelf right after it. Pretty basic stuff. And it worked.

Our micropatches are sometimes very similar to official patches (at least functionally speaking), and other times very different; not surprisingly, there is always more than one way to skin a cat - or to fix a vulnerability. So when the official patch from Microsoft came out today, we were naturally curious as to how they fixed it.

The first thing we noticed was that the Windows Update replaced schedsvc.dll with a new version. Promising - this is the exact DLL we had micropatched. Next we ran BinDiff to compare the new and the old version. Even more promising - the only modified function was RpcServer::SetSecurity, which is the very function we had micropatched. And finally, BinDiff showed the exact difference between the old and the new version of this function. Let's take a look at that (note: the diff is for 64bit Windows 7).

As you can see, Microsoft's official patch is functionally identical to our micropatch. We could say that this official patch delivers Microsoft's unofficial confirmation that our approach to patching this vulnerability - in a complex closed-source product - was also optimal from their perspective. That's very positive feedback for us and a great case for "unofficial" 3rd-party micropatches.

Don't get carried away, however! There have been, and will be cases where a 3rd-party micropatch will fix a vulnerability differently and less well than the official vendor fix - or even break a thing or two. While we're doing our best and leverage our advantages (agility, instant patch deployment, instant patch removal), original product developers will always have advantage in their knowledge about the product and its environment, and their code fixes will be preferred. Nevertheless, our mistakes are much easier to remedy than those delivered in a 300MB package that requires a reboot both to install and uninstall. When a micropatch needs to be revoked, it takes just a few minutes for us to do that, and within an hour all online agents stop applying it without interrupting users in the slightest. And an improved version of the micropatch can later be delivered just as easily.

In any case, if you have installed 0patch Agent to micropatch this vulnerability on your computer(s), it is now time to let the official fix take over. To do that, you simply apply today's Windows Updates and as soon as they replace the vulnerable schedsvc.dll, our micropatch will automatically stop applying because the cryptographic hash of the DLL will no longer match that associated with the micropatch. You don't have to do anything else; this is 0patch being a good citizen and stepping aside when it's no longer your best option.