Hunting Windows Desktop Window Manager Bugs

Zhang WangJunjie (Security Researcher · Hillstone Networks), YiSheng He (Hillstone Networks), Wenyue Li (Senior Security Researcher · Hillstone Networks)

HITBSecConf2023 - Amsterdam · Day 1 · Track 1

Overview

This talk, "Hunting Windows Desktop Window Manager Bugs," presented by Zhang WangJunjie, Wenyue Li, and YiSheng He from Hillstone Networks, delves into the vast and often overlooked attack surface within the Windows Desktop Window Manager (DWM) and its underlying DirectComposition user-mode component. The speakers provide a comprehensive analysis of the DWM architecture, the interaction between user-mode applications and the kernel, and the types of vulnerabilities that can arise from this complex interplay.

Watch on YouTube

Visual summary for Hunting Windows Desktop Window Manager Bugs by Zhang WangJunjie, YiSheng He, Wenyue Li
Visual summary for Hunting Windows Desktop Window Manager Bugs by Zhang WangJunjie, YiSheng He, Wenyue Li

Key moments

  1. 2:00 DirectComposition architecture and DWM components
  2. 3:00 DWM command submission via kernel syscalls
  3. 20:00 DWM's large attack surface and fuzzing methodology
  4. 28:00 CVE-2022-2196: Shared memory arbitrary address access
  5. 34:00 Type confusion leading to out-of-bounds write
  6. 38:00 Use-After-Free in DWM's publisher/subscriber model
  7. 42:00 Heap buffer overflow and future DWM research

Hunting Windows Desktop Window Manager Bugs

Speakers: Zhang WangJunjie (Security Researcher, Hillstone Networks); YiSheng He (Hillstone Networks); Wenyue Li (Senior Security Researcher, Hillstone Networks)

Conference: HITB Amsterdam

YouTube: https://www.youtube.com/watch?v=4_ExouTXe10

Overview

This talk, "Hunting Windows Desktop Window Manager Bugs," presented by Zhang WangJunjie, Wenyue Li, and YiSheng He from Hillstone Networks, delves into the vast and often overlooked attack surface within the Windows Desktop Window Manager (DWM) and its underlying DirectComposition user-mode component. The speakers provide a comprehensive analysis of the DWM architecture, the interaction between user-mode applications and the kernel, and the types of vulnerabilities that can arise from this complex interplay.

The research highlights DWM's critical role in rendering the Windows user interface and its elevated privileges, running at the System Integrity Level. This makes DWM a prime target for privilege escalation attacks, particularly from sandboxed, low-privileged processes like those found in app containers. The presentation details several novel vulnerabilities discovered through both fuzzing and code auditing, including arbitrary address dereferences, out-of-bounds accesses, type confusions, use-after-frees (UAFs), and heap buffer overflows. The insights shared are crucial for security researchers and defenders seeking to understand and mitigate risks within core Windows display components.

Background

▶ Watch: DirectComposition architecture and DWM components (2:00)

DirectComposition is a fundamental Windows component designed to enable high-performance bitmap composition, facilitating rich visual effects, animations, and transitions within the user interface. Developers leverage the DirectComposition API to create dynamic and visually engaging applications. The architecture is split into two primary domains: user-mode and kernel-mode.

In user-mode, applications interact with the DirectComposition API, which in turn calls Wing32kbase.sys via Wing32u.dll export functions. These kernel-mode system calls generate commands that are stored in a shared section of memory. The DWM process, running in user-mode, then retrieves and processes these commands, orchestrating the final rendering operations. The bulk of command processing within the DWM process is handled by DWM Core.dll. An ALPC port also exists to handle requests from the user in the kernel.

Key system calls that orchestrate this interaction include:

  • NTDCompositionCreateChannel: Initiates a channel, creating a kernel object handle and allocating a shared buffer for commands. The size of this shared section can be customized.
  • NTDCompositionProcessChannelBatchBuffer: Used to create various commands, such as creating or releasing resource objects, setting reference objects, or modifying integer/floating-point attributes. These commands are stored in the previously mapped shared section.
  • NTDCompositionCommitChannel: Submits all generated commands to the DWM process for execution.

Objects within DirectComposition, both in the kernel and DWM Core.dll, possess virtual tables with distinct functions, such as GetType and IsOfType for object verification, and SetReferenceProperty or SetIntegerProperty for attribute manipulation. A SetRemotionFlagObject function is particularly notable as it's invoked when the DWM process restarts, allowing the kernel to recalculate and restore the state of previously created objects, ensuring continuity after unexpected crashes. Object handles are managed through a handle table, which maps numerical handles to object pointers, simplifying subsequent command references.

Key Findings

▶ Watch: DWM's large attack surface and fuzzing methodology (20:00)

The research revealed that the DirectComposition component presents an exceptionally large and complex attack surface, making it ripe for vulnerability discovery. The speakers identified two primary areas of interest:

  1. Kernel-State Driver (win32kbase.sys): This module exposes a vast number of object internal functions. A direct search for "DirectComposition" in a function panel reveals approximately 2163 functions, indicating an extensive surface area for potential kernel-mode vulnerabilities.
  2. User-Mode DWM Process (DWM Core.dll): The DWM process includes a large switch-case branch within CComposition::ProcessChannelBatchBuffer that dispatches commands. In the Windows 21H1 version, there are roughly 0x282 distinct commands, leading to nearly 700 branch functions responsible for processing these commands. Each of these branches represents a potential point of failure or security flaw.

Crucially, the DWM process operates at the System Integrity Level. This elevated privilege status means that vulnerabilities found within DWM can be exploited by low-privileged, sandboxed processes (e.g., those running in an App Container) to achieve privilege escalation. The system calls involved in DWM interaction are often not filtered by sandboxes, allowing attackers to directly target DWM.

The team employed a fuzzing approach, modifying the open-source ciscollar tool (similar to syzkaller) to target DirectComposition. Their fuzzer focused on collecting code coverage for the win32kbase kernel driver. By adding NTDCompositionCommitChannel at the end of each generated program, they ensured commands were submitted to DWM, allowing them to monitor for DWM process crashes. Despite the fuzzer's relative simplicity (lacking DWM user-mode coverage collection), it successfully uncovered several vulnerabilities, including a surprising type confusion issue. The talk detailed five distinct vulnerabilities, highlighting the effectiveness of their methodology.

Technical Deep Dive

▶ Watch: CVE-2022-2196: Shared memory arbitrary address access (28:00)

The speakers detailed several critical vulnerabilities, demonstrating common pitfalls in complex component development:

1. Arbitrary Address Dereference / Use-After-Free (CVE-2022-2196)

This vulnerability stems from DWM Core.dll's handling of data from shared memory. The process involves:

  • Shared Memory Acquisition: DWM Core.dll obtains a pointer to shared memory via NTDCompositionCreateAndBindSharedSection. This syscall creates a kernel section object using ZWCreateSection, attaches it to the DWM process, and allocates a handle. DWM Core then uses CSharedSection::ResolveAllocation to get the actual shared memory address.
  • Lack of Validation: The pointer obtained from shared memory is used without any validation. It's directly copied into an object, and its reference count is incremented.
  • Race Condition: A critical problem arises because DWM Core.dll clears the shared memory content using memset after obtaining the address. If a large shared memory region is created (e.g., 0x2000 bytes), the memset operation takes longer. This extended execution window allows for a race condition.
  • Exploitation: An attacker can create a large shared memory section. Simultaneously, a separate thread can repeatedly write a malicious data pointer (e.g., an invalid address) into this shared memory after DWM has obtained its address but before the memset completes. When NTDCompositionCommitChannel is called, the DWM process will eventually attempt to dereference this invalid pointer, leading to an arbitrary address violation and a crash in the object's destructor function (ReadValueFromCache).

2. Out-of-Bounds Access in Keyframe Data Processing

This vulnerability also resides in shared memory handling, specifically within the CComposition::ProcessSetKeyframeData function.

  • Unchecked Index: The function directly extracts an object index from the shared memory.
  • Direct Object Access: Without any bounds checks on this index, DWM then directly retrieves an object from an array using this potentially malicious index.
  • Reference Count Increment: The reference count of the retrieved (potentially out-of-bounds) object is then incremented.
  • Impact: This leads to an out-of-bounds read or write access, causing a process crash. The crash stack shows the issue occurring after CComposition::ProcessSetKeyframeData is invoked, with the buffer index entirely controllable by the attacker.

3. Type Confusion (CResourceTable::GetResourceWithoutType)

This is a significant vulnerability arising from insufficient type validation.

  • Two Resource Retrieval Functions: DWM Core.dll has two primary functions for obtaining resource objects: CResourceTable::GetResource and CResourceTable::GetResourceWithoutType.
  • Lack of Type Checking: GetResource performs type validation (checking if the object type matches a specified parameter), returning zero if types differ. However, GetResourceWithoutType does not perform any type checks.
  • Exploitation: If IsOfType is not called immediately after GetResourceWithoutType to manually verify the object's type, a type confusion can occur. The talk demonstrated a scenario where a CBaseExpression object is mistakenly treated as a CManipulation object. This leads to DWM creating a weak reference pointer to the unchecked object, setting it to an expression object, and releasing the old object. This process can be repeated.
  • Arbitrary Write: The confused object is eventually passed to CScene::InjectManipulation, which still does not check the object type. DWM then attempts to write controllable values at specific offsets (e.g., 0x256, 0x268, and 0x300) within this object. If the actual size of the confused object is less than these offsets, it results in an out-of-bounds write, allowing an attacker to overwrite data in adjacent memory regions (e.g., overwriting a pointer with 0x41414141), leading to a DWM process crash.

4. Use-After-Free (UAF) in CProxyGeometry::ProcessSetViewbox

This UAF vulnerability is related to the publisher-subscriber model supported by DWM.

  • Unchecked Registration: The CProxyGeometry::ProcessSetViewbox function uses GetResourceWithoutType to obtain a CViewbox object provided by the user and registers it as a subscriber to CProxyGeometry. Critically, this function lacks re-entry detection, allowing multiple CViewbox objects to be registered as subscribers.
  • Publisher/Subscriber Model: When a property of the CProxyGeometry object changes, it notifies all its registered subscriber CViewbox objects by calling their EndNotificationOnChange function.
  • Exploitation Steps:
  1. Create CProxyGeometry and an initial CViewbox object, binding them. Commit via NTDCompositionCommitChannel.
  2. Loop: Create a large number of additional CViewbox objects (e.g., 0x1000), binding them all to the CProxyGeometry object. Commit channel. This registers many CViewbox objects as subscribers.
  3. Release the CViewbox objects created by the kernel. These objects are now freed.
  4. Create a new CViewbox object and bind it to CProxyGeometry. Commit channel.
  5. When ProcessSetViewbox is called, it attempts to notify all previously registered CViewbox objects, including those that have been freed in step 3. This triggers a Use-After-Free.
  • Heap Spray for Control: To gain control over the freed memory, the CInteractionTracker::ProcessSetInteractionModifierAnimation function can be used. This function allows allocating arbitrary-sized memory with fully controlled content, enabling an attacker to occupy the freed CViewbox objects and control the UAF primitive.

5. Heap Buffer Overflow in CInjectionAnimation::ProcessSetInjectionData

This vulnerability is a classic heap buffer overflow due to an allocation/copy size mismatch.

  • Size Calculation Mismatch: In CInjectionAnimation::ProcessSetInjectionData, the function calculates a block_size based on a user-provided buffer_size. It then allocates memory using block_size * 0x84. However, when copying data from the shared memory to this newly allocated buffer using memcpy, it uses the original buffer_size.
  • Vulnerable Scenario: If the buffer_size provided by the user is not a multiple of 0x84 (e.g., 0x83 bytes), the block_size calculation can result in a smaller-than-expected allocation, or even a zero-sized allocation (if buffer_size < 0x84, block_size might be 0).
  • Exploitation: For example, if buffer_size is 0x83, block_size might be calculated as 0. This would lead to a 0-byte allocation. However, memcpy still attempts to copy 0x83 bytes, resulting in a heap buffer overflow.
  • Impact: An attacker can provide a buffer_size of 0x83 and set the content of the shared memory to controlled data (e.g., 0x41414141). This will overwrite a pointer in an adjacent object, causing a DWM process crash and providing a strong primitive for exploitation.

Demo / Proof of Concept

▶ Watch: Use-After-Free in DWM's publisher/subscriber model (38:00)

While the talk did not feature a live demo, the speakers meticulously walked through the Proof of Concept (POC) steps for several of the identified vulnerabilities, particularly the Heap Buffer Overflow and the UAF issue.

For the Heap Buffer Overflow (CInjectionAnimation::ProcessSetInjectionData), the POC involved:

  1. Creating CInjectionAnimation and CSharedSectionMarshall objects.
  2. Establishing shared memory between them, filling it with controlled data (e.g., 0x41414141).
  3. Sending a SetIntegerProperty command to set the buffer size to 0x83.
  4. Sending a SetReferenceProperty command to bind the shared section to the CInjectionAnimation object.
  5. Calling NTDCompositionCommitChannel to submit the commands, leading to a visible DWM process crash with the overwritten pointer.

The speakers noted that the object types and property values might differ across Windows versions (e.g., the POC was based on Windows 11 21H2), requiring adaptation for other environments. The detailed steps provided for the UAF (creating 0x1000 objects, releasing, then re-triggering) and Type Confusion (forcing CBaseExpression to be treated as CManipulation) also serve as comprehensive POC descriptions, outlining the precise sequence of NTDComposition syscalls required to trigger each bug.

Defensive Implications

▶ Watch: Heap buffer overflow and future DWM research (42:00)

The findings presented in this talk offer several critical defensive implications for both developers and security practitioners:

  1. Strict Input Validation: Developers of components interacting with shared memory must implement rigorous validation for all data read from these regions, especially pointers, sizes, and indices. Assumptions about data integrity from shared sections are dangerous.
  2. Robust Type Checking: The prevalence of type confusion issues, particularly when using functions like GetResourceWithoutType, underscores the need for explicit type validation immediately after object retrieval. Every object should be verified against its expected type before any operations are performed.
  3. Careful Reference Counting and Object Lifecycle Management: Vulnerabilities like UAF highlight the importance of correct reference counting and ensuring objects are not accessed after they have been freed. Mechanisms for re-entry detection in object registration processes are crucial to prevent double-frees or UAFs.
  4. Secure Memory Allocation and Copying: The heap buffer overflow demonstrates the classic danger of mismatched allocation and copy sizes. Developers must meticulously ensure that memcpy operations do not exceed the bounds of allocated buffers, especially when sizes are derived from user input or complex calculations.
  5. Regular Patching and Updates: For end-users and system administrators, the most direct defense is to keep Windows operating systems fully updated. Patches for these types of vulnerabilities are regularly released by Microsoft and are essential to mitigate known attack vectors.
  6. Enhanced Sandbox Filtering: While DWM interaction is often unfiltered, security architects should consider if additional filtering or stricter policies could be applied to DWM-related system calls from low-privileged processes, potentially reducing the attack surface for privilege escalation.
  7. Continued Research and Auditing: The DWM component remains a large and active area of development, with new features constantly being added. The speakers explicitly mentioned that the ALPC processing code within DWM has not been fully reviewed, indicating further attack surface. Continuous security auditing and fuzzing efforts are necessary to uncover new vulnerabilities.

Key Takeaways

  • The Windows Desktop Window Manager (DWM) and its DirectComposition component represent a massive and complex attack surface, encompassing both kernel-mode (win32kbase.sys with ~2163 functions) and user-mode (DWM Core.dll with ~700 command processing branches) code.
  • DWM runs at the System Integrity Level, making it a high-value target for privilege escalation from low-privileged sandboxed processes, as its interaction syscalls are often unfiltered.
  • Shared memory handling is a common source of critical vulnerabilities, including arbitrary address dereferences, race conditions, and out-of-bounds accesses, due to insufficient validation and synchronization.
  • Lack of strict type validation, particularly with functions like CResourceTable::GetResourceWithoutType, directly leads to severe type confusion vulnerabilities that can be leveraged for arbitrary memory writes and process crashes.
  • Improper object lifecycle management, including issues with reference counting and re-entry detection during object registration, is a root cause for Use-After-Free (UAF) vulnerabilities.
  • Even relatively simple fuzzing techniques, such as modifying ciscollar to target win32kbase and monitor DWM crashes, can be highly effective in uncovering significant vulnerabilities in complex, continuously updated components like DWM.

About the Speaker(s)

Zhang WangJunjie is a Security Researcher at Hillstone Networks. His primary research focus is Windows vulnerability research, covering both user-mode and kernel-mode components. He has been recognized as a Microsoft Most Valuable Security Researcher (MVS) in both 2020 and 2022.

Wenyue Li is a Senior Security Researcher at Hillstone Networks. His expertise lies in mobile security, operating system vulnerabilities, and Advanced Persistent Threat (APT) analysis.

YiSheng He is the leader of the security team at Hillstone Networks. His main research areas include AIoT and web security. He is also an enthusiastic participant in CTF (Capture The Flag) competitions. Unfortunately, he was unable to attend the conference in person.

Reviews

Dr. Zero (Offensive Security Researcher) — STRONG ACCEPT

Solid bug-hunting talk that delivers five real vulnerabilities in DWM/DirectComposition with clear root-cause analysis. Not groundbreaking technique-wise—race conditions, type confusion, UAFs are familiar primitives—but the target selection is smart and the attack surface enumeration alone is useful. Good craft, not revolutionary.

Heather Calloway (CISO) — SOLID

Competent Windows internals research that documents real privilege escalation paths from sandboxed processes via DWM. The five CVEs are legitimate, but this is specialized offensive research—useful for teams with Windows kernel visibility, not a strategic priority for most security programs.

→ Top-rated talks at HITBSecConf2023 - Amsterdam

All talks from HITBSecConf2023 - Amsterdam