野外0day - CVE-2023-36802:Microsoft 流服务代理权限提升漏洞

admin 2023年10月14日14:20:31评论72 views字数 8400阅读28分0秒阅读模式



野外0day - CVE-2023-36802:Microsoft 流服务代理权限提升漏洞

基础

披露或补丁日期: 2023 年 9 月 12 日

产品:窗户

咨询: https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-36802

受影响的版本:

  • 没有 KB5030211 或 KB5030214 的 Windows 10

  • 没有 KB5030219 或 KB5030217 的 Windows 11

  • 没有 KB5030214 的 Windows Server 2019

  • 没有 KB5030216 或 KB503025 的 Windows Server 2022

第一个补丁版本:

  • 带有 KB5030211 或 KB5030214 的 Windows 10

  • 带有 KB5030219 或 KB5030217 的 Windows 11

  • Windows Server 2019 与 KB5030214

  • 带有 KB5030216 或 KB503025 的 Windows Server 2022

问题/错误报告:不适用

补丁 CL:不适用

Bug 引入 CL: N/A

记者:

  • 夏光辉 (@ze0r) 与河北华测

  • Quan Jin (@jq0904) 和 ze0r 与 DBAPPSecurity WebBin 实验室

  • Valentina Palmiotti 与 IBM X-Force

  • 微软威胁情报

  • 微软安全响应中心

代码

概念验证:

HANDLE h;HRESULT hr;DWORD bytesReturned;char buf[0x100] = {0};
hr = KsOpenDefaultDevice(KSNAME_Server, GENERIC_READ | GENERIC_WRITE, &h);
memset(buf, 'A', sizeof(buf));*(int32_t *)buf = 1;*((int64_t *)buf + 3) = 0;BOOL status = DeviceIoControl(h, IOCTL_FRAMESERVER_INIT_CONTEXT, &buf, sizeof(buf), &buf, sizeof(buf), &bytesReturned, 0);
memset(buf, 'A', sizeof(buf));*((DWORD*)buf + 8) = 1;*((DWORD*)buf + 9) = 1;status = DeviceIoControl(h, IOCTL_FRAMESERVER_PUBLISH_RX, &buf, sizeof(buf), &buf, sizeof(buf), &bytesReturned, 0);

利用样本:未公开

您在进行分析时是否有权访问漏洞利用样本?是的

漏洞

Bug 类别:类型混淆

漏洞详细信息:

当在设备驱动IOCTL_FRAMESERVER_PUBLISH_RX程序上执行 IOCTL时mskssrv,会执行一个调用,而FSRendezvousServer::PublishRx()该调用又会调用FSStreamReg::PublishRx()将获取the 字段FSStreamReg::PublishRx()中的任何内容并将其用作进一步的对象,只要它是有效对象。FsContext2FILE_OBJECTFsStreamReg

攻击者可以在同一设备句柄上IOCTL_FRAMESERVER_PUBLISH_RX使用IOCTL,这会将字段初始化为不同类型(即 类型)的对象IOCTL_FRAMESERVER_INIT_CONTEXTFsContext2FsContextReg

FSStreamReg::PublishRx()对它认为是FsStreamReg对象的对象执行多项操作,其中一些操作会导致可利用的场景,例如越界写入。

其他 3 个 IOCTL 中也存在类似的漏洞:

  • IOCTL_FRAMESERVER_PUBLISH_TX

  • IOCTL_FRAMESERVER_CONSUME_TX

  • IOCTL_FRAMESERVER_CONSUME_RX

所有这些都通过 CVE-2023-36802 标识符引用。

补丁分析:

在补丁之前,FSRendezvousServer::PublishRx()FSRendezvousServer::FindObject()在调用之前调用FSStreamReg::PublishRx()仅当FSRendezvousServer::FindObject()返回TRUE,FSStreamReg::PublishRx()时才被调用。但是,FSRendezvousServer::FindObject()不会检查对象的类型。

该补丁更改了FSRendezvousServer::FindObject()检查对象的类型字段是否专门设置为2,否则返回FALSEFsStreamReg构造对象时(在 中) ,类型字段设置为 2 FSStreamReg::FSStreamReg()此外,FSRendezvousServer::FindObject()还被重命名为更合适的名称FSRendezvousServer::FindStreamObject()

关于如何发现此漏洞的想法(模糊测试、代码审计、变体分析等)

该错误可以通过手动代码审核或模糊测试来发现。查看上面的概念证明,两个 IOCTL 与相对简单的输入缓冲区的组合会触发崩溃。Valentina Palmiotti 通过手动代码审核发现了此漏洞,如她的博客文章中所述

(历史/现在/未来)错误的背景:

  • 2023 年 6 月 16 日:mskssrv.sysSynacktiv 在 Pwn2Own 2023 上使用的另一个权限提升漏洞 CVE-2023-29360 已被修补并公开披露。尽管在同一驱动程序中,CVE-2023-29360 与 CVE-2023-36802 截然不同。

  • 2023 年 9 月 12 日:CVE-2023-36802 已修补并公开披露,据报道已在野外发现。

  • 2023 年 10 月 10 日:Valentina Palmiotti发布了CVE-2023-36802 及其利用的详细信息。

漏洞利用

(此处定义了术语利用原语”“利用策略”“利用技术”“利用流程”。)

利用策略(或多个策略):

  • 通过众所周知的技术泄露相关内核对象的地址NtQuerySystemInformation

  • 创建内核池布局,以便将来的FSContextReg分配落在被攻击者控制的数据包围的洞中。

  • 分配一个FSContextReg对象(通过IOCTL_FRAMESERVER_INIT_CONTEXTIOCTL)。

  • 对对象执行越界操作FSContextReg(通过IOCTL_FRAMESERVER_PUBLISH_RX),这将执行一些有趣的写入并最终将 的 设置PreviousModeKTHREAD0。

  • 在内核地址上使用NtReadVirtualMemoryNtWriteVirtualMemory将系统令牌复制到EPROCESS当前进程的 。

  • 清理。

  • 产生感兴趣的命令,例如cmd.exe.

利用流程:

根据 Windows 版本的不同,分析的野生样本中存在两种不同的漏洞利用流程。这是因为根据 Windows 版本:

  • 代码FSStreamReg::PublishRx略有不同,即最新版本包含对对象字段之一的mskssrv.sys调用,而旧版本则不包含ObfDereferenceObjectFsStreamReg

  • 对象的结构布局FsStreamReg略有不同。这对于漏洞利用流程中引起的副作用很重要。

由于较新的mskssrv.sys版本包含对 的方便调用ObfDereferenceObject,因此它将使用该调用将PreviousMode字段直接递减至 0。我们将首先查看此漏洞利用流程。

由于旧mskssrv.sys版本不包含方便的ObfDereferenceObject调用,因此利用流程有点复杂。它会破坏 CLFS 特定的对象,以通过 vtable 调用来调用内核小工具。

无 CLFS 的漏洞利用流程

  • mskssrv通过调用打开设备KsOpenDefaultDevice

  • 通过以下方式泄漏一些所需的内核地址NtQuerySystemInformation(SystemExtendedHandleInformation, ...)

    • 当前KTHREAD地址(以及当前PreviousMode地址)

    • EPROCESS系统进程和当前进程的地址(以及它们各自的Token地址)

    • FILE_OBJECTmskssrv设备文件句柄的地址

  • 使用众所周知的NtFsControlFile使用 fsctl 代码 0x119ff8进行调用的命名管道技术,将大小为 0x80 的对象(不包括 0x10 字节池标头)喷射到池中。

  • 关闭一些管道,在泳池喷雾上打孔。

  • 调用IOCTL_FRAMESERVER_INIT_CONTEXTioctl:

    • FsInitializeContextRendezVous()来电FSRendezvousServer::InitializeContext()

    • FSRendezvousServer::InitializeContext()分配一个FsContextReg大小为0x78字节的对象,并将 中的FsContext2字段设置为FILE_OBJECT指向该对象。FsContextReg对象将占据先前创建的孔的位置。

  • 重新填满剩余的孔。

  • 在单独的线程中调用IOCTL_FRAMESERVER_PUBLISH_RXioctl 

    • FSRendezvousServer::PublishRx()随后将调用和FSStreamReg::PublishRx()

    • FSStreamReg::PublishRx()将期望FsStreamReg字段中存在一个FsContext2大小为 0x1d8 字节的对象,而实际上FsContextReg存在一个较小的对象,与受控数据相邻。

    • FSStreamReg::PublishRx()然后将调用ObfDereferenceObject()从相邻对象中取出的超出范围的字段。攻击者将PreviousMode当前线程的地址放在那里。这会将主线程的 递减PreviousMode至 0。此时,攻击者可以从主线程调用内核地址上的NtReadVirtualMemory和。NtWriteVirtualMemory

    • 如果不加以处理,FSStreamReg::PublishRx()现在将调用KeSetEvent另一个越界字段,该字段与ProcessBilled相邻对象(不受攻击者控制)的池标头中的字段一致。由于这是一个无效的指针,它会对系统进行错误检查。为了防止这种情况,攻击者保持FSStreamReg::PublishRx()锁定在 while 循环中。这是通过伪造自引用链表条目来实现的。FSFrameMdlList::MoveNext将继续返回相同的列表条目。列表条目被放置在用户模式中,因此该漏洞可以根据需要打破这个 while 循环(见下文)。

  • 同时在主线程中:

    • 尝试NtReadVirtualMemory在循环中使用读取系统进程令牌,直到成功。PreviousMode在另一个线程中被覆盖后,这将成功。

    • 使用将系统令牌写入EPROCESS当前进程的NtWriteVirtualMemory

    • FsContext2从 中读取该字段的值FILE_OBJECT即可获取该对象的地址FsContextReg

    • 读取(以便以后恢复)并将ProcessBilled相邻池块标头之一覆盖为 NULL,因此KeSetEvent不会使系统崩溃。

    • FSStreamReg::PublishRx()通过更改自引用列表条目来打破当前锁定的 while 循环。FSStreamReg::PublishRx()现在将继续但不会调用,KeSetEvent因为该字段为 NULL。

    • 等待 FSStreamReg::PublishRx()另一个线程完成。

    • 将损坏的ProcessBilled字段恢复为其原始值。

    • 增加当前的引用计数EPROCESS

    • 将 重置PreviousMode为 1。

    • 启动感兴趣的命令,例如cmd.exe.

使用 CLFS 来利用流程

在较旧的系统上,FSStreamReg::PublishRx不包含对ObfDereferenceObject这是不幸的,因为ObfDereferenceObject这是一个非常容易减少PreviousMode.

但是,FSStreamReg::PublishRx()仍然会调用FSFrameMdl::UnmapPages()从相邻(喷射的)对象中获取的超出范围的地址,这将在超出范围的地址上进行一些有用的写入:

  • 在该地址的偏移 0xc8 处写入 QWORD 0

  • 在该地址的偏移 0x10 处写入 DWORD 2

该漏洞如何利用这一点?

  • 以与无 CLFS 漏洞利用流程相同的方式泄漏所需的内核地址。

  • 创建一个 CLFS 日志文件,打开它并泄漏其内核地址(使用NtQuerySystemInformation(SystemExtendedHandleInformation, ...))。

  • 解决一些nt内核小工具:PoFxProcessorNotificationIoSizeofWorkItemRtlClearBit

  • CClfsContainer在 0x1000000 处伪造一个假对象,在 0x1000800 处伪造一个虚函数表。

  • 在 0x1000400 处伪造一个假的BitMapHeader,并使用指向该地址的位图指针PreviousMode

  • 喷射池(再次使用NtFsControlFile),但精心制作的对象现在包含 CLFS 日志文件的内核地址 + 0x2c9。

  • 创建孔,分配FsContextReg孔中的对象并重新填充剩余的孔,就像以前一样。

  • 触发FSStreamReg::PublishRx()FSFrameMdl::UnmapPages()将在该地址读取越界时调用,因此写入:

    • QWORD 0 位于内存中 CLFS 日志文件开头的偏移量 0x2c9+0xc8=0x391 处

    • DWORD 2 位于内存中 CLFS 日志文件开头偏移量 0x2c9+0x10=0x2d9 处

  • 调用CreateLogFile最终会调用CClfsBaseFilePersisted::CheckSecureAccess

    • ClfsBaseFilePersisted::CheckSecureAccess将使用偏移量 0x398 处的 DWORD 作为距日志块头(大小为 0x70)末尾的偏移量来查找对象CLFS_CONTAINER_CONTEXT(通过调用CClfsBaseFile::GetSymbol())。但是 QWORD 写入损坏了该 DWORD 的最低有效字节,这使得偏移量从 0x1460 更改为 0x1400。因此,现在 CLFS 日志文件+0x70+0x1400 中的任何内容都将被解释为CLFS_CONTAINER_CONTEXT对象,即攻击者控制的数据。CClfsContainer在该对象的偏移量 0x18 处,取消引用指向对象的指针。该漏洞利用程序将地址 0x1000000 作为指针,之前它在那里准备了一个伪造的CClfsContainer对象。

    • CLFS!CClfsBaseFilePersisted::CheckSecureAccess然后将调用该对象的 vtable 中的第一个函数(在正常情况下CClfsContainer::AddRef),并将对象本身作为第一个参数传递。该漏洞利用将该nt!PoFxProcessorNotification函数放置在伪造的 vtable 中。(请注意,CLFS 驱动程序中有 CFG,因此该漏洞必须使用允许的函数地址作为小工具。)

    • nt!PoFxProcessorNotification将取消引用其参数的几个地址,并使用这些地址中的另一个作为参数来调用这些地址之一。所以现在漏洞利用控制了被调用的函数及其第一个参数。该漏洞利用程序选择nt!RtlClearBit要调用的函数。

    • nt!RtlClearBit需要 2 个参数:指向位图标头的指针(包含指向位图本身的指针)和要清除的位数。回想一下,该漏洞利用程序准备了一个伪造的位图标头,其中有一个指向该地址的位图指针PreviousMode第二个参数 - 要清除的位数 - 不受控制,但rdx可以方便地设置为 0。nt!RtlClearBit因此将将该PreviousMode字段设置为 0。

    • 为了稳定性,该漏洞利用程序准备了第二个 vtable 条目nt!IoSizeofWorkItem- 它除了设置之外什么也不做eax- 因为稍后CClfsBaseFilePersisted::CheckSecureAccess会调用它认为的内容CClfsContainer::Release

  • 将系统进程令牌复制到当前的EPROCESS.

  • 恢复 CLFS 日志文件中原始的 0x1460 偏移量。

  • 恢复PreviousMode为1。

  • 启动感兴趣的命令,例如cmd.exe.

请注意,在这个版本的mskssrv.sys漏洞利用流程中,漏洞利用程序不必处理尴尬的KeSetEvent调用。原因是KeSetEvent旧版本中传递给字段的偏移量mskssrv.sys并不落在池块标头内,而是落在受控喷射数据中,并以这种方式设置为 NULL。

与 Valentina Palmiotti 的漏洞利用存在显着差异

了解上述自然利用与 Valentina Palmiotti 在她的博客文章中描述的利用之间的差异是一个有趣的练习

Valentina 的漏洞利用基于最新mskssrv.sys版本。可以从ObfDereferenceObject屏幕截图中是否存在呼叫来推断。因此,让我们将她的漏洞利用与“无 CLFS 漏洞利用流程”进行比较。

  • Valentina 使用调用提供的“write 2 where”原语FSFrameMdl::UnmapPages(),“与 I/O 环技术结合”。我们分析的漏洞利用了旧mskssrv.sys版本的原语(与 CLFS 技术结合),但ObfDereferenceObject()在新mskssrv.sys版本中使用了调用提供的“递减位置”原语。

  • Valentina 结合信息泄漏进行了一些更复杂的池整理,FSStreamReg::GetStats以防止稍后的KeSetEvent调用因无效指针而崩溃。这里分析的漏洞使用了不同的解决方案:它FSStreamReg::PublishRx从单独的线程触发该函数,并将其保持在锁定的 while 循环中(在用户模式下使用自引用链表条目),从而阻止调用到达KeSetEvent一旦它具有内核读/写,它就会将触发 的字段更改KeSetEvent为 NULL,然后更改自引用链表条目,以便 while 循环中断。这意味着KeSetEvent呼叫将被跳过。(之后它恢复会触发调用的字段,KeSetEvent因为它是池块中的拥有进程 EPROCESS)。

相同漏洞利用流程的已知案例:

正如Zscaler 的博客文章所述,野外利用的 CVE-2022-37969 CLFS 漏洞遵循非常相似的利用流程

漏洞利用链的一部分?此漏洞很可能被用作独立的本地权限升级。

下一步

变异分析

变体分析的领域/方法(以及原因):鉴于此漏洞以及 CVE-2023-29360 相对简单的性质,更多的模糊测试和代码审核可能会mskssrv.sys产生更多错误。

发现的变种:不适用

结构改进

有哪些结构性改进,例如消除 bug 类、防止引入此漏洞、减轻漏洞利用流程、使此类漏洞更难利用等方法?

杀死 bug 类的想法:

CastGuard可能会捕获此错误,因为看起来(基于它们的 vtable)FsStreamRegFsContextRegtype 都派生自同一个FsRegObject类。

减少漏洞利用流程的想法:

  • MTECHERI不会捕获类型混淆,但会捕获类型混淆导致的越界访问。

  • 在无 CLFS 漏洞利用流程中FSStreamReg::PublishRx取消引用假指针时,SMAP将捕获用户模式访问。FSFrameMdl在 CLFS 漏洞利用流程中,SMAP 将捕获CClfsContainer用户模式下的虚假对象 vtable 访问。

  • 通过调用消除内核地址泄漏NtQuerySystemInformation

其他潜在的改进:

不适用

0day检测方法

类似 0day 的潜在检测方法有哪些?这意味着是否有任何关于如何将此漏洞或类似漏洞检测为 0day 的想法?

  • 使用的漏洞利用技术的静态签名(例如使用 Yara)。

  • 根据有趣的动态信号分析样本,例如NtQuerySystemInformation使用SystemExtendedHandleInformation参数的调用。


阅读原文可通过点击阅读原文



感谢您抽出

野外0day - CVE-2023-36802:Microsoft 流服务代理权限提升漏洞

.

野外0day - CVE-2023-36802:Microsoft 流服务代理权限提升漏洞

.

野外0day - CVE-2023-36802:Microsoft 流服务代理权限提升漏洞

来阅读本文

野外0day - CVE-2023-36802:Microsoft 流服务代理权限提升漏洞

点它,分享点赞在看都在这里


原文始发于微信公众号(Ots安全):野外0day - CVE-2023-36802:Microsoft 流服务代理权限提升漏洞

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年10月14日14:20:31
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   野外0day - CVE-2023-36802:Microsoft 流服务代理权限提升漏洞http://cn-sec.com/archives/2112044.html

发表评论

匿名网友 填写信息