对某驱动程序提权漏洞的分析

 

一、前言

随着微软不断加固内核安全、提升原生内核组件的漏洞利用难度,现在第三方内核驱动正逐渐成为攻击者的首选目标,也是安全分析人员的重点研究对象。已签名的第三方驱动中的漏洞可能会造成非常重大影响:攻击者可以滥用该漏洞来提升权限,或者绕过驱动程序强制签名机制(这是更为常见的一种做法),无需在操作系统中使用更为珍贵的0-day内核漏洞。

计算机厂商通常会向用户附带提供便于设备管理的一些软件及工具,这些软件和工具(包括驱动)通常会包含运行在内核ring-0层的组件。由于这些组件会默认安装,因此在安全方面必须与内核保持一致:即便其中某个组件存在缺陷,也可能成为整个内核安全的致命弱点。

我们在分析Microsoft Defender Advanced Threat Protection内核传感器模块生成的警告时就找到了这样一个驱动。经过跟踪定位,我们发现这种异常行为存在于Huawei研发的某个设备管理驱动中。经过深入挖掘,我们发现该设备存在一个本地提权漏洞。

反馈该漏洞后(漏洞编号为CVE-2019-5241),Huawei方面积极响应,整个合作过程非常迅速且专业。2019年1月,Huawei发布了修复程序。在本文中,我们将与大家分享我们从调查ATP警告到发现漏洞、最终与厂商合作以保护客户安全的完整过程。

 

二、使用Microsoft Defender ATP检测内核发起的代码注入

从Windows 10 1809版本开始,系统在内核中新部署了一些传感器,用来跟踪由内核代码执行的User APC代码注入操作,能更更好地分析DOUBLEPULSAR之类的内核漏洞利用技术。在之前的一篇深入分析报告中我们提到,DOUBLEPULSAR是WannaCry勒索软件使用的一个内核后门,用来将主功能payload注入用户空间(user-space)。DOUBLEPULSAR会将payload从内核拷贝到lsass.exe中的一块可执行内存区域,将User APC插入某个目标线程,并将NormalRoutine指向这一块内存区域。

图1. WannaCry User APC注入技术示意图

虽然User APC代码注入技术并不罕见(参考ConfickerValerino之前提供的proof-of-concept),但想检测运行在内核中的安全威胁并非易事。自从Windows引入PatchGuard以来,用户再也无法hook NTOSKRNL,驱动程序无法通过公开的方式获取关于上述操作的任何通知。因此,如果没有更好的选择,可采取的唯一策略就是内存取证技术,而这可能是非常复杂的一个过程。

这些新部署传感器的目标正是为了解决这类内核威胁。Microsoft Defender ATP利用这些传感器来检测由内核代码发起的可疑操作,这些操作最终可能会将代码注入用户模式(user-mode)中,我们也是因为某次可疑操作才开始这次调查之旅。

 

三、分析来自内核的异常代码注入行为

当监控与内核模式攻击有关的告警信息时,我们注意到了某条警报:

图2. Microsoft Defender ATP中关于内核发起的代码注入警报

从警报中的进程树信息,我们发现某个内核代码会在services.exe的上下文中执行异常的内存分配及执行操作。进一步调查后,哦们发现同一时间在另一台主机上也出现了相同的警报。

为了更好理解这种异常现象,我们观察了来自内核传感器的原始信号,得出了两点结论:

  • 某个系统线程调用了nt!NtAllocateVirtualMemory,在services.exe地址空间中分配了单个页面(size = 0x1000),该页面带有PAGE_EXECUTE_READWRITE保护掩码
  • 该系统线程随后会调用nt!KeInsertQueueApc,将User APC加入services.exe任意线程的队列中,其中NormalRoutine指向可执行页面的开头处,NormalContext指向0x800偏移处

拷贝自内核模式的payload分成两部分:一个shellcode(NormalRoutine)和一个参数块(NormalContext)。到目前为止,整个过程已经足够可疑,值得我们继续研究。我们的目标是确定触发该警报的内核代码。

 

四、定位来源

在用户模式威胁中,我们可以根据调用方进程的上下文找到攻击者及其他攻击阶段的线索。然而,对于内核模式威胁而言情况有点复杂。内核本质上是异步的,回调函数可以在任意上下文中调用,因此对取证分析而言,我们无法借鉴进程上下文信息。

因此,我们尝试去寻找第三方代码载入内核的间接证据。分析主机的时间线,我们发现了之前该主机曾载入了多个第三方驱动。

根据这些驱动的文件路径,我们发现这些驱动都与某个程序有关:来自Huawei的PC Manager,这是一款设备管理软件,用来管理Huawei MateBook笔记本。Huawei官网提供了安装程序的下载地址,我们也下载到本地研究。对于每个Huawei 驱动,我们都使用dumpbin.exe来检查相应的导入函数。

然后我们得到了一个线索,如下所示:

图3. 使用dumpbin检测User APC注入特征

 

五、HwOs2Ec10x64.sys:来自驱动程序的非预期行为

现在我们已经找到了触发警告的内核代码。通常情况下,设备管理软件主要执行与硬件有关的任务,相关的设备驱动承担与OEM专用硬件的通信层。那么为什么这个驱动会出现异常行为?为了回答这个问题,我们逆向分析了HwOs2Ec10x64.sys

我们的切入点是实现了用户APC注入的函数,我们找到了一条代码路径:

1、在某些目标进程中分配RWX页面;

2、在该目标进程的地址空间中解析CreateProcessWCloseHandle函数指针;

3、将来自驱动的某个代码区域和看上去像是参数块的数据拷贝至已分配的页面;

4、执行针对该页面的User APC注入操作。

这个参数块中包含已解析的函数指针以及一个字符串,该字符串实际上是一个命令行:

图4. User APC注入代码

APC NormalRoutine是一个shellcode,会使用指定的进程命令行字符串来调用CreateProcessW。这意味着注入services.exe的代码会生成一个子进程。

图5. User shellcode创建进程

检查xrefs,我们发现注入的代码来自于某个进程创建通知例程(create-process notify routine),其中Create = FALSE。因此,当某些进程结束时就会触发该操作。

但shellcode具体执行了什么命令?我们可以attach内核调试器,在负责将参数从内核拷贝至用户模式的memcpy_s上设置断点,就可以看到创建的进程:Huawei 已安装的某个服务,即MateBookService.exe,使用/startup命令行来调用。

图6. 在拷贝shellcode参数的memcpy_s上触发断点

为什么一个正常的服务会以这种方式来启动?分析MateBookService.exe!main后,我们找到了一个“启动模式”,当服务停止时,可以借助该模式重新启动。这相当于一种watchdog机制,可以保持Huawei PC Manager主服务处于运行状态。

图7. MateBookService.exe /startup代码路径

分析到这一步,我们还需要确定导致结束进程触发注入操作的的确是MateBookService.exe

图8. 验证结束进程的标识

这里代码使用一个全局的进程名列表来判断是否注入services.exe。在迭代循环中设置断点并触发后,我们可以找到该服务器所注册的进程:与预期相符,该进程正是MateBookService.exe,这也是列表中的唯一进程。

图9. 使用全局列表匹配进程名过程中触发的断点

HwOs2Ec10x64.sys还部署了进程保护机制,可以避免外部篡改。如果想强制结束MateBookService.exe,都会返回“Access Denied”错误。

 

六、滥用HwOs2Ec10x64.sys进程监控机制

接下来我们需要判断攻击者是否可以篡改这个全局监控进程列表。我们找到了一个IOCTL处理函数(handler),该函数负责往列表中添加元素。MateBookService.exe进程很可能会在服务启动时使用该IOCTL来注册。这个IOCTL会发送到由其DriverEntry创建的驱动控制设备。

图10. 使用IoCreateDevice创建HwOs2Ec10x64.sys控制设备

由于设备对象使用IoCreateDevice创建,因此任何人(Everyone)都具备该对象的RW访问权限。另外有一点也非常重要,这个设备并不处于独占状态,因此可以同时打开多个句柄。

然而,当我们尝试打开\\.\HwOs2EcX64的句柄时,会返回一个Last Error = 537错误,提示“Application verifier has found an error in the current process”。该驱动拒绝我们打开设备的请求。那么我们如何满足访问条件呢?我们必须位于CreateFile路径上,或者更具体一些,位于HwOs2Ec10x64.sysIRP_MJ_CREATE调度例程中。

图11. IRP_MJ_CREATE调度例程

该函数会检查调用进程的主执行路径是否位于白名单中(如C:\Program Files\Huawei\PCManager\MateBookService.exe)然而,对初始进程名的这种检查机制并不能确保调用进程的完整性。如果攻击者控制了MateBookService.exe实例,那么就具备\\.\HwOs2EcX64设备的访问权限,可以调用该设备的某些IRP函数。随后,攻击者控制的进程可以滥用这种功能来与设备通信,注册自己选择的监控程序。由于父进程具备子进程的完全访问权限,因此即便是低权限的代码也能生成受影响的MateBookService.exe,并将代码注入其中。在我们的proof-of-concept中,我们使用了process hollowing这种技术。

图12. Procmon工具中可以看到POC进程的启动/退出及完整性级别(IL)

由于监控进程会在终止时被watchdog盲目启动,因此攻击者控制的可执行程序就会作为services.exe的子进程被调用,以LocalSystem权限运行,最终实现权限提升效果。

图13. Procexp工具中可以看到以LocalSystem权限运行的LPE_POC进程

 

七、漏洞披露

当我们的POC能够借助攻击者控制的、低完整性级别的进程完成权限提升操作后,我们第一时间通过微软安全漏洞研究(MSVR)项目向Huawei方反馈了该漏洞,漏洞编号为CVE-2019-5241。与此同时,我们构建了一个检测机制,如果攻击者利用本文描述的HwOs2Ec10x64.sys漏洞来提升权限时,就会触发安全警报,从而保护我们客户的安全。

图14. Microsoft Defender ATP能够检测到POC提权代码

 

八、滥用另一个IOCTL处理函数

由于我们已经能够从用户模式中自由调用驱动的IOCTL处理程序,因此我们开始寻找能够滥用的其他功能。我们很快找到了一个目标:该驱动有一个功能,能够将任意物理页面映射到用户模式中,并且具备RW权限。调用这个处理函数后,低权限代码就能跨进程边界,对其他进程(甚至是内核空间)执行读写操作,这最终将导致攻击者完全控制整台主机。

我们同样与Huawei方合作修复了第二个漏洞,该漏洞编号为CVE-2019-5242,Huawei已在同一个安全公告中解决了这个问题。

我们在2月份的Blue Hat IL Conference上介绍了我们的研究成果,欢迎大家观看相关视频,下载演示文稿

 

九、总结

我们在驱动中发现的这两个漏洞表明,开发者在设计软件及产品时需要时刻遵守安全这条线。安全边界是非常重要的一点,开发者应该尽量减少可能存在的攻击面。在本文这个案例中,如果开发者采取了如下预防措施,可能避免出现这些缺陷:

  • 由驱动创建的设备对象的DACL应当匹配SYSTEM RW访问权限(因为只有厂商的服务能直接与该驱动通信);
  • 如果某个服务需要持续运行,开发者在实现一个复杂的维护机制前,应当检查系统是否提供了这类功能;
  • 不应当允许用户模式下执行某些特权操作(如写入物理页面);如果确实需要,驱动应当在明确定义的、与驱动相关的场景下执行实际的写入操作。

微软提供了一份驱动安全检查清单,可以为驱动程序开发者提供参考,减少驱动程序被入侵的风险。

这个驱动漏洞的发现过程也彰显了Microsoft Defender ATP传感器的优点,这些传感器感知到了异常行为,可以为SecOps人员提供威胁事件的相关信息及实用工具。

异常行为通常与不怀好意攻击者所采取的攻击技术有关,在本文案例中,这些异常行为与攻击者能够滥用的某个设计缺陷相关。无论如何,Microsoft Defender ATP还是找到了一处安全缺陷,在攻击者将其应用于实际场景前就能提前保护客户的安全。

(完)