目标达成 感谢每一位支持者 — 我们达成了 100% 目标!

目标: 1000 元 · 已筹: 1359 元

100%

CVE-2023-36424 PoC — Microsoft Windows Common Log File System Driver 安全漏洞

来源
关联漏洞
标题: Microsoft Windows Common Log File System Driver 安全漏洞 (CVE-2023-36424)
Description:Microsoft Windows Common Log File System Driver是美国微软(Microsoft)公司的通用日志文件系统 (CLFS) API 提供了一个高性能、通用的日志文件子系统,专用客户端应用程序可以使用该子系统并且多个客户端可以共享以优化日志访问。 Microsoft Windows Common Log File System Driver存在安全漏洞。攻击者利用该漏洞可以提升权限。以下产品和版本受到影响:Windows 11 Version 23H2 for ARM
Description
Windows Kernel Pool (clfs.sys) Corruption Privilege Escalation
介绍
# Information
==============

Windows Kernel Pool (clfs.sys) Corruption Privilege Escalation. (CVE-2023-36424)

This repo contains technical analysis & working exploit.

Author: Nassim Asrir (@p1k4l4) || https://www.linkedin.com/in/nassim-asrir-b73a57122/

# Vulnerability
================

There is a pool overflow in clfs.sys mini filter driver. Information on this can be read on:

1 - https://googleprojectzero.blogspot.com/2021/01/hunting-for-bugs-in-windows-mini-filter.html

2 - https://www.zerodayinitiative.com/blog/2021/7/19/cve-2021-31969-underflowing-in-the-clouds

The reason is that the driver is not sufficiently checks a data that comes from NTFS reparse point.

We will consider clfs.sys version 10.0.22621.2134 (Windows 11 22H2 22621.2215)

The function HsmFltProcessHSMControl is responsible for processing cloud filter FSCTLs. For an operation with code 0xC0000003 , it will eventually call HsmFltProcessUpdatePlaceholder . 

After some processing the execution flow will reach HsmiOpUpdatePlaceholderDirectory and then finally HsmpRpCommitNoLock: 

```c
__int64 __fastcall HsmpRpCommitNoLock(__int64 a1, __int64 a2, struct _FILE_OBJECT *a3, char a4, char a5)

{ .....

v26 = FileObject; LODWORD(v9) = HsmpRpReadBuffer(*(PFLT_INSTANCE *)(v164 + 32), FileObject, (unsigned __int16 **)&P); // [1*]

HsmDbgBreakOnStatus((unsigned int)v9);

if ( (_DWORD)v9 == -1073741195 ) .....

goto LABEL_55; }

if ( (v9 & 0x80000000) != 0i64 )

goto LABEL_9;}
 

if ( (*(_DWORD *)P & 0xFFFF0FFF) != dword_1C0027650 )// Is
Cloud Reparse Tag?
{
LODWORD(v9) = 0xC000CF0B;
.....
goto LABEL_54;
}
v32 = *((unsigned __int16 *)P + 2);
v9 = (unsigned int)HsmpRpValidateBuffer((__int64)P + 8, v32); [2*]
.....
Pool2 = ExAllocatePool2(0x100i64, 0x4000i64, 'pRsH'); // [3*]
v146 = (_DWORD *)Pool2;
v13 = (void *)Pool2;
if ( Pool2 )
{
v64 = v159_10;
v65 = Pool2 + 4;
if ( v8 && *((_WORD *)v8 + 7) > 0xAu )
v64 = *((_WORD *)v8 + 7);
v9 = Pool2 + 20;
v66 = (unsigned int *)(Pool2 + 12);
*(_OWORD *)v65 = 0i64;
*(_WORD *)(Pool2 + 16) = 0;
*(_WORD *)(Pool2 + 18) = v64;
*(_DWORD *)(Pool2 + 12) = 8 * v64 + 16;
*(_DWORD *)v65 = 'pReF';
memset((void *)(Pool2 + 20), 0, 8i64 * v64);
.....
if ( v8 )
{
v127 = 10;
if ( *((_WORD *)v8 + 7) > 0xAu ) // [4*]
{
if ( WPP_GLOBAL_Control !=
(PDEVICE_OBJECT)&WPP_GLOBAL_Control
&& (HIDWORD(WPP_GLOBAL_Control->Timer) & 1) != 0

&& BYTE1(WPP_GLOBAL_Control->Timer) >= 4u )
{
WPP_SF_qiq(WPP_GLOBAL_Control->AttachedDevice, v86,
v87, a2, *(_QWORD *)(v156 + 32), FileObject);
}
while ( v127 < *((_WORD *)v8 + 7) )
{
*(_QWORD *)(v65 + 8i64 * v127 + 16) = *(_QWORD
*)&v8[8 * v127 + 16];
memmove(
(void *)(v65 + *v66),
&v8[*(unsigned int *)&v8[8 * v127 + 20]],
*(unsigned __int16 *)&v8[8 * v127 + 18]); //
[5*]
*(_DWORD *)(v65 + 8i64 * v127 + 20) = *v66;
*v66 += *(unsigned __int16 *)(v65 + 8i64 * v127++ +
18);
}
}
}
.....
}
```

`HsmpRpReadBuffer` [1*] retrieves reparse point data. This data contains WORD-size value *((_WORD *)v8 + 7) , specifying a count of the structured items. Each item has a Type field, Size and Offset to data fields. 

Which item type in which place is strictly predetermined. But only for the first 10 ones. For example, the type field of the first item must have a value equal to 0x7.

The driver will execute HsmpRpValidateBuffer [2*] to verify acquired data. Then [3*] will be allocated paged pool with fixed 0x4000 bytes size. And if reparsed point data has a Count value more than 10, then the

data of the items after the tenth will be copied into this fixed-size pool [4*] without any additional checks.

The validation inside HsmpRpValidateBuffer is insufficiant, because it checks only first 10 records. 

```c
__int64 __fastcall HsmpRpValidateBuffer(__int64 pBuf, unsigned int a2)
{
.....
v2 = a2 - 4;
pBuf2 = pBuf + 4;
LOBYTE(v5) = 0;
v6 = 0i64;
if ( a2 <= 4 )
v2 = 0;
v7 = 0;
v8 = *(_DWORD *)pBuf & 0xF;
if ( !v8 )
{
.....
return IsReparseBufferSupported;
}
if ( v8 > 1 )
{
....
}
v9 = 0;
v66 = 0;
if ( v2 < 0x18 )
goto ERROR_EXIT;
v9 = 1;
if ( *(_DWORD *)pBuf2 != 'pReF' )
goto ERROR_EXIT;
v9 = 2;
v10 = (unsigned int *)(pBuf + 0xC);
if ( (*(_BYTE *)(pBuf + 16) & 2) != 0 && *(_DWORD *)(pBuf +
8) != RtlComputeCrc32(0, (PUCHAR)(pBuf + 0xC), v2 - 8) )
goto ERROR_EXIT;
v11 = *v10;
v9 = 3;
if ( v2 < (unsigned int)v11 )
goto ERROR_EXIT;
v12 = *(unsigned __int16 *)(pBuf2 + 0xE);
v9 = 4;
if ( !(_WORD)v12 )
goto ERROR_EXIT;
v13 = 8 * v12 + 16;

v9 = 5;
if ( v13 >= v11 )
goto ERROR_EXIT;
v9 = 0x10000;
for ( i = 0; ; ++i )
{
v15 = *(unsigned __int16 *)(pBuf2 + 0xE);
if ( (unsigned int)v12 >= 0xA ) // [1*]
v15 = 10;
if ( i >= v15 )
break;
}
```

As we can see [1*] the code will verify only the first 10 items and ignores the case when there are more records.

# Exploitation
=================

The size of the vulnerable pool is 0x4000. The size is a multiple of page and therefore the segment allocation will be used [3].

For exploitation was used the technique described here[4]. Calling NtAlpcCreateResourceReserve will create a lot of handles and ovewriting one of them with the pointer to constructed fake _KALPC_RESERVE object will give us the ability to write to arbitrary kernel address.

To prepare the memory, we sequentially allocating pools of 0x4000 size, using pipes[5]. Then we will free every second pool, provide a place for vulnerable buffer. 

![Alt text](analysis1.png)

To read an arbitrary kernel address, the exploit utilised pipes. For this purpose we will overwrite AttributeValue pointer of the PipeAttribute structure. 

![Alt text](analysis2.png)

And afterwards, we can steal system token to overwrite token in the target process. 

Thanks for reading.
 

文件快照

登录后查看神龙缓存的 POC 文件快照

登录查看
备注
    1. 建议优先通过来源进行访问。
    2. 本地 POC 快照面向订阅用户开放;当原始来源失效或无法访问时,本地镜像作为订阅权益的一部分提供。
    3. 持续抓取、验证、维护这份 POC 档案需要不少投入,因此本地快照已纳入付费订阅。您的订阅是让这份资料能继续走下去的关键,由衷感谢。 查看订阅方案 →