Windows cldflt.sys驱动堆溢出漏洞CVE-2024-30085分析与利用

本文详细分析了Windows云文件迷你过滤器驱动cldflt.sys中的堆溢出漏洞CVE-2024-30085,包括漏洞触发原理、利用技术实现内核指针泄露和任意读写,最终实现从普通用户到SYSTEM权限的提升过程。

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)作为重解析标签。

用户定义的数据具有以下结构:

1
2
3
4
5
6
7
8
typedef struct _REPARSE_DATA_BUFFER {
    ULONG  ReparseTag;
    USHORT ReparseDataLength;
    USHORT Reserved;
    struct {
        UCHAR DataBuffer[1];
    } GenericReparseBuffer;
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;

触发漏洞

让我们看看触发漏洞所需的代码路径:

1
2
3
4
5
-> HsmFltPostCREATE
    -> HsmiFltPostECPCREATE
        -> HsmpSetupContexts
            -> HsmpCtxCreateStreamContext
                -> HsmIBitmapNORMALOpen

通过打开包含cldflt重解析数据的文件,我们能够到达HsmpCtxCreateStreamContext。但是,为了到达HsmIBitmapNORMALOpen触发易受攻击的memcpy,我们必须通过一些与FeRp对象及其嵌套的BtRp对象相关的检查。

利用概述

目前,我们在分页池中有一个溢出,影响大小为0x1000的对象。为了提升权限,我们需要一个内核指针泄露和任意写入能力。我们计划触发这个漏洞两次——第一次获取内核泄露并获得任意写入原语,第二次获取任意读取能力从而获取令牌地址。

完整的利用步骤如下:

  1. 创建漏洞利用文件1并设置大小为0x1010的自定义重解析点数据
  2. 喷洒填充_WNF_STATE_DATA
  3. 喷洒第一组_WNF_STATE_DATA对象
  4. 通过释放每隔一个_WNF_STATE_DATA对象来打孔
  5. 第一次触发漏洞以回收其中一个孔——这会破坏_WNF_STATE_DATA对象,给我们越界读写能力
  6. 喷洒ALPC句柄表以回收剩余的孔
  7. 通过从第一个被破坏的_WNF_STATE_DATA对象读取泄露内核指针
  8. 创建漏洞利用文件2并设置大小为0x1010的自定义重解析点数据
  9. 喷洒第二组填充_WNF_STATE_DATA
  10. 通过释放每隔一个_WNF_STATE_DATA对象来打孔
  11. 第二次触发漏洞以回收其中一个孔
  12. 喷洒PipeAttribute以回收剩余的孔
  13. 使用第二个被破坏的_WNF_STATE_DATA对象破坏PipeAttribute对象,使其指向用户空间中的伪造对象——这给了我们任意读取能力
  14. 使用被破坏的PipeAttribute对象获取令牌地址
  15. 使用第一个被破坏的_WNF_STATE_DATA对象破坏ALPC句柄表,给我们任意写入能力
  16. 覆盖令牌权限获取完全权限!
  17. 获取winlogon进程的句柄
  18. 弹出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在我研究这个漏洞时的耐心指导——我真的学到了很多!

参考文献

  1. Windows云过滤器API文档
  2. 占位文件文档
  3. 重解析点文档
  4. Windows结构体参考
  5. 云过滤器重解析数据结构
  6. ALPC技术论文
  7. PipeAttribute技术论文
  8. Windows内核堆分析
  9. 使用ALPC和PipeAttribute利用CVE-2023-36424
  10. WNF堆喷洒技术
  11. 从句柄创建进程技术
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计