导语:本研究的主要主题是对两个版本的DotRunpeX注入器进行深入分析,对比它们之间的相似之处,并介绍用于分析新版本的DotRunpeX的PoC技术,因为它是由自定义版本的KoiVM .NET protector.虚拟化传播的。
在过去的几个月里,CPR一直在监测DotRunpeX恶意软件以及它在野外的使用情况。监测显示,这种新型的网络注入器仍在不断发展中。CPR发现了几种不同的传播方法,在发现的所有示例中,DotRunpeX都是第二阶段感染的一部分。这种新的威胁被用来传播许多不同的恶意软件家族,主要与窃取程序、RAT、加载程序和下载程序有关。
与新版DotRunpeX相关的最早示例的日期为2022.10.17。关于这一威胁的首次公开信息发布日期为2022.10.26年。
本研究的主要主题是对两个版本的DotRunpeX注入器进行深入分析,对比它们之间的相似之处,并介绍用于分析新版本的DotRunpeX的PoC技术,因为它是由自定义版本的KoiVM .NET protector.虚拟化传播的。
主要发现
Check Point Research(CPR)对DotRunpeX注入器及其与旧版本的关系进行了深入分析;DotRunpeX受到虚拟化(KoiVM的自定义版本)和混淆(ConfuserEx)的保护;
调查显示,DotRunpeX在野外被用来传播许多已知的恶意软件家族;
通常通过网络钓鱼电子邮件作为恶意附件和伪装成常规程序的网站进行传播;
CPR确认并详细说明了恶意使用易受攻击的进程资源管理器驱动程序来禁用反恶意软件服务的功能;
本文会介绍几种PoC技术,这些技术已被批准用于反向工程受保护或虚拟化的dotnet代码;
DotRunpeX是一种使用Process Hollowing技术在.NET中编写的新注入器,用于感染各种已知恶意软件家族的系统。尽管这种注入器是新的,但与旧版本有一些相似之处。此注入器的名称基于其版本信息,在dotRunpeX的两个版本中都是一样的,在CPR分析的所有示例中都是一致的,并且包含ProductName–RunpeX.Stub.Frame。
在CPR监测这一威胁的同时,CPR发现了一些主要由独立研究人员公开共享的信息,这些信息与DotRunpeX的功能有关,但被错误地归因于另一个著名的恶意软件家族。
CPR通过对这一威胁连续进行几个月的监测,CPR获得了足够的信息来区分第一阶段和第二阶段(DotRunpeX)加载程序,但没有迹象表明它们之间存在关系。在各种下载程序和加密货币窃取程序中,CPR发现了这些由dotRunpeX传播的已知恶意软件家族:
AgentTesla
ArrowRAT
AsyncRat
AveMaria/WarzoneRAT
BitRAT
Formbook
LgoogLoader
Lokibot
NetWire
PrivateLoader
QuasarRAT
RecordBreaker – Raccoon Stealer 2.0
Redline
Remcos
Rhadamanthys
SnakeKeylogger
Vidar
XWorm
DotRunpeX传播的恶意软件家族
从发生的时间顺序来看,基于DotRunpeX示例的编译时间戳,这种新的威胁主要在2022年11月和2023年1月开始流行。
DotRunpeX时间轴——编译时间戳
感染途径
DotRunpeX注入器通常是原始感染的第二阶段。典型的第一阶段是.NET加载程序/下载程序的非常不同的变体。第一阶段加载程序主要通过钓鱼电子邮件作为恶意附件(通常是“.iso”、“.img”、“.zip”和“.7z”的一部分)或通过伪装成常规程序实用程序的网站进行传播。除了最常见的感染途径外,DotRunpeX的客户还很善于滥用谷歌广告,甚至通过木马恶意软件构建器构建其他潜在的攻击者。
钓鱼邮件“Transaction Advice 502833272391_RPY - 29/10/2022”将第一阶段加载程序作为恶意“.7z”附件的一部分传播第一阶段加载程序,导致加载DotRunpeX(SHA256:“457cfd6222266941360fdbe36742486ee12419c95f1d7d3502243e795de28200e”)。
钓鱼邮件“Transaction Advice 502833272391_RPY - 29/10/2022”
钓鱼网站会伪装成常规程序实用程序(Galaxy Swapper、OBS Studio、洋葱浏览器、Brave Wallet、LastPass、AnyDesk、MSI Afterburner),并提供第一阶段加载程序,导致dotRunpeX在第二阶段的一部分被感染。
伪装成Galaxy Swapper的网站:https://www.galaxyswapper[.]ru/:
在谷歌搜索Galaxy Swapper得到的结果“https://www.galaxyswapper[.]ru/”
下载重定向到https://gitlab[.]com/forhost1232/galaxyv19.11.14/-/raw/main/galaxyv19.11.14.zip。
“https://www.galaxyswapper[.]ru/”上的下载按钮重定向到一个木马程序
伪装成LastPass密码管理器的网站:http://lastpass[.]shop/en/
网站“http://lastpass[.]shop/en/”伪装成LastPass密码管理器
LastPass密码管理器的假冒网站在调查时已经关闭。尽管如此,CPR可以确认该假冒软件是从“最终URL”https://gitlab[.]com/forhost1232/lastpassinstaller/-/raw/main/LastPassInstaller.zip下载的。
“http://lastpass[.]shop/en/” 上的下载按钮重定向到一个木马程序
GitLab页面https://gitlab[.]com/forhost1232包含数十个被DotRunpeX恶意软件木马化的程序。
GitLab存储库“https://gitlab[.]com/forhost1232”上的数十个木马程序
在前面提到的GitLab页面上,所有的木马程序都包含了主.NET应用程序,并通过覆盖层进行了放大,以避免使用沙盒进行扫描。
由GitLab存储库" https://gitlab[.]com/forhost1232 "提供的木马程序示例
上面提到的带有覆盖的.NET应用程序是典型的第一阶段,其行为就像带有简单混淆的dotnet加载程序。这些不同的加载程序变体在第二阶段使用反射来加载DotRunpeX注入器。其中有些非常简单,有些则更高级。
简单的第一阶段加载程序(System.Reflection.Assembly.Load()方法):
简单的第一阶段加载程序
下面可以看到更高级的第一阶段加载程序的示例(使用AMSI Bypass和DynamicMethod通过反射加载和执行第二阶段加载程序)。这种高级加载程序的优点是没有直接引用System.Reflection.Assembly.Load()方法,因此它可以避免检测依赖于.NET元数据静态解析的引擎。
使用AMSI绕过和DynamicMethod的更高级的第一阶段加载程序
后一种的去混淆形式如下图所示:
更高级的第一阶段加载程序的去混淆形式
从这些类型的加载程序中提取第二阶段(DotRunpeX阶段)的编程方式可以简单地使用AsmResolver和反射来实现,如下所示。
使用AsmResolver和反射从第一阶段加载程序提取DotRunpeX
值得注意的是,那些指向GitLab页面的钓鱼网站的示例只与一个活动有关,在这个活动中,DotRunpeX注入器总是负责注入带有C2–77.73.134.2的Redline恶意软件。
除了前面提到的最常见的感染途径外,CPR还观察到了一个非常有趣的感染途径示例,在这个示例中,DotRunpeX的一位客户可能已经厌倦了以普通受害者为目标,并决定以其他潜在的攻击者为目标。Redline构建器Redline_20_2_crack.rar (SHA256: “0e40e504c05c30a7987785996e2542c332100ae7ecf9f67ebe3c24ad2468527c”)被下载程序木马化,该下载程序使用反射来加载dotRunpeX作为构建器的隐藏“添加功能”。
木马化的Redline构建器的文件夹结构
事实证明,在Redline的构建过程中,根据需求进行配置,使用者还将获得另一个Redline示例。
使用反射来加载DotRunpeX的下载程序,该下载程序传播另一个Redline恶意软件
旧版本的DotRunpeX:
使用自定义混淆:仅对名称进行混淆;
配置有限(有效负载注入目标、提升+UAC绕过、有效负载解密的XOR密钥);
只有一种UAC绕过技术;
使用简单的XOR对要注入的主要有效负载进行解密;
使用D/Invoke类似的技术来调用本机代码(基于使用GetDelegateForFunctionPointer()),但使用诱饵系统调用例程;
使用D/Invoke重新映射" ntdll.dll "
新版本的DotRunpeX:
由自定义版本的KoiVM虚拟程序保护;
高度可配置(禁用反恶意软件服务,反虚拟程序,反沙盒,持久性设置,有效负载解密密钥,UAC绕过方法);
更多的UAC绕过技术;
使用简单的XOR来解密要注入的主要有效负载(在最新开发的版本中省略了);
滥用procexp驱动程序(Sysinternals)阻止受保护进程(反恶意软件服务);
基于俄罗斯procexp驱动程序的标志名称 Иисус.sys 翻译过来就是“jesus.sys”;
两个版本的相似之处:
用.NET编写的64位可执行文件“.exe”;
用于注入几个不同的恶意软件家族;
使用简单的XOR对要注入的主要有效负载进行解密;
可能使用相同的UAC绕过技术(新版DotRunpeX提供了更多技术);
UAC绕过技术
使用相同的版本信息;
DotRunpeX版本信息
使用相同的.NET资源名称BIDEN_HARRIS_PERFECT_ASSHOLE来保存要注入的加密有效负载:
新旧版本的Dotnet资源名
使用相同的代码注入技术——Process Hollowing;
使用相同的结构化类定义本机委托;
用于定义Native委托的相同结构化类
完整的技术分析——旧版本的DotRunpeX
对于旧版本的DotRunpeX的分析,使用了示例SHA256:“65cac67ed2a084beff373d6aba6f914b8cba0caceda254a857def1df12f5154b”。这个示例是一个用.NET编写的64位可执行文件“.exe”,实现了自定义的混淆——只对名称进行混淆。CPR分析的所有示例的版本信息都是一致的,CPR可以注意到ProductName - RunpeX.Stub.Framework,这可能是某种CPR正在处理网络注入器的第一个提示。
旧DotRunpeX版本信息
为了方便介绍,CPR对方法名称、参数和局部变量进行了部分清理。就在Main()方法中,CPR可以看到资源BIDEN_HARRIS_PERFECT_ASSHOLE的简单XOR解密,该资源包含要注入的加密有效负载。CPR分析的所有示例的资源名称都是一致的。
主要方法导致嵌入式有效负载的简单XOR解密
CPR还可以看到具有类名UAC的名称空间UACBypass,此类实现了UAC(用户帐户控制)绕过方法,但未配置为在此示例中使用。
UAC绕过方法
方法Inject()实现了一种称为“Process Hollowing”的代码注入技术。下图显示了一个正在生成处于挂钩状态的进程。
创建挂钩的流程作为Process Hollowing技术的一部分
这种技术在恶意软件开发领域并不新鲜。尽管如此,一旦CPR检查了这个示例的P/Invoke(允许从托管代码访问非托管库中的结构、回调和函数的技术)定义的方法,就可以立即发现一些有趣的东西。这些方法可以在ImplMap表中看到,该表是.NET元数据的一部分。
ImplMap表——旧版本的DotRunpeX
必须使用某些WIN API或NT API来执行Process Hollowing技术。正如CPR在ImplMap表中看到的那样,缺少了一些最关键的API。更具体地说,CPR看不到任何与取消映射和写入远程进程内存相关的API。这背后的原因是使用D/Invoke框架来调用某些通常会引起注意的NTAPI例程。
D/Invoke包含功能强大的原语,这些原语可以智能地组合在一起,以精确地从磁盘或内存动态调用非托管代码。它依赖于dotnet方法GetDelegateForFunctionPointer()的使用和相应的委托定义。
在这种情况下,NT API ZwOpenSection、ZwMapViewOfSection、ZwUnmapViewOfSection、NtClose、NtWriteVirtualMemory、NtResumeThread和RtlMoveMemory是通过D/Invoke实现的。委托的相应定义如下所示。
用于定义Native委托的类
更有趣的是,通过D/Invoke实现的4个NT api (ZwUnmapViewOfSection, NtWriteVirtualMemory, NtResumeThread, RtlMoveMemory)使用了一些可以被认为是添加的PoC技术,而不是原始D/Invoke框架的一部分——系统调用补丁。例如,CPR可以通过CallNtWriteVirtualMemory()方法检查NtWriteVirtualMemory调用是如何实现的。
导致系统调用修复的D/Invoke实现示例
首先,我们可以看到MapDllandGetProcAddress()方法中D/Invoke框架的用法发生了变化。每次调用此方法时,它都会重新映射指定的库,并获得所需函数的地址。在返回所需函数的地址之前,使用指针算术将指针移动4个字节,使其指向系统调用号的地址。在这种情况下," ntdll.dll "模块被重新映射,返回NT API例程NtWriteVirtualMemory的地址,偏移量为4个字节。
改变了D/Invoke的用法,它返回指向系统调用号的地址
NtWriteVirtualMemory地址改变了4个字节的偏移量,指向它的系统调用号
模块的重新映射被用作逃避杀毒软件和反调试技术,因为它会导致解除挂钩并删除所有设置的软件断点。某个本机函数的获取地址是通过典型的D/Invoke实现——DynGetProcAddress()来实现的,它负责在内存中解析PE结构,以查找指定例程的地址。
通过D/Invoke实现的PE结构的典型内存解析
正如我们在本例中看到的那样,DynGetProcAddress()也用于查找NT API NtAddBootEntry的地址,CPR可以将其称为诱饵例程。诱饵例程地址将用于系统调用修复。
用于系统调用修复的诱饵例程NtAddBootEntry
正在获取NtWriteVirtualMemory例程的地址,该地址修改了4个字节的偏移量(系统调用号的地址);
获取诱饵例程NtAddBootEntry的地址;
从修改后的NtWriteVirtualMemory地址复制2个字节(即使系统调用号是DWORD,这2个字节足够了,并且代表NtWriteVirtualMemory的系统调用号)到字节字段SyscallStub(该字段包含系统调用存根代码);
使用字节字段SyscallStub修复NtAddBootEntry的地址;
分解SyscallStub的默认值会更明显地说明为什么恰好有2个字节被NtWriteVirtualMemory例程修改地址的字节所替换。这两个字节表示要调用的某个实函数的系统调用号。
分解字节字段SyscallStub的默认值
简单地说,一旦调用NtWriteVirtualMemory函数,CPR将从用户模式中看到的唯一内容就是调用NtAddBootEntry。
CPR使用WinDbg“内核模式调试”来验证上述执行流,可以看到,原始系统调用编号为0x6a的NT API NtAddBootEntry(在CPR的目标系统上)被用作修复的诱饵例程。在需要调用NtWriteVirtualMemory的情况下,诱饵例程的系统调用号会用系统调用号0x3a(目标系统上的NtWriteVirtualMemory系统调用号)进行修复,并被调用。
WinDbg“内核模式调试”显示了系统调用修复导致的执行流
本文翻译自:https://research.checkpoint.com/2023/dotrunpex-demystifying-new-virtualized-net-injector-used-in-the-wild/如若转载,请注明原文地址