TLDR
CVE-2024-30085是影响Windows云文件迷你过滤器驱动cldflt.sys的基于堆的缓冲区溢出漏洞。通过构造特殊的重解析点,可以触发缓冲区溢出破坏相邻的_WNF_STATE_DATA对象。被破坏的_WNF_STATE_DATA对象可用于从ALPC句柄表对象泄露内核指针。第二次缓冲区溢出用于破坏另一个_WNF_STATE_DATA对象,进而破坏相邻的PipeAttribute对象。通过在用户空间伪造PipeAttribute对象,我们能够泄露令牌地址并覆盖权限,将权限提升至NT AUTHORITY\SYSTEM。
漏洞分析与补丁
CVE-2024-30085是由SSD Secure Disclosure的Alex Birnberg以及Theori的Gwangun Jung和Junoh Lee发现的基于堆的缓冲区溢出漏洞。对于Windows 10 22H2,该漏洞在KB5039211更新中被修复。
查看补丁差异,可以清楚地看到HsmIBitmapNORMALOpen函数已被修改。在未打补丁的函数中,驱动程序在分页池中分配了一个大小为0x1000的HsBm对象,并将memcpy_size大小的数据复制到分配的缓冲区中。由于用户可以控制复制的数据以及memcpy_size的值,如果memcpy_size大于0x1000,就会发生分页池中的堆缓冲区溢出!
重解析点结构
重解析点包含一个重解析标签(标识拥有该重解析点的文件系统驱动程序)和用户定义的数据。在本例中,我们将使用IO_REPARSE_TAG_CLOUD_6(0x9000601a)作为重解析标签。
用户定义的数据具有以下结构:
|
|
触发漏洞
让我们看看触发漏洞所需的代码路径:
|
|
通过打开包含cldflt重解析数据的文件,我们能够到达HsmpCtxCreateStreamContext。但是,为了到达HsmIBitmapNORMALOpen触发易受攻击的memcpy,我们必须通过一些与FeRp对象及其嵌套的BtRp对象相关的检查。
利用概述
目前,我们在分页池中有一个溢出,影响大小为0x1000的对象。为了提升权限,我们需要一个内核指针泄露和任意写入能力。我们计划触发这个漏洞两次——第一次获取内核泄露并获得任意写入原语,第二次获取任意读取能力从而获取令牌地址。
完整的利用步骤如下:
- 创建漏洞利用文件1并设置大小为0x1010的自定义重解析点数据
- 喷洒填充_WNF_STATE_DATA
- 喷洒第一组_WNF_STATE_DATA对象
- 通过释放每隔一个_WNF_STATE_DATA对象来打孔
- 第一次触发漏洞以回收其中一个孔——这会破坏_WNF_STATE_DATA对象,给我们越界读写能力
- 喷洒ALPC句柄表以回收剩余的孔
- 通过从第一个被破坏的_WNF_STATE_DATA对象读取泄露内核指针
- 创建漏洞利用文件2并设置大小为0x1010的自定义重解析点数据
- 喷洒第二组填充_WNF_STATE_DATA
- 通过释放每隔一个_WNF_STATE_DATA对象来打孔
- 第二次触发漏洞以回收其中一个孔
- 喷洒PipeAttribute以回收剩余的孔
- 使用第二个被破坏的_WNF_STATE_DATA对象破坏PipeAttribute对象,使其指向用户空间中的伪造对象——这给了我们任意读取能力
- 使用被破坏的PipeAttribute对象获取令牌地址
- 使用第一个被破坏的_WNF_STATE_DATA对象破坏ALPC句柄表,给我们任意写入能力
- 覆盖令牌权限获取完全权限!
- 获取winlogon进程的句柄
- 弹出NT AUTHORITY\SYSTEM shell!!!
获取内核指针泄露
我们将使用两个内核对象来获取内核指针泄露:_WNF_STATE_DATA和_ALPC_HANDLE_TABLE。
Windows通知设施(WNF)是一个未记录的内核组件,用于在系统间发送通知。用于发送通知的数据存储在_WNF_STATE_DATA对象中,该对象分配在分页池中,由一个大小为0x10的头部和紧随其后的数据组成。
高级本地过程调用(ALPC)是Windows内核中未记录的内部进程间通信设施。当创建ALPC端口时,_ALPC_HANDLE_TABLE对象最初以0x80的大小分配在分页池中。每次调用NtAlpcCreateResourceReserve时,都会创建一个_KALPC_RESERVE blob,并调用AlpcAddHandleTableEntry将其地址添加到句柄表中。
任意读取
现在我们有了内核指针泄露,我们想要获得任意读取能力以便获取令牌地址。为此,可以第二次触发漏洞来覆盖第二个_WNF_STATE_DATA数据对象。与之前一样,我们将喷洒_WNF_STATE_DATA,通过释放每隔一个对象来打孔,然后触发漏洞导致溢出并破坏相邻的_WNF_STATE_DATA对象。但这次,我们将喷洒PipeAttribute,并使用被破坏的_WNF_STATE_DATA来破坏相邻的PipeAttribute结构。
PipeAttribute任意读取技术由Corentin Bayet和Paul Fariello在他们的论文中提出。当创建管道时,用户可以添加属性,这些属性随后以键值对的形式存储在链表中。PipeAttribute是一个可变大小的结构,分配在分页池中。
权限提升
现在我们有了令牌地址,我们最终可以将权限提升到NT AUTHORITY\SYSTEM!
记住我们用来泄露ALPC句柄表中_KALPC_RESERVE指针的第一个_WNF_STATE_DATA吗?我们可以使用相同的_WNF_STATE_DATA对象用指向用户空间中伪造的_KALPC_RESERVE结构的指针覆盖该指针。在_KALPC_RESERVE内部,有一个指向_KALPC_MESSAGE的指针。
在_KALPC_MESSAGE内部,有两个我们感兴趣的字段:ExtensisonBuffer和ExtensionBufferSize。当调用NtAlpcSendWaitReceivePort时,用户可控的ExtensionBufferSize大小的数据被写入ExtensionBuffer。为了获得任意写入,我们可以让我们的伪造_KALPC_RESERVE结构指向一个伪造的_KALPC_MESSAGE结构(也在用户空间中),将ExtensionBuffer设置为我们想要写入的位置!
在这种情况下,我们将ExtensionBuffer设置为令牌权限(位于偏移量0x40),ExtensionBufferSize设置为0x10,这样我们可以写入16个\xff,这将启用所有权限。
漏洞利用演示
这是漏洞利用运行时的样子:
[图片描述漏洞利用成功运行]
漏洞利用源代码可以在此处获取。
致谢
我要感谢Chen Le Qi在我研究这个漏洞时的耐心指导——我真的学到了很多!
参考文献
- Windows云过滤器API文档
- 占位文件文档
- 重解析点文档
- Windows结构体参考
- 云过滤器重解析数据结构
- ALPC技术论文
- PipeAttribute技术论文
- Windows内核堆分析
- 使用ALPC和PipeAttribute利用CVE-2023-36424
- WNF堆喷洒技术
- 从句柄创建进程技术