内核模式威胁的最新技术与防御方式(第二部分)

阅读量    70337 |   稿费 200

分享到: QQ空间 新浪微博 微信 QQ facebook twitter

传送门

内核模式威胁的最新技术与防御方式(第一部分)
https://www.anquanke.com/post/id/160412

 

概述

在上一篇文章中,我们对内核模式威胁的演变进行了详细讲解。对于一些大型攻击团队来说,这仍然是一种首选方案,因为这种攻击难以被发现,并且能够保证具有较好的持久性。

诚然,随着时间的推移,各类安全机制和安全产品对计算机的保护也在逐渐加强,但与此同时,内核模式威胁也在不断地发展,并且已经应用到许多大规模的攻击之中,例如WannaCry和NotPetya。那么,针对安全人员来说,我们可以采取哪些措施来防御内核模式威胁呢?幸运的是,随着防御技术的不断发展,目前已经可以与这种攻击方式相抗衡。

通过我们的研究,我们得出了如何改进内核模式威胁防御方式的结论。在本文中,首先将会介绍研究过程,我们的这一研究从红蓝对抗中演变而来。随后,针对目前最新的攻击技术,将讨论几种内核模式威胁的防御方法。

 

攻击技术研究

为了测试和提升我们的防御方式,我们必须要充分理解最新的攻击技术。在内部开展的红蓝对抗期间,我们首先尝试着利用内核模式恶意软件来绕过终端安全产品和常见内核保护机制(例如:驱动程序签名强制执行DSE)。

随后,我们尝试了用于绕过最新内核保护机制的方法(例如:基于虚拟化的安全性VBS和管理程序代码完整性HVCI)。

红蓝对抗的收获

Endgame会定期组织红蓝对抗,以测试产品性能和团队能力。红队的任务是模拟不同级别的攻击者,其中包括非常复杂的商品化恶意软件和中高级APT攻击。通常情况下,我们红队成员都会使用最新的用户模式内存技术保持隐蔽。然而,随着蓝队水平的不断提升,他们已经能够有效防御我们的用户模式注入攻击。因此,我们决定研究内核模式,从而提升攻击的水平。

Turla Driver Loader(TDL, https://github.com/hfiref0x/TDL )是我们进行内核攻击的关键所在。TDL是Turla/Uroburos驱动程序加载技术的开源实现。简而言之,它将负责加载易受攻击的VirtualBox驱动程序。在这里,VirtualBox驱动程序被利用加载并执行任意内核Shellcode。TDL借助Shellcode构建,在用户模式下利用“MemoryModule”等技术手动映射任意驱动程序,并调用其入口点。通过使用TDL,可以帮助红队实现两个目标:绕过驱动程序签名强制执行、不会将驱动程序写入目标计算机的磁盘中。

除此之外,还有一些其他高级的植入物设计方案。首先,我们希望避免任何用户模式组件。有一个典型的设计方案就是使用内核模式组件,并注入到用户模式进程中,以执行主要“植入”功能。在这两篇文章中引用到的内核模式恶意软件,其中就包含一些用户模式组件。

避免用到用户模式需要耗费一定的时间,但我们认为是值得的。因为向用户模式中注入任何内容,都有可能被蓝队发现。由此,就要求我们从内核模式进行网络命令和控制。我们选择了Winsock Kernel(WSK)作为我们的网络选择,因为该工具的官方文档详尽,有较好的示例代码,提供了一个相对简单的接口,可以从内核进行网络通信。

为了进一步对抗蓝队,我们不希望有Beacon式的植入物。Beaconing是迄今为止最流行的恶意软件技术,我们也深知蓝方会努力找寻这样的恶意软件。但不幸的是,我们最初的端口开放很容易被他们发现。因此,我们通过重新使用DoublePulsar函数指针挂钩,劫持一些现有的内核套接字,从而实现了一种更为隐蔽的攻击方法。

但是,又因为它会被PatchGuard监控,我们不想使用相同的挂钩点。在筛选了众多的驱动程序之后,我们锁定了开放445端口的srvnet驱动程序。于是,我们在该驱动程序中寻找问题,并使用自己的accept函数挂钩srvnet的WskAccept函数。这样一来,我们的植入物就可以选择性地劫持445端口的流量。 使用TDL,就意味着我们的内核驱动程序永远不会在磁盘留下痕迹,但是仍然存在加载器可能被捕获的风险。因此,希望加载过程本身尽可能的无文件化。这样就要使用PowerShell或JavaScript链。我们之所以选择JS,是因为它相对更不容易被防守方察觉。

具体而言,使用了squiblydoo( https://attack.mitre.org/wiki/Technique/T1117 )技术,从regsvr32进程运行一个scriptlet,而不是通常的启动cscript/wscript自身。

在Black Hat会议上,我们做了实际的演示,过程中使用了SquiblyTwo( http://subt0x11.blogspot.com/2018/04/wmicexe-whitelisting-bypass-hacking.html )和winrm.vbs逃避技术( https://posts.specterops.io/application-whitelisting-bypass-and-arbitrary-unsigned-code-execution-technique-in-winrm-vbs-c8c24fb40404 )。
至此,我们已经确定,要使用DotNetToJS从JavaScript加载或执行任意.NET可执行文件。现在可以从这个.NET可执行文件中进行漏洞利用,并加载我们的驱动程序,执行此操作的代码可以使用C语言编写。

还有一个更容易的选择,就是使用MemoryModule样式的.NET加载器,加载并执行本地可执行文件。本地可执行文件(TDL)会加载易受攻击的VirtualBox驱动程序,并对其进行漏洞利用,将我们的植入物加载并映射到内存中。在这整个过程中,真正接触到本机磁盘的唯一可执行文件,就是合法的VirtualBox驱动程序。

无文件内核模式威胁的演示视频:https://youtu.be/7ACGx8CwctU

绕过VBS和HVCI

当我们决定参加Black Hat会议时,就打算要尝试扩大攻击的范围。目前,Microsoft将基于虚拟化的安全性(VBS)与管理程序代码完整性(HVCI)这两种机制相结合,能够有效地组织任何未经过签名的代码在内核中运行,这里也包括DoublePulsar以及我们为红蓝对抗所编写的植入物。

首先,我们发现了一个存在漏洞的驱动程序,因为在启动HVCI时,TDL的VirtualBox驱动程序不会加载。由此,我们从Parvez Anwar的网站( https://twitter.com/ParvezGHH )上获得了一个已知易受攻击的样本。接下来,就要选择要利用的漏洞了。

考虑到其难度,最终选择了易于利用的Write-*What-Where漏洞(在任何情况下攻击者能够将任意值写入任意位置),而没有选择例如静态单字节写入这样难度较大的漏洞。后者通常会涉及到一些池损坏(Pool Corruption,例如Win32k GDI对象),以实现完整的读写原语。

由于易受攻击的驱动程序在进行覆盖时会解除对用户提供的指针的引用,所以它还为我们提供了一个便捷的任意读取原语。

HVCI机制会阻止未签名的代码在内核中运行,但该机制无法保护内核模式数据的完整性。如果篡改关键的数据接口,可能会严重影响系统的完整性。

例如,攻击子和可以通过修改IAT,来“NOP”掉某些函数调用。攻击者可以禁用终端检测响应(EDR)产品与用户通信的内核,也可以禁用安全相关内核的Etw提供程序(例如:Microsoft Windows Threat Intelligence)。

此外,攻击者还可以利用数据损坏攻击(Data Corruption Attacks),借助修改Token或Handle来提升权限。除此之外,还有一些技术可以被利用。

为了尽可能模拟现实中的攻击,我们研究了sysmon驱动程序将事件从内核模式发送到用户模式(用于进行日志记录)的方法。最终发现,如果将导入地址表(Import Address Table)中的xor rax,rax ret gadget,事件就不再被记录。

现实中的攻击者,可以像这样阻止事件被记录,从而避免引起怀疑。需要指出的是,这并不是sysmon的一个漏洞,每个安全产品都可能会受到这样的数据损坏攻击。但是,Microsoft可能会扩展“基于虚拟化的安全性(VBS)”,从而保护不应被修改的某些关键数据区域(例如本示例中的导入地址表)。

尽管数据损坏攻击会引起他们的警惕,但我们还是想要探索是否能够实现任意代码执行。来自Microsoft BlueHat IL的Dave Weston发表过一篇演讲( https://www.youtube.com/watch?v=8V0wcqS22vc&t=1s ),其中透露了“基于虚拟化的安全性”的重要设计细节。

然而,它也给我们留下了如何应对执行流保护(Control Flow Guard)的难题。从本质上来说,在Windows内核中,目前仍然适合使用返回导向编程技术(Return Oriented Programming,ROP)实现攻击。

正如Peter Hlavaty在2015年的演讲( https://recon.cx/2015/slides/recon2015-05-peter-hlavaty-jihui-lu-This-Time-Font-hunt-you-down-in-4-bytes.pdf )中提到的,可以滥用读写原语来执行栈挂钩,从而通过ROP实现代码执行。我们觉得可以将这种技术用于对抗HVCI加固后的系统。

于是,首先创建一个代理线程作为挂钩的目标。在那里,我们的PoC将根据目标函数中的参数数量,动态构建ROP链。只需要10个Gadget,就能够实现完整的N-argument函数调用原语。

接下来,利用已经过签名并且存在漏洞的驱动程序,来破坏代理线程的内核堆栈,以便执行生成的ROP链。最终,PoC可以调用任意内核模式函数。在演示中,攻击者可以利用它来注入受保护的用户模式进程( http://www.alex-ionescu.com/?p=116 ),并且在较大程度上绕过了反病毒产品和终端检测响应产品。下面的视频演示了如何使用这种技术绕过HVCI机制:https://youtu.be/SCC_acwPQyo

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;
}

 

总结

在本文中,我们详细介绍了红蓝对抗中作为红方的攻击过程,向大家揭示了攻击者借助内核模式威胁进行攻击的一般思路与高级进阶思路。

最后,通过红蓝对抗中的经验,我们探寻了多种内核模式威胁的防御方法。然而,这些防御方法仅仅是原理层面的,针对一些运维人员或安全人员可能显得并不友好。

为此,我们开发了两款免费工具,帮助大家有效防御威胁。在下篇文章中,我们将深入分析这两个防护工具的开发历程和工作原理,以帮助大家更好地防御此种威胁。

分享到: QQ空间 新浪微博 微信 QQ facebook twitter
|推荐阅读
|发表评论
|评论列表
加载更多