Symantec终端保护本地提权漏洞分析(CVE-2019-12750)(上)

0

恶意应用程序可以利用Symantec Endpoint Protection中的漏洞,泄漏权限信息或以更高的权限执行代码,从而完全控制受影响的主机。

目前受影响的产品有:

Symantec Endpoint Protection v14.x < v14.2 (RU1)
Symantec Endpoint Protection v12.x < 12.1 (RU6 MP10)
Symantec Endpoint Protection Small Business Edition v12.x < 12.1 (RU6 MP10c)

几个月前,在最新版本的Symantec Endpoint Protection(SEP v14.2 Build 2486)软件中寻找本地权限升级漏洞时,我们遇到了隐藏了几年的漏洞。

此外,Windows 10 v1809中引入的内核池分配的最新安全更新使我们有机会实现一种不同的方法,以便在当前可用的最新版本中成功地利用此漏洞。

由于我们使用的两种方法之间存在很大差异,因此我们决定将本文分为两部分。

在第一部分中,我们将讨论实际的漏洞以及在早期Windows版本Windows 7至10 v1803中如何利用它,而不需要额外的内核模式执行控制要求。

在第二部分中,我们将采用一种更复杂的方法,由于Windows 10 v1809及更高版本中新引入了用于内核模式池分配的低碎片堆(LFH),因此需要对易受攻击的产品进行进一步分析,该方法和第一部分中使用的漏洞利用方法完全不同。为了在内核模式下获得代码执行,同时绕过SMEP和KASLR等其他利用缓解措施,这是必需的。

漏洞分析

创建新进程后,SEP将注入一个名为“sysfer.dll”的DLL模块,该模块在加载后会发出一系列输入输出控制(IOCTL)请求。

在本文的示例中,我们对发送到“ SysPlant.sys”内核驱动程序的IOCTL 0x222014感兴趣。

在处理此请求期间,编程漏洞使恶意攻击者能够泄漏和破坏内核模式数据。特别是,通过检查在此IOCTL请求期间执行的一个子例程,我们会看到以下步骤:

1. 调用ExAllocatePool在分页池池中分配大小为0x14字节的缓冲区;

2. 调用IoAllocateMdl来为该缓冲区分配一个内存描述符列表;

3. 调用MmProbeAndLockPages来探测并锁定内存中的关联页面;

4. 调用MmMapLockedPagesSpecifyCache将这些页面映射到另一个虚拟地址范围。

在用户模式下映射页面的进程

上述的最后一个步骤在调用进程的上下文中以用户模式映射池块,但是,在映射缓冲区时,也会映射应用缓冲区范围的整个内存页面。

在本文的示例中,缓冲区将分配一个很小的块,该块占用总计0x30字节(缓冲区大小+池头+对齐填充)。这意味着,通过在用户模式下映射此池块,我们还会泄漏其余的内存页面。这基本上是可能包含其他权限信息的附加内核内存的0xFD0(4048)字节。

不过,默认情况下,内存页被映射为可写的,这也允许用户模式进程修改其内容。任何应用于userland映射内存页的修改,都将映射到原始的内核模式内存页。

为了缓解信息泄漏,驱动程序应分配一个内核模式缓冲区,该缓冲区的大小是系统使用的内存页大小的倍数,通常为4KB。在发生任何映射之前,必须先清理(填充0)此缓冲区。

另外请注意,内核模式缓冲区仍应映射到用户地址空间,不应释放它。否则,任何写入该缓冲区的新数据也将在userland被泄漏。

从Windows 8开始,内核模式缓冲区的映射也应该是只读的,因此在调用MmMapLockedPagesSpecifyCache函数时可以使用MdlMappingNoWrite标志。

传递给MmMapLockedPagesSpecifyCache的第一个参数是一个指向MDL结构的指针,该结构在第二步中被分配,如上所述。

MDL结构

我们对该结构的三个突出显示的函数感兴趣:

1. StartVa:内存页面的起始地址;

2. ByteCount:MDL描述的缓冲区大小;

3. ByteOffset:内存页面内缓冲区的起始偏移量;

开发人员的意图是将大小为0x14字节的小缓冲区映射到调用进程的用户模式地址空间中。但是,系统将映射整个内存页面,而不仅仅是所需的池块,如下图所示:

内核模式缓冲区

用户模式映射的缓冲区

但是我们希望有更多发现,而不是仅仅在userland中显示分页池内存。

请注意,在模块加载阶段,每个进程只能运行一次。因此,我们不能在同一个进程多次重用同一个IOCTL来映射userland中的其他内核内存页面。

另一方面,由于内核对象一直都在分配和释放,因此与这些对象相关联的映射页面的内容将不断变化。

但是,通过在我们自己的函数中重新使用相同的IOCTL,一旦初始化了进程,便可以找到该块所映射的userland地址。

了解这一点后,我们也可以通过屏蔽最后两个字节(VA&0xFFFFF000)来找到特定页面userland中的基址,假设页面分配大小为4KB。

一旦我们有了这些信息,我们就可以解析映射的页面来找到我们可以用来进一步利用这些信息的信息和有趣的对象。

漏洞利用(Win 7 –Win 10 v1803)

在漏洞利用的第一部分中,我们将重点介绍Win 10 v1809之前的Windows版本。这也将帮助我们在第二部分中了解LFH应用于内核池分配如何影响了最新Win 10版本中的漏洞利用。因此,在这一部分中,我们将重点介绍Win 10 v1803。

由于每个进程只能泄漏一个分页池内存页,不同的进程也可能会泄漏相同的页,所以我们首先启动一堆进程。

每个进程都使用上述IOCTL来获取userland中映射页面的基地址,并将该数据保存在文件中以供进一步研究。

在创建了几个进程之后,漏洞利用就可以开始了。

泄漏的令牌对象

我们注意到,有时候,我们能够泄漏令牌对象,这是内核LPE漏洞利用的众所周知的目标。是的,这些是分页池对象,现在我们拥有了它们。

请注意,泄漏的内存页不一定包含与调用进程关联的对象分配。事实上,通常不会有。

这些页面主要是在上述IOCTL请求发生时泄漏的随机页面,0x30字节块适合于分页内核池中任何有可用空间的地方。

也就是说,泄漏的令牌对象不一定属于调用进程,实际上通常也不属于。但是,由于我们知道这种有趣的对象类型偶尔会出现在泄漏的页面池内存页面中,所以我们需要找到一种方法来利用这种情况。

第一种漏洞利用方法

由于每个进程都有其自己的令牌对象,因此我们可以开始创建许多进程,每次将其置于“等待”状态。我们需要这样做,以确保不会释放关联的令牌对象。

简而言之,每个子进程都将检查在其地址空间中映射的泄漏的内核内存页面,并查找泄漏的令牌对象。无论结果如何,此进程都将无限期地等待。

创建的进程越多,我们将分配的令牌对象就越多,因此我们将开始在可写的用户模式映射的内核页面中泄漏这些对象。

此时,我们还不知道每个对象所属的进程,因此我们必须保留进程句柄的列表。子进程创建完成后,我们就可以检查它们的令牌,以找到一个我们修改了其原始权限并在其自身上下文中执行代码的令牌。

第二种漏洞利用方法

由于我们的第一个目标是泄漏尽可能多的令牌对象,这样分配的令牌对象越来越多,分配的0x30字节块出现在同一内存页中的几率就越大。

我们可以通过使用DuplicateTokenEx函数创建漏洞利用进程的主要令牌的复制来实现,此函数还允许我们指定每个复制都是主令牌,稍后可以通过CreateProcessAsUser函数使用它。

另外,我们可以使用ImpersonateLoggedOnUser函数来允许漏洞利用的调用线程直接使用提升的令牌权限。

一旦创建了主要令牌的数千个复制,我们便可以使用上述第一种方法。同样,我们一开始先创建子进程,其中每个进程将检查映射到其自身地址空间中的泄漏内核页面,并搜索要修改的令牌对象。

其次,我们可以遍历令牌复制列表,并使用带有TokenPrivileges TOKEN_INFORMATION_CLASS的GetTokenInformation,并搜索一个实例,该实例具有只有提升后的进程才具有的权限,比如“SeDebugPrivilege”。

最后,我们使用CreateProcessAsUser函数修改后的令牌来启动具有提升的权限的新进程,或者通过ImpersonateLoggedOnUser函数来提升调用线程的权限。

主要步骤总结

1. 创建数千个主令牌复制;

2. 开始自我检查子流程,搜索和修改泄漏的令牌对象;

3. 解析我们的主令牌克隆列表,以找到一个被修改的令牌;

4. 使用CreateProcessAsUser或ImpersonateLoggedOnUser函数执行具有更高权限的代码;

5. 在以系统身份运行的进程中注入并执行代码;

本文只介绍了一个简单的编程漏洞示例,开发人员只需在调用过程中映射一小块数据,而无需考虑文档的所有详细信息及其可能的安全隐患。

在利用此漏洞的第二部分中,我们将重点介绍最新的Windows 10 v1909,并了解如何添加内核池LFH来迫使我们寻找其他利用此漏洞的方法。

Focus On The Network Information Security.

作者主页 邮箱 微博 腾讯微博 QQ Twitter Facebook Google+

发表评论

您的邮箱不会公开,当您的评论有新的回复时,会通过您填写的邮箱向您发送评论内容。 必填字段 *

返回顶部