In August 2020, we revealed a weblog submit about Operation PowerFall. This focused assault consisted of two zero-day exploits: a distant code execution exploit for Web Explorer 11 and an elevation of privilege exploit concentrating on the most recent builds of Home windows 10. Whereas we already described the exploit for Web Explorer within the unique weblog submit, we additionally promised to share extra particulars concerning the elevation of privilege exploit in a follow-up submit. Let’s check out vulnerability CVE-2020-0986, the way it was exploited by attackers, the way it was fastened and what further mitigations had been carried out to complicate exploitation of many different comparable vulnerabilities.


CVE-2020-0986 is an arbitrary pointer dereference vulnerability in GDI Print/Print Spooler API. Through the use of this vulnerability it’s potential to control the reminiscence of the splwow64.exe course of to realize execution of arbitrary code within the course of and escape the Web Explorer 11 sandbox as a result of splwow64.exe is working with medium integrity degree. “Print driver host for purposes,” as Microsoft describes splwow64.exe, is a comparatively small binary that hosts 64-bit user-mode printer drivers and implements the Native Process Name (LPC) server that can be utilized by different processes to entry printing capabilities. This enables using 64-bit printer drivers from 32-bit processes. Under I present the code that can be utilized to spawn splwow64.exe and connect with splwow64.exe’s LPC server.

To ship information to the LPC server it’s sufficient to arrange the printer command within the shared reminiscence area and ship an LPC message with NtRequestWaitReplyPort().

When the LPC message is obtained, it’s processed by the operate TLPCMgr::ProcessRequest(PROXY_MSG *). This operate takes LpcRequest as a parameter and verifies it. After that it allocates a buffer for the printer command and copies it there from shared reminiscence. The printer command operate INDEX, which is used to establish totally different driver capabilities, is saved as a double phrase at offset Four within the printer command construction. Nearly a whole listing of various operate INDEX values could be discovered within the header file winddi.h. This header file consists of totally different INDEX values from INDEX_DrvEnablePDEV (0) as much as INDEX_LAST (103), however the full listing of INDEX values doesn’t finish there. Evaluation of gdi32full.dll reveals that which can be quite a lot of particular INDEX values and a few of them are supplied within the desk beneath (to seek out them in binary, search for calls to PROXYPORT::SendRequest).

Operate TLPCMgr::ProcessRequest(PROXY_MSG *) checks the operate INDEX worth and if it passes the checks, the printer command shall be processed by operate GdiPrinterThunk in gdi32full.dll.

GdiPrinterThunk itself is a really giant operate that processes greater than 60 totally different operate INDEX values, and the handler for one among them – specifically INDEX_DocumentEvent – accommodates vulnerability CVE-2020-0986. The handler for INDEX_DocumentEvent will use info supplied within the printer command (absolutely controllable from the LPC shopper) to examine that the command is meant for a printer with a sound deal with. After the examine it would use the operate DecodePointer to decode the pointer of the operate saved on the fpDocumentEvent international variable (positioned in .information phase), then use the decoded pointer to execute the operate, and at last carry out a name to memcpy() the place supply, vacation spot and dimension arguments are obtained from the printer command and are absolutely controllable by the attacker.


In Home windows OS the bottom addresses of system DLL libraries are randomized with every boot, aiding exploitation of this vulnerability. The exploit masses the libraries gdi32full.dll and winspool.drv, after which obtains the offset of the fpDocumentEvent pointer from gdi32full.dll and the deal with of the DocumentEvent operate from winspool.drv. After that the exploit performs quite a lot of LPC requests with specifically crafted INDEX_DocumentEvent instructions to leak the worth of the fpDocumentEvent pointer. The worth of the uncooked pointer is protected utilizing EncodePointer safety, however the operate pointed to by this uncooked pointer is executed every time the INDEX_DocumentEvent command is distributed and the arguments of this operate are absolutely controllable. All this makes the fpDocumentEvent pointer one of the best candidate for an overwrite. A vital step for exploitation is to encode our personal pointer in such a way that it is going to be correctly decoded by the operate DecodePointer. Since we’ve the worth of the encoded pointer and the worth of the decoded pointer (deal with of the DocumentEvent operate from winspool.drv), we’re capable of calculate the key fixed used for pointer encoding after which use it to encode our personal pointer. The mandatory calculations are supplied beneath.

At this stage, with a view to obtain code execution from the splwow64.exe course of, it’s adequate to overwrite the fpDocumentEvent pointer with the encoded pointer of operate LoadLibraryA and supply the title of a library to load within the subsequent LPC request with the INDEX_DocumentEvent command.

Operation PowerFall: CVE-2020-0986 and variants

Overview of assault


Evaluation of CVE-2020-0986 reveals that this vulnerability is the dual brother of the beforehand found CVE-2019-0880. The write-up for CVE-2019-0880 is out there right here. It’s one other vulnerability that was exploited as an in-the-wild zero-day. CVE-2019-0880 is simply one other absolutely controllable name to memcpy() in the identical GdiPrinterThunk operate, only a few strains of code away in a handler of operate INDEX 118. It appears onerous to imagine that the builders didn’t discover the existence of a variant for this vulnerability, so why was CVE-2020-0986 not patched again then and why did it take so lengthy to repair it? It will not be apparent on first look, however GdiPrinterThunk is completely damaged. Even fixing a few calls to memcpy doesn’t actually assist.

Arbitrary pointer dereference host for purposes

The issue lies in the truth that virtually each operate INDEX in GdiPrinterThunk is vulnerable to a possible arbitrary pointer dereference vulnerability. Let’s have a look once more on the format of the LPC request message.

InputBuf and OutputBuf are each pointers that ought to level to a shared reminiscence area. InputBuf factors to a location the place the printer command is ready, and when this command is processed by GdiPrinterThunk the outcome may be written again to the LPC shopper utilizing the pointer that was supplied as OutputBuf. Many handlers for various INDEX values present information to the LPC shopper, however the issue is that the pointers InputBuf and OutputBuf are absolutely controllable from the LPC shopper and manipulation of the OutputBuf pointer can result in an overwrite of splwow64.exe’s course of reminiscence.

The way it was mitigated

Microsoft fastened CVE-2020-0986, but additionally carried out a mitigation aimed to make exploitation of OutputBuf vulnerabilities as onerous as potential. Earlier than the patch the operate FindPrinterHandle() blindly trusted the info supplied by way of the printer command in an LPC request and it was straightforward to bypass a sound deal with examine. After the patch the format of the printer command was modified so it not accommodates the deal with of the deal with desk, however as an alternative accommodates a sound driver ID (quad phrase at offset 0x18). Now the linked listing of deal with tables is saved contained in the splwow64.exe course of and the brand new operate FindDriverForCookie() makes use of the supplied driver ID to get a deal with desk securely. For a printer command to be processed it ought to include a sound printer deal with (quad phrase at offset 0x20). The printer deal with consists of course of ID and the deal with of the buffer allotted for the printer driver. It’s potential to guess some bytes of the printer deal with, however a profitable real-world brute-force assault on this implementation appears to be unlikely. So, it’s secure to imagine that this bug class was correctly mitigated. Nevertheless, there are nonetheless a few locations within the code the place it’s potential to jot down a Zero for the deal with supplied as OutputBuf and not using a deal with examine, however exploitation in such a state of affairs doesn’t look like possible.