一款基于Python 实现的恶意软件加载程序
研究人员最近调查了一个存在于用户启动文件夹中的可疑链接文件。该文件名为“sysmon.lnk”,看起来有点可疑。经过一番初步调查后,研究人员发现该链接正在执行恶意 Python 脚本,该脚本被用来向系统注入一个远程访问木马(RAT)。
分析期间,研究人员总共遇到了六个连续的有效载荷和一些非常有趣的新型攻击工具。最后,研究人员还尝试了一些自定义脚本,用于从最终的RAT中得到没混淆过的数据并提取配置。
分析过程如下:
研究人员偶然发现了一个可疑文件 (sysmon.lnk),它似乎位于用户的启动目录中。启动目录的本质是保存用户登录计算机时自动运行的文件。因为它看起来就像一个普通的文件夹,你所需要做的就是复制并粘贴一个文件到这个文件夹中,然后你就可以在重新启动之间继续保存。
这为合法程序提供了一种简单的方法,使其能够继续运行。由于它的简单性和隐蔽性,它是攻击者放置恶意软件和恶意文件的常见场所。
如上所述,这是一个 .lnk 文件(也称为快捷方式文件),它重定向到系统上的另一个文件或命令。检查 .lnk 文件可以告诉研究人员它指向哪里。
当研究人员检查 sysmon.lnk 时,研究人员发现它正在重定向到一个可疑的“ctfmon.exe”,并将“update.py”作为参数发送。两者都出现在一个可疑的目录中:
因此,研究人员检索了文件并进行了一些分析。
文件分析
首先,研究人员注意到 ctfmon.exe 的哈希在 VirusTotal 上竟然没有被检测到,研究人员一开始觉得这很有趣,但在查看文件信息后发现事情并没有那么简单。
该信息表明 ctfmon.exe 是一个重命名的 Python 解释器,确切地说,是一个IronPython解释器,它利用 Python 的一个分支来访问 .NET 库。这允许 Python 代码访问通常为 .NET 或 PowerShell 保留的深层 Windows 操作系统功能。这很有趣,并提供了足够的信息来进入 Python 文件。
研究人员可以看到原始文件ctfmon.exe在VirusTotal上没有检测到,因为从技术上讲,它是一个合法的解释器,而不是恶意文件。
下面,研究人员可以看到文件描述,这表明它是一个重命名的 IronPython 解释器,或者,研究人员也可以使用 PeStudio 或类似工具发现此信息。
这些信息足以确定 ctfmon.exe 文件的用途,因此研究人员转到 Update.py 文件,研究人员将其称为 stage1.py。
Stage1.py
研究人员首先将 Python 文件移动到虚拟机内的文本编辑器中,以防它是恶意程序。
这样研究人员就会得到一个相对较小的脚本,其中包含一个大的混淆字符串和一些混淆的变量名称。我们可以在此屏幕截图中看到完整的脚本:
这些脚本看起来非常混乱,所以研究人员清理了一下并添加了注释:
如果仔细检查,研究人员可以看到该脚本实现了四个主要功能:
Base64 解码混淆的字符串;
它将 Base64 解码的字符串转换为十六进制值的字节数组;
然后,它将每个字节的值减少 12(十进制);
最后,它执行结果数据;
通过复制混淆的字符串并在 CyberChef 中重新创建逻辑,研究人员能够检索另一个 Python 脚本,研究人员将其保存并命名为 stage2.py。解码逻辑如下:
Stage2.py
研究人员从 CyberChef 中复制了生成的脚本,并在文本编辑器中打开了 stage2,但他们很快注意到另一个混淆的字符串,以及一些与反射相关的导入库。反射是一种常用技术,用于从内存执行代码而无需将其保存到磁盘。
根据这些信息,研究人员假设脚本正在解码字符串并将结果加载到内存中以供执行。
在上面的截图中间,我们可以看到用于解码字符串的两个主要操作:
替换所有“!”带有字母“A”的感叹号;
Base64解码结果;
这看起来并不太复杂,所以研究人员返回到 CyberChef 并重新创建解码逻辑。这导致出现 一个MZ 标头,表明研究人员已成功解码数据并检索到一个可执行文件。研究人员保存了这个文件并将其命名为 stage3.bin。
stage3.bin
将 stage3 保存为可执行文件,这样就能够使用 PeStudio 和 Detect-It-Easy (DIE) 进行一些基本检查。综合分析,这是一个 .NET 文件,很可能是另一个阶段(基于存在引用 injector.pdb 的路径)。
下面,研究人员可以看到 DIE 将文件识别为 .NET 可执行文件,这意味着研究人员可以使用 Dnspy 或 ILspy 进行分析。
下面,研究人员还可以看到引用“injector.pdb”的 PDB 路径,这表明这可能是另一个进行某种注入的阶段:
由于研究人员现在知道这是一个 .NET 文件,因此将其转移到 Dnspy,此时研究人员可以查看文件的源代码。这可以在下面看到。
仅查看函数名称,研究人员就清楚地知道文件将要做什么。研究人员可以看到指示注入(VirtualAlloc、WriteProcessMemory 等)、动态库/函数加载(GetProcAddress、LoadLibrary)和解码(compress, decompress, base64_encode)的函数。在不详细查看代码的情况下,研究人员已经可以假设一个核心函数:一个混淆的有效载荷将被解码并注入到进程中。
浏览主函数,研究人员很快就找到了编码的有效载荷。结合前面的函数调用(Load、Decompress、Base64),研究人员可以假设数据是Base64解码然后解压加载到内存中的。
下面,研究人员可以看到编码后的字符串和相关的函数调用:
在编码数据的末尾,研究人员还观察到对 msbuild.exe 的引用。这很重要,因为它是发送给 Mandark.Load 方法的第二个参数。
接下来,研究人员浏览了 Mandark.Load 方法找到的内容,并确定 msbuild.exe 参数的重要性。
研究人员认为,发送给 load 方法的第二个参数成为注入的目标进程。研究人员还注意到ZwUnmapViewOfSection的使用,这表明这种类型的注入采用的是process hollowing技术。
研究人员认为 MSBuild 很可能是目标,因为它经常被允许执行默认的应用程序白名单工具,包括微软自己的Applocker。
此时,研究人员决定回到主函数并尝试解码注入的有效载荷。研究人员已经注意到使用了 Base64 编码和压缩。
研究人员迅速检查了解压缩方法以确认压缩类型,在本例中,它是 Gzip。
综合以上信息,研究人员能够使用 CyberChef 解码下一个有效载荷。这导致了可执行文件的另一个 MZ 标头。研究人员保存了这个文件并将其命名为 stage4.bin。请注意,此有效载荷可能已被注入到 msbuild.exe 进程中。
stage4.bin
在加载stage4.bin时,研究人员执行了一些基本的静态分析并确定它不是另一个 .NET 文件,因此研究人员无法使用 Dnspy。
下面,研究人员可以看到使用 DIE 检测到的编译器,这表明它是用 C++/C 而不是 .NET 编写的。
使用PeStudio时,研究人员注意到这个导出的函数,它对研究人员来说很重要,因为它表明这可能是另一个加载程序(通过术语“ReflectiveLoader”得出)。
通过进一步分析,研究人员在文件的调试部分注意到了这个引用。这包含另一个 PDB 路径和一个非常类似于 git 的文件夹结构。
对 PDB 路径中的一些关键字进行搜索后,研究人员相信该文件可能是一个执行程序集加载程序,它是 Cobalt Strike 执行程序集模块的开源重新实现:
在 GitHub 存储库文档的其余部分中,有一个特别的地方非常引人注目。表示嵌入的有效载荷结构,格式为“0|0|0|0|1|sizeofpayload.b64_encoded_compressed_payload”。有效载荷采用了Gzip 压缩和 Base64 编码格式。
这非常有趣,因为文件中有一个非常大的字符串,大小为 64983 字节,足够容纳另一个有效载荷的空间。
研究人员将该字符串复制到 CyberChef 中并重新实现了解码例程(Base64 和 Gzip 解压缩),从而生成了另一个可执行文件。
研究人员保存了这个文件并将其命名为 stage5.bin。
stage5.bin
在对最新的文件进行常规静态分析时,研究人员很快意识到它是另一个 .NET。幸运的是,研究人员可以跳回 Dnspy 并查看源代码。
进入 Dnspy,研究人员注意到这次的函数并不多,总共只有六个:
导航到主函数,研究人员注意到两个大的混淆字符串:
第一个只是 Base64 编码,结果证明这是一个反恶意软件扫描接口 (AMSI) 修补脚本。AMSI 由 Microsoft 实施,为安全工具提供了一个框架来监控 PowerShell 脚本活动。AMSI 补丁的目标是绕过此框架并降低防病毒或 EDR 检测到任何恶意 PowerShell 活动的机会。稍后,研究人员将看到恶意软件确实使用了 PowerShell 脚本,因此此补丁可能允许它们在不被检测到的情况下执行。
下面,研究人员可以看到完整的 AMSI 补丁脚本,它被轻微混淆了。
研究人员能够解码脚本,大致翻译如下:
第二个字符串更有趣,因为它结合了自定义编码例程以及研究人员迄今为止已经习惯的 Base64 和压缩。这表明研究人员需要的不仅仅是 CyberChef 来解码研究人员的下一个有效载荷。
为了更好地理解混淆,研究人员检查了 Cipher 方法并找到了编码例程。它看起来并不标准,而且很明显,它是定制的。像这样的例程通常被用来逃避自动分析,因为非标准性质阻碍了一些自动化工具,通常需要手动干预和分析才能正确解码。
下面,研究人员可以看到完整的自定义例程,它采用编码字符串、密钥和加密标志。
通过查看主函数,研究人员很快找到了密钥“avyhk”和设置为 false 的加密标志。
经过一些仔细的检查和分析,研究人员能够使用下面包含的等效 Python 代码重新实现该例程。
使用新的Python脚本,研究人员为密码函数编写了一个包装程序,它能够将解码的内容转储到一个新文件中。使用它,研究人员最终得到了另一个可执行文件:stage6.bin。
stage6.bin
研究人员将 stage6.bin 文件保存并加载到 PeStudio 和 DIE 中进行一些静态分析,并看到研究人员有另一个 .NET 文件。
总的来说,研究人员在 PeStudio 中没有发现任何特别有用的东西,所以研究人员开始分析Dnspy。研究人员能够确定该文件是远程访问木马 (RAT),可能来自 URSU恶意软件家族。
该恶意软件具有 RAT 的所有典型功能,包括收集和枚举系统信息的能力,以及从远程命令和控制服务器下载文件和命令的能力。
恶意功能分析
下面,研究人员可以看到最终 RAT 有效载荷功能的概述。
解密配置
在确定此恶意软件很可能是 RAT 之后,研究人员决定寻找 C2 服务器的指标以及研究人员可以用作攻击指标的任何配置设置,分析 Dnspy 中的 RAT 代码,研究人员发现了一种“InitializeSettings”方法,该方法从使用 AES256 加密的值加载配置数据,然后使用 Base64 进行编码。
这是在 InitializeSettings 方法中解密配置数据的代码:
下面,研究人员可以看到加载了经过AES256加密和base64编码的值。
在使用了解密代码之后,研究人员能够解密配置并提取包括端口号、互斥锁名称、版本和分组号,以及 C2 服务器的三个域。
枚举
通过对操作系统的查询组合,主要是通过 WMI 查询,恶意软件收集了以下信息发送到 C2 服务器:
目前正在运行防病毒和安全产品;
用户权限;
受害者是否连接到某个域;
当前设备的外部IP;
打开的窗口和活动进程的名称;
反分析检查
在枚举系统信息后,恶意软件会执行一些反分析检查,以查看它是否在虚拟机或分析环境中运行。
该恶意软件包含多种检测方法和功能。这些检查相对简单,包括五个主要检查:
DetectManufacturer:在硬件描述中查找 VMware 或 VirtualBox;
DetectDebugger:检查“Debugger.IsAttached”标志,还会检查 %appdata% 目录中是否存在 dnspy.xml 文件;
DetectSandboxie:查找 Sandboxie 驱动程序 (sbiedll.dll);
IsSmallDisk:检查磁盘大小是否小于 61GB;
IsXP:检查当前操作系统是否为 Windows XP;
如果上述检查中的任何一项为真,则恶意软件会使用“failFast”方法进行清理并自我终止。
实现持久化:运行密钥和计划任务
完成反分析检查后,恶意软件会根据当前权限级别通过计划任务和运行密钥建立进一步的持久性。
如果管理员权限可用,则会创建提升的计划任务。这将允许恶意软件在重新启动时保持管理员级别的权限,而无需每次都发出 UAC 提示。
如果只有标准用户权限可用,则会将 .bat 脚本放入当前用户的运行密钥中,这将提供标准用户权限的持久性。
使用这些指标,研究人员能够找到恶意软件留下的其他工件,并开发可用于对类似活动发出警报的检测。
研究人员可以通过定期查看以下运行密钥和计划任务位置,通过计划任务和运行密钥检查类似的持久性:
C2 命令和功能
一旦建立持久性,恶意软件就会联系命令和控制服务器以获取进一步的命令,比如通过 PowerShell 下载新的恶意软件,启动它,然后终止当前进程。
参考及来源:https://www.huntress.com/blog/snakes-on-a-domain-an-analysis-of-a-python-malware-loader