导语:在上一篇文章中,我们描述了内核模式威胁的演变过程。在接下来的篇幅中,我们将首先介绍我们自己的研究,这个研究由红队蓝队的演练引申而来,就如何避开当前平台的保护做详细深入分析,然后简述当前最先进的间谍攻击技术的框架的搭建过程
在上一篇文章中,我们描述了内核模式威胁的演变过程。对于国家级攻击者而言,这些攻击手段虽有瑕疵,但相较于当前的状况来说也是很优异的,因为它们难以被发现,且具有强大的持久性。尽管平台在保护工作上取得了许多进展,但内核模式威胁同样也在不断发展中,并且也已经应用于许多引人注目的攻击里了,例如WannaCry和NotPetya。那么,组织机构可以采取哪些措施来防范内核模式威胁呢?幸运的是,防御技术的最新发展已经为这种攻击趋势做出了有力反击。
我们对间谍攻击技术的研究给予了我们改进内核威胁防御的灵感。在接下来的篇幅中,我们将首先介绍我们自己的研究,这个研究由红队蓝队的演练引申而来,就如何避开当前平台的保护做详细深入分析,然后简述当前最先进的间谍攻击技术的框架的搭建过程,讨论几种防御内核模式威胁的方法,还将介绍两种开源工具帮助抵御内核模式威胁——一种能快速制胜,另一种则涉及狩猎和建立实时保护。但无论如何,我们都强烈建议您能升级到最新的Windows 10系统,它能给您尽可能多的保护。
间谍攻击技术研究
为了测试和拓展我们防御能力的界限,首先得了解间谍技术的最新水平。在测试红蓝对抗期间,我们先是利用了内核恶意软件来逃避端点安全产品和最常见的内核保护系统(例如DSE),接着我们研究了用于规避VBS和HVCI等最先进的内核保护系统的方法。
红蓝对抗
Endgame为了测试产品和团队的能力,会定期进行内部红蓝对抗演练。红队的任务是模仿各种不同复杂度的恶意软件,包括嘈杂的商业恶意软件到中高端APT。通常情况下,红队会尝试用最新的用户模式内存技术让恶意软件“隐身”,但我们的蓝队也在不断提高他们的游戏水平,并在我们的用户模式注入技术中变得越来越有效,所以我们决定在存储技术中追求内核模式以提高标准。
Turla Driver Loader(TDL)是我们内核间谍技术的关键部分。TDL是Turla / Uroburos驱动程序加载技术的开源实现。简而言之,它将加载易受攻击的VirtualBox驱动程序,VirtualBox驱动程序被用来加载和执行任意内核shellcode。TDL使用shellcode构建,在用户模式下利用“MemoryModule”等技术手动映射任意驱动程序并调用其入口点。使用TDL可以帮助红队实现两个功能:逃避驱动程序签名强制执行,永远不会将驱动程序写入目标计算机上的磁盘。
我们对植入程序还设计了一些较高的目标。首先,我们想要避免植入程序里有任何用户模式组件,所以采用了一种更为典型的设计——使用内核模式组件,这个组件的主要功能就是“植入”到用户模式。这两篇文章中所提到的内核恶意软件,有些会具有一些用户模式组件。避免用户模式对于基本功能来说更耗时,但我们认为这是值得的,向用户模式注入任何内容都很有可能被我们的蓝队捕获,这就要求我们从内核模式执行网络命令和控制。我们把Winsock Kernel(WSK)作为联网选择,因为它有很好的文档记录和示例代码,并提供了一个相对简单的接口,用于从内核的网络通信。
为了进一步混淆蓝队,我们将Beacon式的植入程序排除在选项之外,虽然Beaconing是迄今为止最流行的恶意软件,但照理说也会很容易被蓝队捕获。我们最初关于端口开放的想法总是行不通,于是我们选定了一种更隐蔽的方法——通过重新使用DoublePulsar函数指针挂钩技巧来劫持一些现有的内核套接字,同时,我们也不想利用相同的挂钩点,让它马上被PatchGuard监视到。在深入研究了各种股票网络驱动程序后,我们确定了打开端口445的srvnet驱动程序,子驱动程序会找寻srvnet的WskAccept函数的定位,并用我们自己的accept函数连接它。这样一来,所植入的程序就可以选择性的劫持445端口的流量。
利用TDL意味着我们的内核驱动程序永远不会触及磁盘,但是仍然可能存在加载器本身被捕获的高风险。因此,我们希望确保加载过程尽可能无文件化。这意味着需要使用PowerShell或JavaScript启动链。我们之所以选择JS,是因为维护者的能见度普遍较低。我们没有启动cscript/wscript本身,而是使用squiblydoo技术从regsvr32进程运行一个脚本。对于我们实际的黑帽演示(下面的视频),我们用到了SquiblyTwo和winrm.vbs规避技术。
从这里开始,我们使用DotNetToJS从JavaScript加载/执行任意.NET可执行文件。我们可以从这个.NET可执行文件中使用和加载我们的驱动程序,但执行此操作的代码已经用C编写好了。更容易的选项是使用MemoryModule样式的.NET加载器,然后加载并执行本机可执行文件。本机可执行文件(TDL)将加载易受攻击的VirtualBox驱动程序,并利用它来加载映射驱动程序并将其映射到内存中。在这整个过程中,真正触及本机磁盘的唯一可执行文件就是合法的VirtualBox驱动程序。
规避VBS / HVCI
当接受出席黑帽会议时,我们想要突破我们间谍攻击技术的边界。目前,微软基于虚拟化的安全性(VBS)与虚拟机管理程序代码完整性(HVCI)相结合,阻止了任何未签名的代码在内核中运行。这包括DoublePulsar和我们为RvB练习编写的植入代码。
首先,我们需要识别一个易受攻击的驱动程序,因为在启用HVCI时,TDL的VirtualBox驱动程序是不会加载的。事实上,容易被攻击的驱动程序的数量几乎是无限的。我们从Parvez Anwar的站点抓取了一个已知的易受攻击的样本,由于我们可以为端点选择漏洞,于是选择了一个易于利用的write- * what-where漏洞,而不是像静态单字节写入那样更难的漏洞,后者为了实现完整的读/写原语通常会涉及到一些池损坏(如win32k GDI对象)。由于易受攻击的驱动程序在进行覆盖时会取消引用用户提供的指针,因此它还为我们提供了一个方便的任意读取原语。
HVCI能阻止未签名的代码在内核中运行,但它无法保护内核模式数据的完整性。篡改关键数据结构可能会严重影响系统完整性。例如,攻击者可以通过修改IAT来“NOP”掉某些函数调用,可以禁用EDR内核与用户的通信,或禁用如Microsoft-Windows-Threat-Intelligence这样的安全集中内核Etw的提供者。数据损坏攻击同样可以依靠修改令牌或句柄来提升权限,还有许多其他技术也是可行的。
为了探索这一领域的现实意义,我们研究了sysmon驱动程序在进行日志记录时将事件从内核模式发送到用户模式的方式。我们发现,如果我们将导入地址表(IAT)中的IoCsqRemoveNextIrp指针修改为xor rax,rax ret小工具,则不再记录事件。现实世界的攻击者可以选择性的放弃事件以免引起怀疑。值得指出的是,这绝不是sysmon中的一个缺陷,因为每个安全产品都受到这样的数据损坏攻击都可能受损。但是,微软可能会扩展VBS来保护那些不应被修改的数据区域(例如本示例中的IAT)。
当数据损坏攻击让我们担惊受怕的时候,我们想要探索是否仍然可以实现任意代码执行。微软的Dave Weston在BlueHat IL的演讲中对解释VBS的设计提供了绝佳的细节。然而,它也使我们陷入了当前关于后缘控制流动防护方法的空白。从本质上讲,Windows内核对面向返回编程(ROP)攻击仍是无法抵抗的。
正如Peter Hlavaty在2015年的讨论中所提到的,为了通过ROP让代码执行,可以以滥用读写原语的方式来执行堆栈挂钩。我们有兴趣将这种技术化为武器去对抗HVCI强化系统。我们创建了一个代理线程作为我们的挂钩目标,之后,PoC将根据目标函数中的参数数量动态构建ROP链,它只需要10个小工具来实现完整的N-argument函数调用原语。在下一步中,我们利用已签名且易受攻击的驱动程序来破坏代理线程的内核堆栈,以便执行生成的ROP链。最终结果是我们的PoC可以调用任意内核模式函数。在一个示例中,攻击者可以利用它来注入受保护的用户模式进程,并且在很大程度上对AV / EDR不可见。下面的视频演示了如何使用这种技术绕过HVCI(请到原文中查看视频)。
NTSTATUS WPM(DWORD_PTR targetProcess, DWORD_PTR destAddress, void * pBuf, SIZE_T Size) { SIZE_T Result; DWORD_PTR srcProcess = CallFunction("PsGetCurrentProcess"); LONG ntStatus = CallFunction("MmCopyVirtualMemory", srcProcess, (DWORD_PTR)pBuf, targetProcess, destAddress, Size, KernelMode, (DWORD_PTR)&Result); return ntStatus; }
防御内核模式威胁
首先也是最重要的,在保护您的企业免受内核模式威胁上,您能做的最简单的事情,就是确认驱动程序负载上所发生的事件。有很多可用的工具可以做到这一点,包括审计模式下的SysInternals Sysmon和Windows Defender Application Control,最好就是能用那些不怎么普遍的、已知可利用的驱动程序。建立基线同样很重要,在了解敌人前您更需要了解自己——公司的资产和基础设施,和整个构架中内核模块的暴露程度。
如果可能,防御者应该部署管理程序代码完整性策略来阻止大多数旧版驱动程序。理想情况下,您应该将驱动程序发布者列入白名单,但维护有效的白名单可能会非常困难,不过至少,您应该在所有驱动程序上强制使用WHQL签名。要获得WHQL签名,您必须将驱动程序上载到Microsoft。理论上来说,这能减轻被盗证书的威胁,因为攻击者不能再偷偷签署他们的恶意软件,但WHQL也不是万能的,比如我们用来逃避HVCI的驱动程序就是WHQL签名的。
此外,防御者可以通过将已知可利用的驱动程序列入黑名单来作为对代码完整性策略的补充。从Windows 10 Redstone 5开始,如果启用HVCI,微软将默认阻止许多已知可利用的驱动程序,这对某些用户来说非常有用,但它不能帮助那些运行早期版本的Windows,或者使用Redstone 5但无法启用HVCI的用户。
开源防御:内核攻击面减少(KASR)
为了帮助其他组织机构,我们发布了KASR,这是一个免费工具,可以屏蔽已知并且可利用的驱动程序。当不熟练的攻击者利用已知攻击方式试图进行攻击时,KASR会为其添加障碍。我们知道这份记载了驱动程序列表的黑名单没有扩展性,它无法阻止那些知道如何在内核驱动程序中查找和利用漏洞的攻击者,但我们希望它至少能阻止脚本在内核中肆虐。微软正在最终确定他们的RS5驱动程序黑名单,完成后,我们会将其纳入未来版本的KASR。
内核搜寻
回顾我们的RvB,我们意识到我们需要一种更好的方法来寻找像DoublePulsar和“无文件植入”这样的内核模式威胁。传统的取证式技术涉及全内存采集和离线分析,这些都是时间和带宽密集型的,这种方法无法扩展。为了解决这个问题,我们利用相同的技术来获取内核内存,但是是在端点上进行分析,原理类似“blackbox”rootkit扫描程序,可以在几毫秒内完成扫描。
有几种技术可用于读取Windows机器上的物理内存,包括PhysicalMemory设备和基于MDL的API。我们比较偏爱用的一个是页表输入重映射(如上所示),因为它简单并且性能高。
我们的目标是检测出DoublePulsar——当它处于“隐身”状态,并且没有签名的时候。一般的做法是,扫描内核池/堆内存,寻找类似shellcode的内存对象。但在Win7系统里,整个非分页池(NonPagedPool)是可执行的,这样就会留下相当大的搜索空间,很容易出现误报。
与之相反,我们则专注于识别函数指针挂钩。第一个步骤是确定内存中函数指针的位置,函数指针是绝对地址,这意味着如果重新定位图像,则需要重新定位指针,因此为了找到函数指针,我们遍历了所有已加载驱动程序的PE重定位表。其次,我们会检查重定位的值是否指向原始磁盘副本中驱动程序的可执行部分,接着检查它是否在内存中任意加载的驱动程序之外。最后,如果它指向的非支持内存区域是可执行的,那么我们就认为找到了。
这个方法能同时检测到由我们内核模式植入程序安装的DoublePulsar和套接字处理程序钩子。基于此原理我们发布了Marta,这是一种能扫描系统上所有驱动程序的免费工具(通常以毫秒为单位),并能识别任何活跃状态的感染程序。Marta的名字取自Marta Burgay,她是第一位发现现实双脉冲星的天文学家。下面视频将展示Marta快速识别出隐身的DoublePulsar的过程。
实时保护
按需求扫描的方式非常优秀,但我们希望能更进一步,看看是否能够实时捕获并在任何损坏发生之前阻止这些类型的攻击。我们从事研发Endgame的HA-CFI ™产品多年,对大多数现代CPU上的性能监控单元(PMU)的展示方式已经非常熟悉。PMU是CPU的一个组件,通过对PMU编程可以计算每个内核上发生的特定低级事件的次数。在这种情况下,我们使用间接近程呼叫分支误预测(indirect near call branch mispredictions),当其中一个事件发生时,PMU会产生一个中断,执行我们的中断服务程序。在此例程中,我们有机会验证并实施策略。下面的视频演示了我们在系统被感染时检测DoublePulsar的实时方法(请到原文中查看视频)。
为了检测未支持的代码是否执行,我们会保留一个与加载的驱动程序相对应的内存范围列表,并验证指令指针是否位于其中一个范围内。但是,我们的概念证明存在一些缺点,比如说 PatchGuard本身使用非支持页面试图阻碍逆向工程。虽然抓住PatchGuard很有趣,但这种误报需要以可靠和稳健的方式解决,鉴于PatchGuard没有文档并且随时可能发生变化,这就造成了实现的难度。另一个缺点是内核代码能够对PMU进行编程,对系统知识很熟悉的攻击者就可以重新编程PMU或禁用中断。最后,与所有内核驱动程序一样,这种非支持检测驱动程序容易受到数据攻击,例如IAT修补或攻击我们的策略结构。
正如我们前面提到的,目前没有针对ROP(后流CFG)的内核保护机制。微软抵御ROP的计划需要英特尔控制流强制技术(CET)。但是这项技术在未来才有可能实现,CET在当今任何生产处理器中都是不存在的。
为了弥补其间的空白,我们提出了一种基于PMU的保护系统,它可以检测后流控制流策略是否违规。我们可以通过配置CPU的末尾分支记录(Last Branch Recorded,LBR)机制,将内核中的每个返回记录到循环缓冲区中,也可以通过扫描所有加载的驱动程序并识别调用指令来生成控制流策略,调用指令之后即是相应的返回站点。我们的策略是列出这些有效返回站点的位图,在启动时生成策略,并在加载新驱动程序时更新它。
为每个返回指令生成中断的代价太高。我们利用ROP倾向于产生大量分支误预测的事实,将PMU设为仅为错误预测的分支生成中断。当中断触发时,验证LBR中记录的每个返回地址,如果它们中的任何一个不在上述策略中(也就是先前没有调用),就认为控制流违规。如果不能正确调试这些系统,它们可能会产生太多中断并对系统性能产生负面影响。正如下面的演示所示,通过适当的调整,可以看到JetStream浏览器基准测试得分大约减少了1%,同时仍然保持100%的检测率。下面的最终演示将介绍内核模式ROP检测(请到原文中查看视频)。
结语
Windows平台安全性在过去十年中有了很大改进,但内核模式威胁仍然是一个大问题。要利用Microsoft的最新防御,您应该升级到最新的Windows 10并在系统中启用尽可能多的保障机制(Secure Boot,VBS,HVCI等)。从内核模式攻击者的角度来看,基于虚拟化的安全性是他们最大的痛点,但它同时也存在许多兼容性问题。确保您正在收集跨端点加载的驱动程序的遥测,利用此数据来发现正在加载的异常或易受攻击的驱动程序。最后,利用工具,您可以搜索和检测可能已存在于您的网络中的内核模式恶意软件。虽然这似乎是一项巨大的努力,但我们希望这两篇文章和两个开源工具有助于提高对内核模式威胁的认识,并在这些威胁发展时促进保护。