2019最有意思的五大 ZDI 案例之:通过调色板索引实现 Win32k.sys 本地提权漏洞 (下)...

 聚焦源代码安全,网罗国内外最新资讯!

编译:奇安信代码卫士团队

本文是趋势科技 ZDI 项目推出的第二届年度最有意思的五大案例系列文章之一。他们从1000多份安全公告中遴选出这些案例,奇安信代码卫士团队将一一翻译,供大家参考。本文说明的是由 Marcin Wiazowski 提交的存在于 Windows 内核模式驱动器中的一个本地提取漏洞(下)。

现在,我们来起草一下完整的利用算法:

1、确保整个内存范围从 0x30000000 到0x30ffffff 是可写的且填充了0。

2、创建一对足够相近的调色板:PaletteLO和PaletteHI。

3、分配一个空页面并准备虚假的POOL_DESCRIPTOR。其内容应该能够导致覆写PaletteLO的_PALOBJ内核结构的 cEntries字段。写入的值虽然未知但应该保证至少是 0x10000。

4、通过上述算法1找到并 hook任何打印机驱动 DLL,但跳过第8步。Hook 驱动的DrEnablePDEV函数。

5、调用 gdi32.dll!EngCreatePalette以创建具有256个条目的模板调色板,它将被成为PaletteSRC。

6、下指令将被 hook 的DrvEnablePDEV 函数返回 PaletteSRC,其中ulNumColors参数等于514,在flGraphicsCaps字段中设置GCAPS_PALMANAGED标记。

7、调用 gdi32.dll!CreateDCA/W 创建一个内部设备调色板,其ppalThis字段指向某个0x30XXXXXX 地址。该设备调色板将被称为PaletteDEVICE。PaletteSRC 的引用计数器将变为1。

8、扫描内存范围 0x30000000 到0x30ffffff并找到虚假的用户模式下的_PALOBJ 结构。

9、调用gdi32.dll!DeleteDC。PaletteSRC的引用计数器将变为0,这样我们就能在第15步将其删除。

10、调用 gdi32.dll!EngCreatePalette,创建另外一个模板调色板,将被称作 PaletteHELPER。

11、指令被 hook 的DrvEnablePDEV函数返回PaletteHELPER。这次,除了范围内的一个ulNumColors值,应该在 flGraphicsCaps字段中设置GCAPS_PALMANAGED 标记。

12、调用gdi32.dll!CreateDCA/W。PaletteHELPER的引用计数器将变为1,而这正是我们需要的。

13、在我们虚假的、用户模式下的_PALOBJ 结构中,将 BaseObject 字段中包含的句柄值设置为 PaletteHELPER。同时将 ppalThis 字段设置为指向用户模式下 _PALOBJ结构的开头。

14、在用户模式下的 _PALOBJ 结构之前准备一个虚假的池标头以及另外一个在其之上的池标头。

15、调用PaletteSRC上的gdi32.dll!EngDeletePalette。由于hSelected 字段位 PaletteSRC 的_PALOBJ内核结构引用 PaletteDEVICE 中,因此也将删除PaletteDEVICE。由于PaletteDEVICE的ppalThis指针指向用户内存中虚假的_PALOBJ 结构,因此这个用户地址将被传递给win32k.sysExFreePoolWithTag。另外由于我们在虚假的_PALOBJ 之前和之后创建了虚假的池标头,因此我们虚假的空页面池描述符将被ExFreePoolWithTag使用。这样,PaletteLO 的_PALOBJ 内核结构中的cEntries 字段将被至少为0x10000的值覆写。

16、调用 PaletteLO 上的 gdi32.dll! SetPaletteEntries,通过任意所选地址覆写 PaletteHI的_PALOBJ 内核结构中的pFirstColor指针。

17、调用PaletteHI 上的gdi32.dll! SetPaletteEntries,通过任意所选值覆写任意所选地址。

现在,我们就有了一个 write-what-where 的原语。接下来将说明如何选择覆写的最终目标。

选择覆写的内存位置

进程访问令牌是不错的覆写选择。

访问令牌即包含进程或县城安全上下文的一个内核对象,包括开启进程或线程的用户账户身份以及该用户的权限。目前定义的权限有34种:

这些权限可能是显示 (present) 也可能是缺失 (absent) 状态,也有可能是启用或禁用状态。在令牌中显示的权限可能会被禁用,之后再次被启用;不过也有可能被删除,因此变为缺失状态且无法再显示,因此进程无法提权。只有在创建令牌的过程中才有可能让权限显示,而且只有为持有SeCreateTokenPrivilege和SeSecurityPrivilege的高权限系统进程才能创建令牌。如果进程有权限创建令牌,则可以创建具备它想要的任意权限的令牌。这类权限随后可被用于以任意用户身份启动进程。

要利用该漏洞,必须获得令牌结构的内核地址。为此,首先必须通过调用advapi32.dll!OpenProcessToken来获得令牌句柄。之后可使用内部的 API ntdll.dll!NtQuerySystemInformation  获得该令牌结构的内核地址。简化之后的令牌结构如下:

Privileges_Present字段是一个64位的位字段,它决定的是显示和缺失权限。目前只定义了2到35的权限,因此这有这些位处于正常使用状态。

Privileges_Enabled字段是一个64位的位字段,它决定的是哪些显示权限是启用的,哪些是禁用的。

要提升权限,我们将把PaletteHI的pFirstColor 字段设置为指向字段TOKEN.Privileges_Present。然后我们调用 PaletteHI 上的gdi32.dll!SetPaletteEntries以写入四个连续的索引从0到3的调色板条目。这些调色板条目的新内容应该包含所有设为1的位。它将使所有的权限为显示和启用状态。设置未定义的权限并不会引发任何问题,尽管可通过使用advapi32.dll!AdjustTokenPrivileges将其删除。

现在,我们拥有所有可能的权限,但仍然无法做某些事情,因为我们仍然是一个标准用户。下一步就是使用我们现在拥有的SeCreateTokenPrivilege 和SeSecurityPrivilege权限。通过使用这些权限,我们可以使用未记录的 API ntdll.dll!NtCreateToken来创建任意想要创建的令牌。事实上,我们可以创建一个令牌,表示具有所有显示权限的最强大的 SYSTEM 用户。操作系统本身使用的是 SYSTEM 令牌,但它的某些权限是缺失状态。之后,拥有了最强大的令牌以及SeAssignPrimaryTokenPrivilege权限,我们可以使用advapi32.dll!CreateProcessAsUserW来创建能够存在的最强大的进程。

由于我们还具有一个SeTcbPrivilege,我们可以更改新建令牌的SessionId字段。默认情况下它被设置为0,因此通过该令牌创建的进程像系统服务一样起作用而且无法和桌面交互。将令牌的SessionId 设置为某些已登录用户的SessionId之后,新创建的进程可以在用户桌面画窗口。我们可以在演示过程中这样做,尽管并不需要占用操作系统。

64位系统上的利用

在64位系统,palDst -> ppalThis指针是一个8字节值。通过用 0x30 覆写其最高字节,我们将它设置为一个格式为 0x30XXXXXX’ XXXXXXXX的值。当前64位架构的硬件实现仅支持48位寻址,虚拟地址的最高16位(位48至63)必须是位47的副本。因此,最高的16位必须为全0或全1。通过将最高字节设置为 0x30,我们就打破了这个规则,从而引发例外和崩溃。这就意味着在64位系统上,该漏洞仅可用于拒绝服务。

这个漏洞可能也可用于装有 Windows Server 的Itanium 计算机上提升权限。

Windows 8 及以上版本中的变化

根据反编译的 win32k.sys(Windows8 和 8.1)或者win32kbase.sys(Windows 10),CreateSurfacePal 函数中的漏洞并不存在。从用户模式下传递的值已被正确验证。

另外一点值得注意的是,自 Windows 10 版本1607(Redstone1 “AnniversaryUpdate”)起,GDICELL. KernelAddress 字段不再持有内核内存的直接指针。有兴趣的读者可参考如下链接,详细了解:

https://labs.f-secure.com/archive/a-tale-of-bitmaps/

补丁

微软在今年10月份修复了这个漏洞并授予其编号 CVE-2019-1362。随附的安全公告只是简述为通过“更正 Windows 内核模式驱动处理内存中对象”的方法修复了该问题。该修复方案极有可能存在从 Windows 8 向后移植的行为,因为该版本的操作系统并不受影响。

结论

再次感谢 Marcin Wiazowski 提供了如此全面且良好的提权分析过程。当回顾2019年时,我们很容易就能得出该bug(及其分析)为何能独树一帜。

这类漏洞通常结合使用其它漏洞来伪造完整的利用链。最近我们看到类似的本地提权漏洞结合一个 Chrome 释放后使用漏洞瞄准了韩国新闻站点。尽管本地提权漏洞本身的严重程度并非“严重 (critical)”级别,但和其它远程代码执行漏洞结合使用可形成有效攻击。

后续奇安信代码卫士团队将为您奉上另外的 Top 5 有意思案例,敬请期待。

推荐阅读

2019最有意思的五大 ZDI 案例之:通过调色板索引实现 Win32k.sys 本地提权漏洞(上)

原文链接

https://www.zerodayinitiative.com/blog/2019/12/16/local-privilege-escalation-in-win32ksys-through-indexed-color-palettes

题图:Pixabay License

本文由奇安信代码卫士编译,不代表奇安信观点,转载请注明“转自奇安信代码卫士 www.codesafe.cn”

奇安信代码卫士 (codesafe)

国内首个专注于软件开发安全的产品线。

 点个“在看”,让我体验一下猪肉般的幸福~                                          

                                                

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。在编写C程序时,需要注意变量的声明和定义、指针的使用、内存的分配与释放等问题。C语言中常用的数据结构包括: 1. 数组:一种存储同类型数据的结构,可以进行索引访问和修改。 2. 链表:一种存储不同类型数据的结构,每个节点包含数据和指向下一个节点的指针。 3. 栈:一种后进先出(LIFO)的数据结构,可以通过压入(push)和弹出(pop)操作进行数据的存储和取出。 4. 队列:一种先进先出(FIFO)的数据结构,可以通过入队(enqueue)和出队(dequeue)操作进行数据的存储和取出。 5. 树:一种存储具有父子关系的数据结构,可以通过中序遍历、前序遍历和后序遍历等方式进行数据的访问和修改。 6. 图:一种存储具有节点和边关系的数据结构,可以通过广度优先搜索、深度优先搜索等方式进行数据的访问和修改。 这些数据结构在C语言中都有相应的实现方式,可以应用于各种不同的场景。C语言中的各种数据结构都有其优缺点,下面列举一些常见的数据结构的优缺点: 数组: 优点:访问和修改元素的速度非常快,适用于需要频繁读取和修改数据的场合。 缺点:数组的长度是固定的,不适合存储大小不固定的动态数据,另外数组在内存中是连续分配的,当数组较大时可能会导致内存碎片化。 链表: 优点:可以方便地插入和删除元素,适用于需要频繁插入和删除数据的场合。 缺点:访问和修改元素的速度相对较慢,因为需要遍历链表找到指定的节点。 栈: 优点:后进先出(LIFO)的特性使得栈在处理递归和括号匹配等问题时非常方便。 缺点:栈的空间有限,当数据量较大时可能会导致栈溢出。 队列: 优点:先进先出(FIFO)的特性使得

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值