下载安卓APP箭头
箭头给我发消息

客服QQ:3315713922

win32k.sys驱动CreateSurfacePa的本地提权漏洞分析(CVE-2019-1362)(下)

作者:xiaohui     来源: 嘶吼点击数:1205发布时间: 2019-12-25 10:37:15

标签: Javascript 视频Javascript 课程视频Javascript 课程

在上一篇文章中,我们介绍了漏洞发生的运行环境和运行过程。在这一篇文章,我将介绍漏洞的实际攻击过程,并对其进行分析。

1.每个池内存块(大块除外)前面都有一个POOL_HEADER记录,我们需要在伪造的_PALOBJ结构之前欺骗一个池标头。

2.释放一块内存时,用下一个池标头的内容验证它的池标头的内容。因此,我们还需要在fake _PALOBJ结构上创建一个额外的伪造池标头。

3.池标头(PoolIndex字段)中有一个字段包含内存块所属的池的索引。

4.在正常情况下,尽管理论上最多可以分配16个池,但是在操作系统中可以使用4个池。每个池都通过使用其描述符POOL_DESCRIPTOR记录进行管理。

5.我们将使用一种名为“PoolIndex Overwrite”的池利用技术,尽管在我们的示例中,“Overwrite”部分不是一个技巧,因为我们的伪造池头位于用户内存中,所以我们可以随意向它们写入。我们将伪造池头中的PoolIndex字段设置为15。内核使用一个表将PoolIndex值转换为相应的POOL_DESCRIPTOR记录的地址。由于只分配了4个池,因此PoolIndex为15的值将转换为空指针。

在x86上默认安装Windows 7时,可以通过调用ntdll.dll!NtAllocateVirtualMemory本机API来分配一个空页(内存从地址0开始)。 (此外,请注意,可以使用注册表项HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory的EnableLowVaAccess启用或禁用空页分配。)这使我们可以在此处分配伪造的POOL_DESCRIPTOR结构。就我们的目的而言,足以初始化此结构的PendingFrees,PendingFreeDepth和ListHeads字段,如前面提到的“ Windows 7上的内核池利用”中所述。这将导致能够用半控制值覆盖我们选择的内核内存。

根据物理安装的RAM内存的数量,操作系统要么立即将要释放的内存块返回池中,要么以较大的突发次数(称为“延迟释放”)返回到池中。根据该变量,通过使用精心设计的POOL_DESCRIPTOR结构,我们可以使用释放的内存块地址(在本例中为Dword,格式为0x30XXXXXX)或某些用户的地址覆盖我们选择的内核内存。该内存块在准备我们精心设计的POOL_DESCRIPTOR结构时分配(该值范围从0x00010000到0x7fff0000)。我们最后的非显而易见的任务是在内核中找到一个很好的覆盖目标,该目标的某些值通常未知,但保证至少为0x10000。

有这样的约束,调色板对象就是一个不错的选择。可以使用gdi32.dll!SetPaletteEntries API将调色板条目写入。在其内核实现中,此API对请求写入的索引强制执行0xffff的限制。这是因为无法在用户模式下创建较大的调色板。我们可以创建一些调色板(将其命名为PaletteLO),例如,包含256个条目。仅在请求的要写入的调色板条目在0到255的范围内时,在PaletteLO上调用SetPaletteEntries才会成功。然后,我们可以使用上述利用方法,使用未知值覆盖PaletteLO的_PALOBJ内核结构中的cEntries字段。至少0x10000。完成此操作后,SetPaletteEntries将在PaletteLO上的最大可能范围为0到0xffff范围内工作。这将使我们能够覆盖位于PaletteLO上的0xffff限制内的所选存储位置,并且我们将能够通过调用SetPaletteEntries时传递的颜色参数来完全控制内容。

对于下一步的攻击,我们将创建另一个调色板,该调色板位于PaletteLO的上方。我们把它命名为PaletteHI。然后,我们将在PaletteLO上调用SetPaletteEntries,用我们选择的指针在PaletteHI的_PALOBJ内核结构中设置pFirstColor字段。由于pFirstColor表示调色板的颜色数组的基本地址,因此在PaletteHI上对SetPaletteEntries的后续调用将覆盖pFirstColor值所指向的内存,并完全控制其内容。至此,就可以调用PaletteHI上的SetPaletteEntries,我们已经获得了用任何选择的内容覆盖任何选择的内存位置的能力。

操作之前的调色板如下:

win32k.sys驱动CreateSurfacePa的本地提权漏洞分析(CVE-2019-1362)(下)_Javascript 视频_Javascript 课程视频_Javascript 课程_课课家

覆盖PalleteLO中的cEntries字段:

覆盖PaletteHI中的pFirstColor字段:

要查找调色板的内核地址,我们可以使用全局内核GDI表,该表保存有关每个GDI对象的信息,并以只读模式映射到每个正在运行的进程的用户地址空间。该表包含65536个条目。条目结构没有公开的文档,但是它通常被称为GDICELL:

GDICELL字段的含义如下:

KernelAddress:指向分配给对象的内核内存的指针;

ObjectOwnerPid:对象所属进程的PID;

Upper:对象32位句柄值的16位上半部分

ObjectType:表示对象类型的枚举

Flags:显然是一个包含一些标志的字段;

UserAddress:指向为对象分配的用户内存的指针;

要查找调色板的内核地址,只需使用调色板句柄值的16个最低位作为GDI表的索引,然后读取GDICELL.KernelAddress字段。

要创建在内核内存中足够接近的PaletteLO和PaletteHI调色板,只需在循环中创建调色板对象,直到所创建的任何两个调色板的位置满足我们的要求。当寻址0xffff限制内的条目时,PaletteLO必须能够覆盖PaletteHI的内核内存中的pFirstColor指针。不够,在实践中可以很容易地创建这样的调色板。

现在该说说完整的利用算法了:

1.确保从0x30000000到0x30ffffff的整个内存范围都是可写的,并用零填充。

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

3.分配一个空页面,并准备一个伪造的POOL_DESCRIPTOR。它的内容会导致覆盖PaletteLO的_PALOBJ内核结构中的cEntries字段。写入的值将是未知的,但保证至少是0x10000。

4.使用上述算法1查找并挂钩任何打印机驱动程序DLL,但不执行步骤8,挂钩驱动程序的DrvEnablePDEV函数。

5.调用gdi32.dll!EngCreatePalette创建一个包含256个条目的模板调色板,它将被称为PaletteSRC。

6.指示挂钩的DrvEnablePDEV函数返回PaletteSRC,以及ulNumColors参数等于514和在flGraphicsCaPS字段中设置的GCAPS_PALMANAGED标志。

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

8.扫描内存范围从0x30000000到0x30ffffff的内存范围,并在其中找到伪造的用户模式_PALOBJ结构。

9.调用gdi32.dll!PaletteSRC的参考计数器将变为0,这允许我们在以后的步骤15中将其删除。

10.调用gdi32.dll!EngCreatePalette创建另一个模板调色板,这将称为PaletteHELPER。

11.指示挂钩的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。由于PaletteSRC的_PALOBJ内核结构中的hSelected字段引用了PaletteDEVICE,因此PaletteDEVICE也将被删除。由于PaletteDEVICE的ppalThis指针指向用户内存中虚假的_PALOBJ结构,因此该用户地址将传递给win32k.sysExFreePoolWithTag。而且,由于我们在伪造的_PALOBJ之前和之后创建了伪造的pool header,所以我们的伪空页池描述符将由ExFreePoolWithTag使用。这样,PaletteLO的_PALOBJ内核结构中的cEntries字段将被一个至少为0x10000的值覆盖。

16.调用PaletteLO上的gdi32.dll!SetPaletteEntries,可以使用任意选定的地址覆盖PaletteHI的_PALOBJ内核结构中的pFirstColor指针。

17.调用 PaletteHI上的的gdi32.dll!SetPaletteEntries,可使用任何选定的值覆盖任何选定的地址。

我们现在有一个write-what-where原语,下面将描述如何选择覆盖的最终目标。

选择要覆盖的内存位置

访问令牌是包含进程或线程安全上下文的内核对象,这包括启动该进程的用户帐户的标识或该用户的线程和权限。当前,定义了34种可能的权限:

这些权限可能存在,也可能不存在。它们也可以被启用或禁用。令牌中存在的权限可能被禁用,然后重新启用。也可以将其删除,以使其不存在并且无法再出现,从而使进程无法提升其权限。仅在创建令牌期间才可以提供权限,并且创建令牌仅可用于拥有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用户的令牌,它是一个比通常的系统令牌更强大的令牌。操作系统本身使用系统令牌,该令牌没有某些权限。然后,拥有最强大的令牌以及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位系统上,该漏洞只能用于DoS。

有可能利用这个漏洞来提高安装了Windows服务器的Itanium计算机上的权限。

Windows 8及更高版本中的变化

根据反汇编的win32k.sys(Windows 8和8.1)或win32kbase.sys(Windows 10),CreateSurfacePal函数中,该漏洞不存在。因为,用户模式传递的值可以被正确验证。

还值得注意的是,自Windows 10版本1607开始,GDICELL就开始了。KernelAddress字段不再保存指向内核内存的直接指针,你可以点此详细了解这部分内容。

补丁说明

微软在10月份解决了这个漏洞,并将该漏洞定义为 CVE-2019-1362。不过在漏洞修复中,微软只是通过“更正Windows内核模式驱动程序处理内存中对象的方式”方法解决了该漏洞。这个补丁很可能会将Windows 8的操作行为恢复到原来的版本,因为那个版本的操作系统没有受到影响。

总结

通过以上的讲解,很容易看出为什么这个漏洞为什么与众不同。

这些类型的漏洞通常与其他漏洞结合在一起,形成一个完整的漏洞链。最近,在针对韩国新闻网站的Chrome浏览器中,出现了类似的LPE和免费使用的Chrome浏览器。尽管LPE本身被认为没有严重的漏洞,但是与其他远程代码执行漏洞的结合会导致有效的攻击。

赞(9)
踩(0)
分享到:
华为认证网络工程师 HCIE直播课视频教程