首款反射式PE壳<琥珀>简介
由于操作系统内部日益增加的安全标准和恶意软件检测技术的快速改进,现如今的恶意软件作者开始利用由内存执行。PE的内存执行或者无文件执行可以被定义为在内存中执行一个编译的PE文件,手动运行OS加载程序在正常PE文件加载时应有的操作。恶意软件的内存执行有助于混淆和反模拟技术。另外,正在使用这种方法的恶意软件在系统上留下的痕迹更少,因为内存执行没必要在硬盘上占有一个文件。内存执行方法和多阶段注入模型组合,可以使用及其小的程序加载器将恶意软件注入系统。加载程序的唯一目的是通过链接到远程系统来加载和执行实际的恶意软件代码。使用小型加载器的代码很难被安全产品检测,因为加载器的代码片段在合法应用程序中也普遍使用。使用这种方法的恶意软件仍然可以通过扫描内存并检查进程的行为来检测,但是在安全性方面,这些操作难以实施,因为资源使用量较高而且代价昂贵。(Ramilli, 2010[1])
目前普遍增长的趋势是使用机器学习机制自动检测恶意软件,给系统提供巨大的数据集,如所有的机器学习程序一样,这种机制可以更快更准确的吸收更多的恶意软件样本。这些机制可以提供大量的人类恶意软件分析师无法处理的级别的样本。Malware Detection Using Machine Learning[2]由BitDefender Romania Labs的 Gavriluţ Dragoş发表的这篇论文广泛的阐述了机器学习在恶意软件检测中的使用的内部原理。根据Konrad Rieck的论文 Automatic Analysis of Malware Behavior using Machine Learning[3],只要有足够的数据和时间,假阳性的结果将趋近于0,并且恶意软件的检测将在新的恶意软件样本上产生显著效果。
这项工作的主要目的是为PE文件开发一种新的加壳方法,可以改变将恶意软件传送到系统的方式。取代试图找到新的反检测技术来提供机器学习的数据集,通过无文件代码注入将payload加载到系统中从而绕过绝大多数的安全机制。通过这种新的加壳方法,可以将PE文件转化为可用于常见软件漏洞(如缓冲区溢出)的多阶段注入的payload。
已知方法
以下的技术是我们壳的灵感来源:
反射式DLL注入[4]是一个非常好的由 Stephen Fewer 开发的库注入技术,该方法是开发这个名为琥珀的壳的主要启发点。这种技术允许在内存执行中用反射编程的方法编写特定的DLL。由于采用了反射编程方法,这种技术允许多阶段payload的部署。除了这种技术的诸多优点之外几乎没有限制。第一个限制是所需的文件格式,该技术期望将恶意软件作为DLL文件进行开发或重新编译,不幸的是在大多数情况下,将已编译的EXE文件转换为DLL是不可能的,或者需要对二进制文件进行大量工作。第二个限制是需要重定位数据。反射型DLL注入技术需要重定位数据来调整内存中DLL的基址。同时,这种方法已经存在了一段时间了,这意味着最新的安全产品可以很容易的检测到反射型DLL注入的使用。我们的新工具,琥珀将为这些限制提供解决方案。
Process Hollowing[5]是另一种广为人知的内存执行方法,使用公开的WindowsAPI创建新的进程然后将PE文件映射进该进程。这种旨在降低恶意软件检测率的加密器和壳中很受欢迎。但是这个方法也有几个缺点。由于最新的Windows操作系统中的地址空间布局随机化(ASLR)安全措施,创建新进程时内存区域是随机的,因为process hollowing同样也需要实现在最新的Windows操作系统上的镜像基址重定位。如上所述,基址重定位需要PE文件内的重定位数据。另一个缺点是由于特定文件的映射和进程创建API函数的使用有特定的顺序,这种方法很容易被安全产品识别。
Hyperion[6] 是一款PE加密器,由Christian Amman 于 2012开发并发布。它解释了运行时加密器的理论知识以及实现原理。在开发Hyperion是使用的PE解析方法和设计视角对我们的POC壳很有帮助。
技术细节
通过模仿OS的PE加载器,可以在OS内存中执行编译的二进制文件是该壳的基本原理。在Windows上,PE加载器执行许多重要的事情,诸如将问价映射到内存并解析导入函数的地址是执行PE文件最重要的步骤。目前用于在内存中执行EXE文件的方法是使用特定的WindowsAPI函数来模拟WindowsPE加载器。通常的方法是使用NtMapViewOfSection
,MapViewOfFile
和CreateFileMapping
函数。这些函数的使用通常会造成可疑行为,增加恶意软件检测的可能性。开发这款壳的关键方面之一就是尽量减少API函数。为了避免使用可疑文件映射API函数,我们的壳使用预先封装的PE映像,此外,恶意软件的执行发生在目标进程内部,不使用WindowsAPICreateProcess
函数。目标进程内执行的恶意软件以相同的进程权限运行,因为它们共享了包含进程特权信息和配置的TEB块。琥珀有两种你类型的stub,其中一个用于支持ASLR,另一个用于被剥离或不具有任何重定位数据的EXE文件。ASLR stub仅使用4个Windows API,其他的stub仅使用3个大多数合法应用程序广泛使用的API。
ASLR stub:
VirtualAlloc
CreateThread
LoadLibraryA
GetProcAddress
非ASLR stub:
VirtualProtect
LoadLibraryA
GetProcAddress
为了在运行时调用这些API,琥珀使用了Stephen Fewer的反射式DLL注入[4]方法所使用的公开的EAT解析技术。该技术简单在内存中通过PEB来定位InMemoryOrderModulesList结构。定位该结构后,可以读取所有加载的DLL导出表,读取由InMemoryOrderModuleList指向的每个_LDR_DATA_TABLE_ENTRY结构。在访问到DLL的导出表之后,将先前计算出的每个导出函数名的ROR(右移)13散列值进行比较,直到匹配。琥珀的加壳方法还提供了集中替代的WindowsAPI使用方法,其中之一是使用固定的API地址,如果使用者熟知承载琥珀的远程进程的相关信息的话。使用固定API地址将直接绕过最新的操作系统级漏洞利用,检查导出表地址删除API地址查找代码将减少总体的payload大小。另一种替代技术可用于定位所需功能的地址,例如 Josh Pitts 在 “Teaching Old Shellcode New Tricks”[7]中展示的技巧。当前版本的琥珀加壳器仅支持固定API地址和EAT解析技术,但IAT解析将在下一个版本中添加。
生成payload
为了生成实际的琥珀payload,首先加壳器创建一个恶意软件的内存映像,生成的内存映射文件包含PE的所有部分,PE header和未使用的区段空间使用0填充。
获取恶意软件的映射之后,加壳器将检查所提供的EXE的ASLR的兼容性,如果EXE是ASLR兼容加壳器将添加相关的stub,如果PE使用固定基址就不添加。此刻,琥珀的payload就完成了:
ASLR Stub的执行
执行ASLR stub需要5个步骤:
- 申请内存
- 修复导入函数
- 重定位
- FileMapping替换
- 执行
在内存申请阶段,stub通过调用VirtualAlloc函数来分配恶意软件映像大小相同的RWE内存空间,
这个内存空间将是重定位过程后恶意软件新的基址。第二阶段,琥珀的stub将解析导入函数的地址,并将地址写入恶意软件的导入表。
地址戒心阶段与WindowsPE加载程序使用的方法非常类似,琥珀的stub将解析映射的恶意软件映像的导入表,并通过LoadLibraryA函数加载恶意软件的IMAGE_IMPORT_DESCRIPTOR中使用的每个DLL。
在加载完所需的DLL后,stub会保存每个DLL的句柄,并在GetProcAddressAPI的帮助下,从加载的DLL中查找导入函数的地址。IMAGE_IMPORT_DESCRIPTOR还包含一个指向名为import name表的结构指针,该结构的导入函数名与导入地址表(IAT)顺序相同,在调用GetProcAddress时,stub以前加载的DLL句柄和导入函数的名称为参数。每个返回的函数地址都将写入(IAT),每个IAT之间由4字节填充。此过程持续到导入表解析结束,加载完所需的DLL和解析完导入表之后,第二阶段完成。
在第三阶段,stub将根据VirtualAlloc返回的地址开始重定位过程,这几乎和Windows本身的PE加载器完全相同,stub首先计算当前加载基址和原始加载基址之间的偏移delta,然后将delta加上重定位白的每一个条目。在第四阶段,stub将文件映射到先前分配的空间中,采用单字节移动的方式来移动内存。
最后阶段,stub将通过调用CreateThread从恶意软件的入口处创建一个新的线程。创建新线程的原因是为恶意软件创建一个新的可扩展栈,另外在新线程中执行恶意软件并不会映像目标进程的执行状态。创建恶意软件后,线程将恢复执行,返回到第一个调用者或stub,然后跳转到一个死循环,阻塞防线线程,恶意软件线程成功运行。
非ASLR Stub的执行
非ASLR Stub的执行需要4个步骤:
- 内存申请
- 解析IAT
- 文件映射替换
- 执行
如果恶意软件被剥离或者没有重定位信息,则无法将其放到首选基地址。在这种情况下,stub尝试通过调用VirtualPtotect函数来更改目标进程的内存访问权限,大小为恶意软件的大小。如果出现这种情况,首选极其之和目标进程代码段可能由重叠,并且目标进程在执行payload后将无法执行。
stub可能无法更改指定区域的访问权限,这又多个原因,如执行的内存返回不在当前进程页边界内(原因最可能是ASLR),或执行的地址与stack guard重合。这是stub的主要限制,如果提供的恶意软件没有ASLR支持(内部没有重定位数据),并且stub不能更改目标进程访问权限,则无法继续。在某些情况下,stub成功更改内存区域权限,但立即崩溃,这是由于覆盖部分中运行着多个线程引起的。如果目标进程在fix stub执行时有多个线程,则可能会由于更改内存权限或覆盖到正在运行的部分崩溃。然而,如果不使用具有fix stub的多级payload,则这些限制无关紧要,当前的POC封装器可以相应的调整生成EXE文件的基址和stub payload的位置。如果内存分配结束,第一阶段就完成了。第二阶段与上边ASLR stub方法相同。完成后同样使用memcpy移动内存到先前修改的内存区域。
在最后阶段,stub跳转到恶意软件的入口点并执行,不创建新线程。不幸的是使用非ASLR stub的程序不能继续之前的运行状态。
多阶段程序
在不久的将来,操作系统将会采取的安全措施将会减少恶意软件的攻击面。微软已经在2017年5月2日发布了Windows 10 S[8],这个操作系统基本上是Windows10的配置了更高安全性的版本。这个操作系统采取的主要预防措施之一是不允许安装除WindowsStore以外的程序。这种操作系统采用的白名单方法将对通过可执行文件感染系统的恶意软件产生巨大影响。在这种情况下,多级内存执行payload将成为最有效的攻击方法之一。由于stub位置的独立性,它允许多阶段攻击模型,当前的POC加壳器能够从复杂的PE文件中生成一个payload,可以从内存加载和执行,如常规的shell code注入攻击。在这种过度限制的系统用中,琥珀的多阶段兼容性允许利用基于内存的常见软件漏洞,例如栈和堆的缓冲区溢出。
然而由于fix stub的限制,建议在执行多级感染攻击时使用ASLR支持的EXE文件。由POC加壳器生成的阶段payload与从Metasploit Framework [9]生成的小型加载器shellcode和有效载荷兼容,这也就意味着琥珀可以用于Metasploit Framework 中多级meterpreter shell code。
源码如下,欢迎fork以及contribute!
https://github.com/EgeBalci/Amber
被检出率
当前版本(2017.10.19)检测率令人相当满意,但由于这是一个公共项目,目前的检测分数不可避免的会上升。
当没有额外的参数传递(只有文件名)加壳器生成的多级载荷使用多字节随机密钥执行基本的XOR加密,然后将其编译成EXE文件,并加入少量额外的防检测功能。生成的EXE文件在解密payload并执行所需的环境检查之后,像常规的shell code一样执行payload。这个特殊的例子时用12字节XOR key(./amber mimikatz.exe -ks 12
)打包的mimikatz.exe(sha256- 9369b34df04a2795de083401dda4201a2da2784d1384a6ada2d773b3a81f8dad)文件。在VirusTotal上,加壳前的mimikatz.exe文件的检测率为51/66。在这个特殊的示例中,加壳程序使用默认方式来查找使用哈希API的Windows API地址,避免使用hash API会降低检测率。目前加壳器支持IAT偏移的固定地址的使用,下一个版本将包括IAT解析器shellcode以获得更多的替代API地址查找方法。
VirusTotal检测
VirusCheckmate Result
http://viruscheckmate.com/id/1ikb99sNVrOM
NoDistribute
https://nodistribute.com/result/image/7uMa96SNOY13rtmTpW5ckBqzAv.png
未来工作
这项工作为PE文件引入了新一代的加壳方法,但不支持.NET可执行文件,未来的工作可能包括对64位PE文件和.NET文件的支持。另外,这种方法的隐秘性方面可以有更多的改进。在使用RWE权限完成内存分配之后,根据映像对应的区段权限修改该区段对应内存的权限可能会降低检测率。在地址解析完成后擦除PE头可以更难检测。该项目在未来将继续保持开源。
参考链接
[1] Ramilli, Marco, and Matt Bishop. “Multi-stage delivery of malware.” Malicious and Unwanted Software (MALWARE), 2010 5th International Conference on. IEEE, 2010.
[2] Gavriluţ, Dragoş, et al. “Malware detection using machine learning.” Computer Science and Information Technology, 2009. IMCSIT’09. International Multiconference on. IEEE, 2009.
[3] Rieck, Konrad, et al. “Automatic analysis of malware behavior using machine learning.” Journal of Computer Security 19.4 (2011): 639-668.
[4] Fewer, Stephen. “Reflective DLL injection.” Harmony Security, Version 1 (2008).
[5] Leitch, John. “Process hollowing.” (2013).
[6] Ammann, Christian. “Hyperion: Implementation of a PE-Crypter.” (2012).
[7] Pitts, Josh. “Teaching Old Shellcode New Tricks” https://recon.cx/2017/brussels/resources/slides/RECON-BRX-2017 Teaching_Old_Shellcode_New_Tricks.pdf (2017)
[9] Rapid7 Inc, Metasploit Framework https://www.metasploit.com
[10] Desimone, Joe. “Hunting In Memory” https://www.endgame.com/blog/technical-blog/hunting-memory (2017)
[11] Lyda, Robert, and James Hamrock. “Using entropy analysis to find encrypted and packed malware.” IEEE Security & Privacy 5.2 (2007).
[12] Nasi, Emeric. “PE Injection Explained Advanced memory code injection technique” Creative Commons Attribution-NonCommercial-NoDerivs 3.0 License (2014)
[13] Pietrek, Matt. “Peering Inside the PE: A Tour of the Win32 Portable Executable File Format” https://msdn.microsoft.com/en-us/library/ms809762.aspx (1994)
原文链接https://pentest.blog/introducing-new-packing-method-first-reflective-pe-packer/
本文由看雪论坛zplusplus翻译。