Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2023-36424 — Windows 内核池 (clfs.sys) 损坏权限提升 | Kitploit
工具/GitHubGitHub/zerozenxlabs/cve-2023-36424
权限提升内存取证漏洞分析漏洞利用二进制利用
GitHubzerozenxlabs/cve-2023-36424

CVE-2023-36424

Windows 内核池 (clfs.sys) 损坏权限提升

查看仓库
1292312年前Kitploit 审核通过

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

信息

==============

Windows 内核池(clfs.sys)损坏权限提升。(CVE-2023-36424)

本仓库包含技术分析与有效利用代码。

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

漏洞

================

clfs.sys 微过滤器驱动程序中存在池溢出。相关信息可参阅:

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

原因是该驱动程序未充分检查来自 NTFS 重解析点的数据。

我们将考虑 clfs.sys 版本 10.0.22621.2134(Windows 11 22H2 22621.2215)

函数 HsmFltProcessHSMControl 负责处理云过滤器 FSCTL。对于操作码为 0xC0000003 的操作,它最终会调用 HsmFltProcessUpdatePlaceholder。

经过一些处理后,执行流程将到达 HsmiOpUpdatePlaceholderDirectory,然后最终到达 HsmpRpCommitNoLock:

root@kitploit:~
__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*] 检索重解析点数据。该数据包含一个 WORD 大小的值 *((_WORD *)v8 + 7),指定了结构化项目的数量。每个项目都有类型字段、大小和指向数据字段的偏移量。

哪个项目类型出现在哪个位置是严格预定的,但仅限于前 10 个项目。例如,第一个项目的类型字段必须等于 0x7。

驱动程序将执行 HsmpRpValidateBuffer [2*] 来验证获取的数据。然后 [3*] 将分配固定大小为 0x4000 字节的分页池。如果重解析点数据的计数值大于 10,那么第 10 个之后的项目数据将被复制到这个固定大小的池中 [4*],而不进行任何额外的检查。

HsmpRpValidateBuffer 内部的验证是不充分的,因为它只检查前 10 条记录。

root@kitploit:~
__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;
}

正如我们所见 [1*],代码只会验证前 10 个项目,而忽略了存在更多记录的情况。

利用

=================

易受攻击的池大小为 0x4000。这个大小是页面的整数倍,因此将使用段分配 [3]。

利用中使用了此处描述的技术 [4]。调用 NtAlpcCreateResourceReserve 将创建大量句柄,并用指向构造的伪造 _KALPC_RESERVE 对象的指针覆盖其中一个句柄,从而能够写入任意内核地址。

为了准备内存,我们使用管道 [5] 顺序分配大小为 0x4000 的池。然后我们将释放每隔一个池,为易受攻击的缓冲区提供空间。

Alt text

为了读取任意内核地址,利用程序利用了管道。为此,我们将覆盖 PipeAttribute 结构的 AttributeValue 指针。

Alt text

之后,我们可以窃取系统令牌来覆盖目标进程中的令牌。

感谢阅读。

下载工具