This blog details a NULL pointer dereference in the Windows
win32kfull.sys kernel-mode graphics module discovered by ZDI contributor Marcin Wiązowski. It can be used to create a denial-of-service condition. In limited circumstances, it can be used for privilege escalation, though if modern mitigations are present privilege escalation will not be possible. Due to the limited impact, Microsoft has made the decision not to service this bug report. As such, we disclosed the vulnerability as a 0-day according to our policy. This article details the vulnerability, ZDI-CAN-12671, and explains its impact.
In win32k, any drawing operation is performed upon an abstracted drawing surface (“surface”) represented in the kernel by a
Two fields are highlighted above. The field
hdev is a handle to a particular device driver. The field
flags is partially undocumented, but some of the flags that it can contain are the
HOOK_* flags documented here. Each
HOOK_* flag indicates that a particular graphics primitive should be delegated to the device driver specified by
hdev. For example,
HOOK_BITBLT indicates that every BitBlt drawing operation performed on the surface should be delegated to the appropriate
DrvBitBlt primitive offered by the device driver.
The bug is found in the function
win32kfull.sys!BLTRECORD::bRotate, specifically in the one that takes four parameters. Within this function, it performs a
PlgBlt drawing operation on a surface. If
HOOK_PLGBLT is set in the
flags field of the
SURFOBJ, it delegates to the underlying device driver’s
DrvPlgBlt, as explained above. The problem, though, is that it fails to check whether the driver specified by
hdev actually offers a native
DrvPlgBlt. If no such function is offered by the driver, the corresponding entry in the driver’s function table will be NULL, and
win32kfull.sys!BLTRECORD::bRotate will attempt to perform a call to the NULL address.
HOOK_* flags can be set from user mode by calling
gdi32!EngAssociateSurface. There are some additional details involved in preparing a surface for exploiting this bug, but those are secondary to the vulnerability and are beyond the scope of this article.
To exploit this, the first thing needed is a graphics output device driver that does not export a
DrvPlgBlt function. One such driver is the multi-monitor driver implemented in
win32kfull itself. The exported functions of this driver are recognizable by the
Mul prefix in their names, for example,
win32kfull!MulBitBlt. Notably for our purposes, there is no
win32kfull!MulPlgBlt. This device driver is available on any system with multiple active monitors.
Without further preparation, triggering the vulnerability produces a branch to address 0 in kernel mode, crashing the system.
Is it possible to exploit this bug for greater impact, such as a kernel escalation of privilege? Yes, but there are significant preconditions that drastically restrict when it is possible:
- It must be possible to map the NULL page and place executable code there. On currently-supported Windows systems, mapping the NULL page is not possible from an unprivileged user-mode process. There is one known exception, though: The NULL page can still be mapped in a 16-bit process. 16-bit processes can be created only if the NTVDM subsystem is installed. Note that a non-administrator cannot install the NTVDM subsystem, but if this subsystem has already been installed by an administrator, it can be utilized afterward by a non-privileged user. NTVDM is available only on 32-bit installations of Windows.
- Even if a user-mode process maps a page of executable memory at address 0, this page will be executable in user mode only but will not be executable in kernel mode. This is due to SMEP [PDF]. Kernel execution at access 0 can be achieved only on processors that do not offer the SMEP mitigation, or by disabling SMEP via processor control register CR4.
In summary, privilege escalation is possible only on a 32-bit installation of Windows, with NTVDM installed, and where the processor does not offer the SMEP mitigation. However, it should be noted that these conditions may be relaxed if the attacker has knowledge of additional vulnerabilities that can be exploited for SMEP bypass or NULL page mapping. In his submission, Marcin did include working proof-of-concept code that demonstrates privilege escalation under a specific set of circumstances. While the risk to users is small, it is not zero. It is our hope Microsoft reconsiders and produces a patch to address this bug in the future.
ZDI-CAN-12671: Windows Kernel DoS/Privilege Escalation via a NULL Pointer Deref