Windows WDM 驱动漏洞挖掘(下) - 嘶吼 RoarTalk – 网络安全行业综合服务平台,4hou.com

Windows WDM 驱动漏洞挖掘(下)

luochicun 漏洞 2022-06-29 11:55:00
187439
收藏

导语:本文,我们介绍了如何开始寻找WDM驱动程序中的漏洞。最重要的事情就是获得设备句柄。

接上篇Windows WDM 驱动漏洞挖掘(上)

蓝屏现象

简而言之,我们第一个真正的漏洞示例是微软Azure VFP扩展或vfpext.sys。故事从驱动程序的ioctl调度函数开始。在一些变量初始化之后,它调用一个方法来验证用户模式参数,然后调用一些内部逻辑。

12.png

图12-由Ida Pro反编译的SxStartDeviceIoControl函数,从vfpext.sys的disptachIoctl函数调用

我们真正拥有的是一个简单的代码,它执行以下操作:

从宏iogetcurrenttirpstacklocation (IRP)中获取一个指向CurrentStackLocation的指针;

验证缓冲区长度是否超过0x218;

以安全的方式创建一些Unicode字符串;

通过调用我们不关心的SxFindContextByName来进行查找操作;

问题是驱动程序在任何地方都不会检查给定的 ioctl IRP->AssociatedIrp 是什么。例如,SystemBuffer 是一个有效地址;它假定缓冲区的地址是有效的。

然而,回顾图 4,我们可以假设驱动程序期望获得一个带有TransferType的ioctl代码为METHOD_BUFFER或METHOD_IN_DIRECT或METHOD_OUT_DIRECT,因为它从IRP- bb0 AssociatedIrp.SystemBuffer读取输入缓冲区。

但是,如果它是 METHOD_NEITHER,那么 IRP->AssociatedIrp.SystemBuffer 对 IoManager 没有任何意义,它会将其设置为零,因为它会填充 IRP->Parameters.DeviceIoControl.Type3InputBuffer。

接下来,调用 SxInitUnicodeStringSafe ,我认为它应该是内核方法 RtlInitUnicodeString 的更安全版本;第二个参数是 SystemBuffer+8,即源字符串。

13.png

图13-Ida Pro 反编译的 SxInitUnicodeStringSafe 函数,接收 SystemBuffer,它可以指向无效内存

因此,SystemBuffer地址的地址将是0x10 = (0x0+sizeof(wchar_t *)+8)。因此,在调用RtlStringCbLengthW(顾名思义,它计算长度)时,将使用指向无效地址的系统缓冲区。它包含如下代码:

14.png

图14-这里发生了指针解引用

当 *SystemBuffer 解引用发生时,你解引用了一个无效地址,并且内核不会执行空指针。

15.webp.jpg

图15-只是由漏洞触发的蓝屏

这个漏洞检查只需要两行代码就可被触发:

16.png

图16-导致漏洞检查

在这种情况下,我们的漏洞是不可利用的,除非来自有限用户的 DoS。此漏洞也可能由受限用户和应用程序沙箱中触发,因为对设备没有任何保护。因此,每个人都可以得到一个句柄和BSoD。直到今天,这个漏洞还没有被修复; MSRC 的回应是:“我们已经完成了调查,并确定此报告是一个中等严重性的拒绝服务漏洞,很遗憾,这意味着它不符合我们在安全更新中提供服务的标准。”微软的回答很有趣,因为它不仅仅是一个常规的 DoS,而是一个系统的 DoS。从 CVSS 的角度来看,它应该是 7.3。除此之外,修复非常简单;在盲目使用之前检查ioctl代码,这将导致正确使用IRP的缓冲区。

内存漏洞

在了解了拒绝服务攻击后,我们应该继续讨论一个特殊的、隐秘的漏洞类。信息泄漏是指内核内存泄露给用户模式。它不会触发漏洞检查或任何异常,因此在驱动程序开发的常规管道中很难找到。与常规内存池漏洞相比,你也无法通过驱动程序验证程序找到它。

自Windows Vista发布以来,微软引入了KASLR缓解措施,这使得 Windows 内核开发非常具有挑战性。 KASLR是内核ASLR,它在启动时随机化驱动程序、模块、内核对象的基地址。这样,你就不能像过去那样滥用任意写入原语了。那时,你可以找到一个可以被内核调用的地址,比如HalDispatchTable,然后放置一个恶意的shellcode,可以进行令牌窃取,例如,可以由用户模式进程触发。因此,任意写入足以执行代码,或者你可以解 SMEP 作为记录。

如今,当地址被随机化时,人们不知道在哪里分配 shellcode,因为 HalDispatchTable 是在每次启动时随机化的。

漏洞利用编写者变得更聪明,并且很快就明白你可以调用 NtQuerySystemInformation 或 EnumDeviceDrivers 来获取 ntoskrnl 的基地址。这样,我们就绕过了 KASLR,使任意写入对于 LPE 来说已经足够了。当然,只有当被控制的进程具有中等完整性(大多数进程都具有中等完整性)时,才可以调用这些API;浏览器不是。除此之外,使用 PageEntry 攻击覆盖 HalDisptachTable 是无效的,因为 HVCI 等新的缓解措施仍然不是大多数 Windows 设备上的默认设置。

或者,可以直接从系统进程读取数据。例如,可能会读取完全加载到内存中的 SAM 文件。现在,假设你可以从内存中提取它。在这种情况下,你可能可以破解哈希并找到管理员密码,从而使你可以悄悄地实现完全的权限提升。由于你并没有真正接触磁盘,因此不会触发防攻击。

那么信息泄漏是什么样的呢?它主要以获取某些敏感内核对象的内核指针的形式出现,但它也可能看起来像公开未初始化的内核内存,例如在 RtsPer.sys Realtek 驱动程序中:

17.png

图17-rts_ctrl_dump_mem_log 包含严重的信息泄漏漏洞

乍一看,这里提供的代码似乎很可靠;驱动程序使用 METHOD_BUFFERED(因为它以 00 结尾)来传输数据,所以用户数据不能从它的缓冲区分离出;缓冲区长度是可信的(详见图11和上面的内容)。然而,即使使用METHOD_BUFFERED,它也不能保证代码无漏洞。

查找信息泄漏漏洞的最简单方法是查看返回的数据及其长度。由于我们处理的是 METHOD_BUFFERED,因此返回的数据是通过 SystemBuffer 进行的,并且 IRP->IoStatus.Information 指定了大小(不仅针对此传输类型)。由于IoManager 并没有在输入缓冲区的副本之外初始化系统缓冲区。换句话说,如果 OutputBufferLength > InputBufferLength,则 SystemBuffer 的剩余部分是未初始化的数据。因此,驱动程序编写者的工作是初始化系统缓冲区并返回它的正确长度。

图16中的SystemBuffer没有被初始化为零。我们没有检查输入/输出缓冲区的长度,这是我们完全可以控制的。另外,通过查看else块,我们可以检查漏洞的逻辑:

18.png

图18-不正确的缓冲区大小分配

事实证明,通过进入 else 块,你从内核中得到了 0x107c0 字节长度的内核数据。更准确地说,IoManager 复制了 OutputBufferLength 和 InputBufferLength 之间的增量:

OutBufferLength = 0x107c0,InputBufferLength = 1

因此,我们从System进程的内存空间中返回0x107c0,大约有64k的未初始化数据,允许你读取SAM文件的内容,查找系统的内核基地址以及更多内容。此外,你可以根据需要多次触发此行为,因为它不会引发异常。

漏洞利用代码非常简单,我们唯一担心的是找到设备名称,因为它是一个自动生成的数字,但你可以暴力破解它,因为只有大约 0x200 选项,类似于图 2 中所示的方式。我们的漏洞利用代码可以执行以下操作:

打开 RtsPer.sys 公开的设备的句柄;

分配一个大小为 0x107c0 的缓冲区;

调用 DeviceIoControl;

将内核数据写入文件;

19.png

图19-在 RtsPer.sys 中滥用信息泄漏的简短代码

这只是我们在RealTek 最近修复的此驱动程序中发现的众多漏洞之一。

似乎这些漏洞很容易检测,也相对容易修复,你需要做的就是在 else 块中将 IRP->IoStatus.Information 更改为零。此外,你可以通过改变设备的权限来防止所有这些漏洞,只允许管理用户或以上用户与它交互。

第三类漏洞

我们要研究的第三种类型的漏洞会导致完全权限提升,除非它是从低完整性进程中执行的。在内核中发现的一个更好且通常更有用的漏洞是任意写入。这个原语允许你在内核中的任何地方进行写入,这可能会让你覆盖你的访问令牌。

如果你不记得或不熟悉 Windows 操作系统,每个进程都有一个对应的内核对象,称为EPROCESS。每个 EPROCESS 对象都有一个代表其安全上下文的访问令牌。 System 进程实际上是内核,自然拥有操作系统中最强大的访问令牌。由于每个 EPROCESS 都驻留在内核空间中,我们不能随意更改 EPROCESS 的访问令牌,我们必须从内核本身开始。但假设我们有一个任意的写入原语,则可以更改任何进程的访问令牌,并将其替换为系统的进程访问令牌,这种技术被称为纯数据( data-only )攻击。与内存攻击技术相比,我们不会损坏任何页面池条目,这些条目容易受到 kCFG/HVCI/HyperGuard 等新缓解措施的影响。

假设是寻找漏洞的关键

找到任意写入漏洞是很重要的,但对于完全的本地权限升级来说还不够。

假设HVCI开启:

无论你的完整性级别如何,内核中的任意写入对于 LPE 来说都是不够的;你还需要一个读取原语来启用令牌中的正确权限。

如果HVCI关闭:

完整性级别为中(最常见),可以调用 EnumDeviceDrivers 和 NtQuerySystemInformation 来获取内核的基地址,这应该允许你在某些页面条目损坏的情况下覆盖 HalDisptachTable/SMEP,这对 LPE 来说已经足够了。

完整性级别低或不受信任(主要是浏览器),你不能调用上面提到的 API,因此,没有适合你的内核基地址。必须有一个额外的 LPE 原语。

任意写入漏洞是什么样的?通常,它涉及内存的解引用和受控缓冲区的复制操作,它可以有多种形式,比如memcpy/memmove ,任意指针解引用等,让我们看看一些比较流行的:

20.png

图20-在一个我们无法评论的驱动程序中发现的普通任意写入示例

假设我们的驱动程序使用METHOD_NEITHER作为传输类型,并且我们看到输入或输出缓冲区加载到寄存器中,这是一个任意指针解引用。此时,寄存器RAX和RCX都指向用户模式缓冲区。当然,你可以完全控制它们的内容,并且你事先知道它们在内存中的位置,因为你已经创建了它们。由于我们可以完全控制寄存器,我们可以写入 RAX 指向的内存地址,RCX 指向的 shellcode 地址。换句话说,我们有一个 write-what-where 类型的漏洞或任意写入。

如果我们有METHOD_NEITHER传输类型,何时使用缓冲区以及以何种方式使用。图 19 中的这种模式有点少见,但仍不时出现。

攻击功能的来源

谈到任意写入漏洞时,我们不能不提到一个关键函数,这个函数通常是其根源:不正确地使用任何一个memcpy例程。驱动程序开发人员使用的memcpy函数或宏RtlCopyMemory在设计上是不安全的。它不处理越界写入或内存重叠,源或目标位于同一内存中。有一个函数处理内存重叠,它是memmove或宏rtlmovmemory。这仍然不能解决越界写入的问题。此外,任何一个参数的不正确使用都可能导致漏洞。

让我们检查一个驱动程序中一个很容易看到的漏洞,该漏洞应该是无名的:

21.webp.jpg

图21-有问题的驱动逻辑,看起来很糟糕

这里显示的反编译代码有点像Ida,这通常会使我们的工作容易得多,并且在区分IO_STACK_LOCATION结构成员(如果它们是union)时犯了很多错误。乍一看,这会给我们带来一些困惑。让我们忽略 ioctl 0x26DC03 出现的漏洞,即不正确使用 ProbeForRead,甚至不使用缓冲区。幸运的是,熟悉内核内部的每个人都可以看到事情看起来很奇怪:

22.png

图22-更正变量名称和类型

经典的可怕的漏洞

为了使它看起来更好,我们按ALT-Y来选择IO_STACK_LOCATION的正确联合成员的正确字段;让我们看看它是什么样的:

23.webp.jpg

图23-ida应该如何表示调度函数的反编译输出

更改后,我们可以看到反编译的输出看起来像普通的 C。我们对 memmove 进行了几次调用,这是我在查看调度函数时建议做的第一件事。SystemBuffer似乎是一个由源字段、大小字段和目标字段组成的结构,它们被盲目地提供给memmove方法,我称之为最好的安全性。我们可以看到有三个对memmove的调用,ioctl 0x26DC04表示在内核中对任意内容进行写入操作。相反,ioctl 0x26FC08允许从内核读取,因为它稍后将被分配给SystemBuffer(不在图22中)并返回给用户。总而言之,该驱动程序提供了所有读/写功能,这允许攻击者通过系统令牌升级为特权帐户。当然,HVCI与上述示例无关。唯一可用的是这个驱动程序不能从普通用户权限级别访问,只能从管理员和更高级别访问。因此,它限制了升级目的的有用性。然而,这个驱动程序带有灵活内核原语的签名驱动程序,仍可以被利用。

修复这个驱动程序意味着重写调度例程的整个逻辑。供应商没有这样做,而是改变了设备的ACL,以防止非管理员用户干扰它。

本文,我们介绍了如何开始寻找WDM驱动程序中的漏洞。最重要的事情就是获得设备句柄。接着,我们继续分析IRP_MJ_DEVICE_CONTROL的调度例程,然后查看imanager如何处理用户数据。之后,我们讨论了一些漏洞以及如何找到它们并利用它们。

本文翻译自:https://www.cyberark.com/resources/threat-research-blog/finding-bugs-in-windows-drivers-part-1-wdm如若转载,请注明原文地址
  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论

 
本站4hou.com,所使用的字体和图片文字等素材部分来源于原作者或互联网共享平台。如使用任何字体和图片文字有侵犯其版权所有方的,嘶吼将配合联系原作者核实,并做出删除处理。
©2022 北京嘶吼文化传媒有限公司 京ICP备16063439号-1 本站由 提供云计算服务