Talos Vulnerability Report

TALOS-2024-1970

Microsoft Windows CLIPSP.SYS License Update Field Type 0xD3 out-of-bounds read vulnerability

August 13, 2024
CVE Number

None

SUMMARY

An out-of-bounds read vulnerability exists in the License Update Field Type 0xD3 functionality of Microsoft Windows CLIPSP.SYS 10.0.22621 Build 22621, 10.0.26080.1 and 10.0.26085.1. A specially crafted license blob can lead to denial of service. An attacker can use the NtQuerySystemInformation function call to trigger this vulnerability.

CONFIRMED VULNERABLE VERSIONS

The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.

Microsoft CLIPSP.SYS 10.0.22621 Build 22621
Microsoft CLIPSP.SYS 10.0.26080.1
Microsoft CLIPSP.SYS 10.0.26085.1
Microsoft Windows 11 Pro 23H2 22631.3296
Microsoft Windows 11 Pro 24H2 Insider Preview 26085.1

PRODUCT URLS

CLIPSP.SYS - https://www.microsoft.com/en-us/windows/windows-11 Windows - https://www.microsoft.com/en-us/windows/

CVSSv3 SCORE

6.8 - CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:H

CWE

CWE-125 - Out-of-bounds Read

DETAILS

CLIPSP.SYS is a driver used to implement Client License System Policy on Windows 10 and 11. It provides the functions used when handling most of the requests involving licensing, notably the implementation of many use cases involved with the SystemPolicyInformation class used in conjunction with NtQuerySystemInformation.

Context

When calling NtQuerySystemInformation with the SystemPolicyInformation class, ntoskrnl will call ExHandleSPCall2 that will process the data provided. The format is mostly undocumented and encrypted using Microsoft’s Warbird. Upon decryption of the data provided, a call handler is invoked based on the command_id provided and dispatches the payload to the relevant function (e.g. SPCallServerHandleClepKdf, SPCallServerHandleUpdateLicense, etc.). A substential amount of these functions are wrapers around clipsp functions that are stored as function pointers in the nt!g_kernelCallbacks globlal array.

The SPCallServerHandleUpdateLicense (command_id:100) will accept a License blob whose format is also undocumented. Once installed, these license files are stored in the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\{7746D80F-97E0-4E26-9543-26B41FC22F79}\{A25AE4F2-1B96-4CED-8007-AA30E9B1A218} key, only accessible to the SYSTEM user. The format of this license file is TLV (Tag-length-value) following this format:

struct __unaligned __declspec(align(1)) LicenseParsing_entry
{
  __int16 type;
  __int16 reserved;
  int entry_size;
  char value[ANYSIZE_ARRAY]; //expected to be of size entry_size
};

The code snippets below are decompiled output and variables names were assumed from context or retrieved from public symbol servers, sdk, etc. The addresses provided are for the canary build 26085.1.amd64fre.ge_release.240315-1352

There exists multiple out-of-bound reads vulnerabilities when handling various license field types. This vulnerability can be triggered by feeding to the SPCallServerHandleUpdateLicense function a license filed that has been tampered with.

When calling SPCallServerHandleUpdateLicense the data will eventually be past to an obfuscated function inside clipsp and stored in an array (see 0x0001C00E8BA3):

 License->field_0[v13].entry_size = v10->entry_size;
 License->field_0[v13].entry_field2 = v10->field_2;
 License->field_0[v13].entry_ptr = (__int64)&v10->first_byte;

Where v13 is the internal type associated with an entry type in the license file. In most of the case below, the root cause of the problem is reading data in entry_ptr without verifying first that entry_size accomodates for the extent of the data read (e.g. read 2 bytes of data at offset 8 without verifying that entry_size >= 8+2)

Vulnerability

When installing a new license containing keyholder information, an out-of-bound read can occur if a truncated blob of type 0xD3 (internal type 2) is appended at the end of the license such as {0xD3, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xAA }. The following function gets invoked when handling keyholder information while/after installing a new license:

//001C00E77D8 
__int64 __fastcall __spoils<rax,rdx> LicenseStruct_get_dref0_for_type2(LicenseStruct *License)
{
  unsigned int *entry_ptr; // rdx
  __int64 result; // rax

  entry_ptr = (unsigned int *)License->field_0[2].entry_ptr;
  result = 0i64;
  if ( entry_ptr )
    return *entry_ptr; //out of bound read happens here
  return result;

The function above is not necessarily invoked upon installation of the license but when key data is accessed (e.g. tampering with an existing application license and then open/close the application)

TIMELINE

2024-04-12 - Vendor Disclosure
2024-07-09 - Vendor Patch Release
2024-08-13 - Public Release

Credit

Discovered by Philippe Laulheret of Cisco Talos.