红蓝对抗秘籍:如何使用Shellcode逃避检测并隐藏在终端上 - 嘶吼 RoarTalk – 网络安全行业综合服务平台,4hou.com

红蓝对抗秘籍:如何使用Shellcode逃避检测并隐藏在终端上

41yf1sh 技术 2020-01-06 10:02:00
1023766
收藏

导语:本文主要是FireEye Mandiant Red Team的经验分享,探讨了我们如何制作Payload以绕过当今的EDR产品,以及如何在目标系统上获得完整命令与控制(C2)。

概述

在红蓝对抗中,作为红队,除了需要发起攻击之外,还需要关注的就是如何能避免被发现。一个经验丰富的红队,其攻击行为往往不会被任何蓝队成员或系统运维人员发现。随着近年来终端检测与响应(EDR)产品的不断发展,可疑攻击行为被发现的概率也随之增加,因此对于红队来说,也必须不断发展他们的技术。本文主要是FireEye Mandiant Red Team的经验分享,探讨了我们如何制作Payload以绕过当今的EDR产品,以及如何在目标系统上获得完整命令与控制(C2)。

对于我们来说,Shellcode注入和Shellcode执行是在目标系统上运行C2 Payload的最立项方法。那么,什么是Shellcode呢?Michael Sikorski将Shellcode定义为“通常用于描述任何独立的可执行代码的专有名词”。大多数商业渗透测试框架(例如:Empire、Cobalt Strike或Metasploit)都在其工具中内置了Shellcode生成器。Shellcode生成器通常采用二进制格式或十六进制格式,具体取决于我们是希望生成原始输出,还是将其作为应用程序源。

为什么我们所有的Payload都希望使用Shellcode?

在红队进行攻击的过程中,如果使用Shellcode,就能在Payload类型选择上具有很高的灵活性。Shellcode运行程序可以使用多种编程语言编写,这些语言可以合并到多种类型的Payload中。这样的灵活性可以让我们自定义Payload,以满足客户的特定需求,或符合红队在安全评估期间可能出现的任何特定情况。由于Shellcode可以从Payload内部启动,也可以注入到已经运行的进程中,因此我们可以使用多种技术来提高Payload逃避EDR产品检测的能力,具体要取决于目标环境中使用的场景和技术。目前,有几种技术可以用来混淆Shellcode,例如加密、自定义编码等,这使EDR产品很难直接检测到商业C2工具中的Shellcode。总而言之,Shellcode具有的灵活性和逃避检测的特性,是我们在红队评估过程中高度依赖基于Shellcode的Payload的主要原因。

Shellcode注入与执行

红蓝对抗中最关键的一项工作就是开发Payload,这一Payload需要成功、可靠且隐蔽地运行在目标系统上。Payload可以从其自身的进程中执行Shellcode,也可以将Shellcode注入到另一个最终执行Shellcode的进程的地址空间。就本文而言,我们讨论的Shellcode注入是指“在远程进程中执行的Shellcode”,我们讨论的Shellcode执行是指“在Payload进程中执行的Shellcode”。

Shellcode注入是红队和恶意攻击者用于逃避EDR产品和网络防御设备检测的一种技术。有许多EDR产品都基于Windows进程的预期行为进行检测。例如,EDR产品认为进程通常不应该访问lsass.exe,因此从任意进程(例如:DefinitelyNotEvil.exe)的上下文中执行Mimikatz的攻击者可能会被EDR检测并阻止。但是,通过注入经常接触lsass.exe的Windows进程(例如:svchost.exe),可能就会绕过这些检测机制,因为EDR产品会将其视为预期的行为。

在本文中,我们将介绍三种运行Shellcode的技术,分别是:

1、CreateThread

2、CreateRemoteThread

3、QueueUserAPC

上述三种技术各自对应一个Windows API函数,这个函数负责将线程分配给Shellcode,最终导致Shellcode执行。CreateThread是用于执行Shellcode的技术,而CreateRemoteThread和QueueUserAPC是用于Shellcode注入的技术。

下面我们来详细对这三种技术进行描述。

CreateThread

1、在当前进程中分配内存;

2、将Shellcode复制到分配的内存中;

3、修改新分配内存的保护,允许从该内存空间中执行代码;

4、用分配的内存段的基址创建一个线程;

5、等待线程句柄返回。

CreateRemoteThread

1、获取要注入进程的进程ID;

2、打开目标进程;

3、在目标进程内分配可执行内存;

4、将Shellcode写入分配的内存;

5、使用分配的内存段的起始地址,在远程进程中创建线程。

Windows API调用CreateRemoteThread注入:

1570849003993606.png

QueueUserAPC

1、获取要注入进程的进程ID;

2、打开目标进程;

3、在目标进程内分配内存;

4、将Shellcode写入分配的内存中;

5、修改新分配内存的保护,以允许从该内存空间中执行代码;

6、使用分配的内存段的起始地址,在远程进程中打开一个线程;

7、在进入“alertable”状态时,将线程提交到队列中,以便执行;

8、恢复线程,进入“alertable”状态。

Windows API调用QueueUserAPC注入:

1570849013924465.png

命令执行

接下来,我们来拆分一下到目前为止所讨论的内容:

1、恶意代码就是我们的Shellcode,也就是真正要执行恶意工作的第0阶段或第1阶段代码。

2、标准的“Shellcode Runner”应用程序,可以通过注入或执行来运行代码。大多数人都会编写自定义的Shellcode运行程序,因此实际上这并不一定是真正的恶意软件,真正的恶意软件是Shellcode本身。

现在,我们已经回顾了所有之前的内容,我们需要一种方法来执行编译的代码。通常,会使用到可执行文件(EXE)或动态链接库(DLL)。作为红队,更倾向于使用“Living Off the Land”的二进制文件(lolbins)命令,该命令将执行我们已经编译后的代码。

之所以我们利用lolbins,是因为导出不受限制。在一个较高的级别上,当可执行文件调用DLL时,会在DLL中寻找特定的导出,以执行该导出中的代码。如果导出没有得到充分的保护,那么就可以得知可执行文件正在寻找的导出名称,从而可以制作自定义的DLL并运行我们的任意代码。在实际场景中,也就是我们的Shellcode Runner。

组合

我们的目标是开发一个Shellcode运行程序DLL,该DLL通过非托管的导出利用lolbins,同时还具备执行已注入或未注入的Shellcode的灵活性,无需更新代码库。这一过程将会产生一个名为DueDLLigence的C# Shellcode运行程序,其源代码可以在GitHub页面(https://github.com/fireeye/DueDLLigence)上找到。

DueDLLigence项目提供了一种快捷而简便的方法,可以通过简单地切换下图所示的全局变量的值,在不同的Shellcode技术(本文先前所述)之间进行切换。

控制Shellcode技术的变量:

1570849037569752.png

DueDLLigence DLL包含三个非托管的导出。这些导出可以与Rasautou、Control以及Coregen本地Windows命令一起使用,如下表所示。这里示例中的Shellcode仅会弹出计算器(calc)。

(1)本地Windows可执行文件:Rasautou

需要的导出名称:Powershell

运行语法:rasautou –d {DLL的完整路径} –p powershell –a a –e e

(2)本地Windows可执行文件:Control

需要的导出名称:Cplapplet

运行语法:将已编译的“dll”扩展名重命名为“cpl”,然后双击。

(3)本地Windows可执行文件:MSIExec

需要的导出名称:Dllunregisterserver

运行语法:msiexec /z {DLL的完整路径}

当我们打开源代码时,会发现该示例使用下图所示的导出。

导出入口点的源代码:

1570849048696906.png

我们最先应该进行的,就是生成自定义的Shellcode。下图展示了一个示例。在这里,我们使用Cobalt Strike为“rev_dns”监听器生成原始的Shellcode。完成后,我们在Linux中运行base64 -w0 payload.bin > [outputFileName]命令,来生成Shellcode的Base64编码后版本,如下图所示。

生成Shellcode:

1570849058995074.png

将Shellcode转换为Base64:

1570849067314384.png

随后,我们只需要将第58行Base64编码后的Shellcode替换为自定义的x86/x64 Shellcode的Base64编码后版本即可。在上图中,生成了一个x86 Payload,如果实际需要生成x64版本的Payload,可以选中其中的“use x64 payload”选项。

此时,我们应该在Visual Studio项目DueDLLigence中重新安装非托管导出库,以避免我们在使用其他项目时无法正常工作。我们可以重新进行安装,打开NuGet软件包管理器控制台(如下图所示),然后运行Install-Package UnmanagedExports -Version 1.2.7 command。

打开NuGet程序包管理器:

1570849075830382.png

在重新安装非托管导出库,并在第58行替换Base64编码后的Shellcode之后,就可以开始编译了。我们继续构建源代码,然后在bin文件夹中查找我们的DLL。在这里,我们强烈建议对DLL进行测试,以确保它具有正确的导出关联。Visual Studio Pro附带了Dumpbin.exe实用程序,我们可以使用它来运行DLL来查看导出,如下图所示。

Dumpbin.exe输出:

1570849085253515.png

我们可以根据需要,在GitHub页面上找到更多lolbin技术来扩展这个列表。

在实际中,我们更倾向于删除不与生成的相应Payload共同使用的非托管导出,从而使Payload的体积缩小。在制作Payload或编写代码时,这是一个非常好用的技巧。在安全领域,大家比较熟知的是“最小特权原则”,而上述技巧实际上是我们的“最小代码原则”。

当前Shellcode注入的检测方式

尽管Shellcode提供了逃避检测的优势,但作为蓝军成员,也还是有希望成功检测到Shellcode注入的。我们研究了几种不同的进程注入方法。

在我们的Shellcode Runner中,Shellcode注入技术(CreateRemoteThread和QueueUserAPC)以挂起状态生成一个进程,然后将Shellcode注入正在运行的进程。假设我们选择要注入的进程为explorer.exe,并且Payload将与MSIExec一起运行,这将创建一个进程树,其中cmd.exe将派生出msiexec.exe,而msiexec.exe又将生成Explorer.exe。

进程树分析:

1570849117293968.png

在企业环境中,可以使用SIEM收集遥测数据,以确定在所有终端上出现cmd.exe -> msiexec.exe -> explorer.exe进程树的频率。借助父进程与子进程的关系,防御者可以通过异常检测来识别出潜在的恶意软件。

EDR和反病毒产品通常使用API挂钩来监控和检测恶意软件作者常用的Windows API调用的使用情况。利用像PsSetCreateProcessNotifyRoutine(Ex)和PsSetCreateThreadNotifyRoutine(Ex)这样的内核例程,安全软件可以监控何时使用某些API调用(例如:CreateRemoteThread)。将上述信息与其他数据(例如:进程信誉、企业整体范围遥测数据)结合使用,就可以针对潜在的恶意软件产生准确度较高的告警。

在发生进程注入时,一个进程会修改另一个进程的地址空间中某个内存区域的内存保护。我们检测API调用(例如:VirtualProtectEx,可导致一个进程修改另一进程使用的地址空间的内存保护),特别是PAGE_EXECUTE_READWRITE权限的使用,该权限允许在相同的内存空间中编写和执行Shellcode。

随着红队和恶意行为者不断开发新型进程注入技术,蓝队和安全软件也在持续适应不断变化的环境。对Windows API函数调用(例如:VirtualAllocEx、VirtualProtectEx、CreateRemoteThread和NTQueueAPCThread)的监控可以提供有价值的数据,能帮助我们识别潜在的恶意软件。对带有CREATE_SUSPENDED和CREATE_HIDDEN标志的CreateProcess的使用情况进行监控,可能有助于我们检测进程注入,因为攻击者往往会在其中创建要注入的暂停和隐藏进程。

1570849124310382.png

如我们所见,进程注入技术倾向于遵循一定的顺序,通常会调用Windows API函数。例如,两种注入技术都先调用VirtualAllocEx,然后调用WriteProcessMemory。监测进程是否按照上述顺序调用这两个API,实际上就可以检测是否存在进程注入的风险。

总结

在开展安全评估的过程中,如果使用Shellcode作为Payload的最后阶段,可以使红队更加灵活地在广泛的环境中执行Payload,同时也能够逃避检测。DueDLLigence Shellcode Runner是一个动态工具,它利用Shellcode和进程注入的特性,为红队提供了一种逃避检测的方法。而作为蓝队,考虑到随着越来越多的防御方案都采用应用程序白名单的形式,攻击者目前也越来越多地使用“Living off the land”的方式,因此我们建议应该将“在命令行中检测LOLbins的执行情况”和“在API和进程级别检测进程注入”纳入到防御方案之中。

本文翻译自:https://www.fireeye.com/blog/threat-research/2019/10/staying-hidden-on-the-endpoint-evading-detection-with-shellcode.html如若转载,请注明原文地址:
  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论

 
本站4hou.com,所使用的字体和图片文字等素材部分来源于原作者或互联网共享平台。如使用任何字体和图片文字有侵犯其版权所有方的,嘶吼将配合联系原作者核实,并做出删除处理。
©2022 北京嘶吼文化传媒有限公司 京ICP备16063439号-1 本站由 提供云计算服务