导语:本文就以 Roshtyak 后门为例介绍恶意软件的自保护、杀软逃逸技巧。Raspberry Robin于2021年9月首次被发现,通过受感染的USB设备传播。
变量隐藏
一些变量不是以明文形式存储的,而是使用一个或多个算术指令隐藏起来的。这意味着如果 Roshtyak 没有主动使用变量,它将以混淆的形式保留该变量的值。每当Roshtyak需要使用该变量时,它必须在使用它之前先解开它的掩码。相反,在Roshtyak使用该变量后,它会将其转换回掩码形式。这种隐藏方法使调试期间跟踪变量的工作变得复杂,并使搜索内存中已知变量值变得更加困难。
循环变换
Roshtyak 在一些循环条件下很有创意。它没有像 for (int i = 0; i < 1690; i++) 那样编写循环,而是将循环转换为for (int32_t i = 0x06AB91EE;我! = 0 x70826068;i = i * -0x509FFFF + 0xEC891BB1)。虽然两个循环都将执行 1690 次,但第二个循环要难得多。乍一看,不清楚第二个循环执行了多少次迭代,甚至不知道它是否会终止。在第二种情况下,在调试期间跟踪循环迭代的次数也要困难得多。
包装
如上所述,Roshtyak 的核心隐藏在多层包装之后。虽然所有的层看起来都像是最初编译到PE文件中,但除了严格必要的数据(入口点、节、导入和重定位)之外的所有数据都被剥离了。此外,Roshtyak 支持两种自定义格式来存储剥离的 PE 文件信息,各层轮流使用对应的格式。此外,段自定义格式是加密的,有时使用基于各种反分析检查结果生成的密钥。
这使得将 Roshtyak 的层静态解压到一个独立的 PE 文件中变得很困难。首先,必须对自定义格式进行逆向工程,并弄清楚如何解密加密段。然后,必须重构 PE 标头、段、段标题和导入表(重定位表不需要重构,因为重定位可以被关闭)。虽然这一切都是完全可行的,并且可以使用像 LIEF 这样的库来简化,但这可能需要大量的时间。除此之外,这些层有时是相互依赖的,在内存中动态分析 Roshtyak 可能更容易。
其中一个自定义 PE 类文件格式的段标题:raw_size 对应于 SizeOfRawData,raw_size + virtual_padding_size 实际上是 VirtualSize。没有 VirtualAddress 或 PointerToRawData 等效项,因为这些段是按顺序加载的。
其他混淆技巧
除了上述技巧之外,Roshtyak 还使用其他混淆技巧,包括:
垃圾指令插入;
导入哈希;
频繁清除内存;
混合布尔算术混淆;
冗余线程;
重多态性;
核心功能
既然我们已经描述了 Roshtyak 如何保护自己,那么看看它的实际作用可能会很有趣。 Roshtyak 的 DLL 相对较大,超过 1 兆字节,但是一旦消除了所有的混淆,它的功能就非常简单。它的主要目的是下载更多的有效载荷来执行。此外,它还执行通常的恶意软件操作,即建立持久性、提升权限、横向移动和泄露有关受害者的信息。
持久性攻击
Roshtyak 首先在 %SystemRoot%\Temp 中生成一个随机文件名,并将其 DLL 映像移动到那里。生成的文件名由2到8个随机小写字符与从硬编码列表中选择的随机扩展名组成。用于生成此文件名的PRNG的卷序列号为C:\。我们分析的示例是硬编码的7个扩展名(.log、.tmp、.loc、.dmp、.out、.ttf 和 .etl)。我们观察到其他示例中使用了其他扩展,这表明这个列表是动态的。 Roshtyak 也很有可能会使用随机生成的扩展。一旦完全构建,到Roshtyak DLL的完整路径可能看起来如C:\Windows\Temp\wcdp.etl这样。
将 DLL 映像移动到新的文件系统路径后,Roshtyak 将其修改后的时间戳记到当前系统时间。然后它继续设置 RunOnce(Ex) 注册表项,以实际建立持久性。注册表项是使用前面描述的间接注册表写入技巧创建的。插入密钥的命令可能如下所示:
RUNDLL32.EXE SHELL32.DLL,ShellExec_RunDLL REGSVR32.EXE -U /s "C:\Windows\Temp\wcdp.etl."
这里有几点需要注意。首先,regsvr32 不关心它加载的 DLL 的扩展名,从而允许 Roshtyak 隐藏在 .log 等看似无害的扩展名下。其次,/s 参数将 regsvr32 置于静默模式。如果没有它,regsvr32将抱怨找不到名为DllUnregisterServer的导出。最后,请注意路径末尾的句号字符。该句号在路径规范化期间被释放,因此它实际上对命令没有影响。所以,我们不确定开发者的初衷是什么。它看起来像是被设计用来欺骗一些反恶意软件,使其无法将持久性条目与文件系统上的有效负载连接起来。
默认情况下,Roshtyak 使用 HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce 项进行持久化。但是,在某些情况下(例如,当它通过检查名为 avp.exe 的进程检测到 Kaspersky 正在运行时)将使用密钥 HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnceEx。 RunOnceEx 项能够加载 DLL,因此在使用该项时,Roshtyak 直接指定 shell32.dll,省略了 rundll32的使用。
Roshtyak 建立的 RunOnceEx 持久性条目
权限提升
Roshtyak 使用 UAC 绕过和常规 EoP 漏洞来尝试提升其权限,与许多其他恶意软件只是盲目地执行开发者可以找到的任何 UAC 绕过/利用的恶意软件不同,Roshtyak 努力确定权限提升方法是否有可能成功。由于不必要地使用了不兼容的绕过/漏洞,这可能是为了降低检测的机会。对于 UAC 绕过,这涉及检查 ConsentPromptBehaviorAdmin 和 ConsentPromptBehaviorUser 注册表项。对于 EoP 漏洞利用,这是关于检查 Windows 内部版本号和补丁级别。
除了检查 ConsentPromptBehavior(Admin|User) 项之外,Roshtyak 还执行其他健全性检查以确保它应该继续绕过 UAC。即,它使用 SID S-1-5-32-544 (DOMAIN_ALIAS_RID_ADMINS) 的 CheckTokenMembership 检查管理员权限。它还检查 KUSER_SHARED_DATA.SharedDataFlags 中 DbgElevationEnabled 标志的值。这是一个未记录的标志,在启用 UAC 时设置。最后,还有针对 BitDefender(由模块 atcuf32.dll 检测)、卡巴斯基(进程 avp.exe)和我们自己的 Avast/AVG(模块 aswhook.dll)的杀毒软件检查。如果检测到这些杀毒软件,Roshtyak 会避开选定的 UAC 绕过技巧,大概是那些可能导致被检测到。
至于实际的UAC旁路,主要有两种实现方法。第一个是 UACMe 中恰当命名的 ucmDccwCOM 方法的实现。有趣的是,当执行此方法时,Roshtyak 通过覆盖对应于主可执行模块的_LDR_MODULE 结构中的FullDllName 和BaseDllName 临时将其进程伪装成explorer.exe。此方法启动的有效负载是一个随机命名的 LNK 文件,使用 IShellLink COM 接口放入 %TEMP%。此 LNK 文件旨在通过 LOLBins(例如 advpack 或 register-cimprovider)重新启动 Roshtyak DLL。
第二种方法更像是一个 UAC 绕过框架而不是特定的绕过方法,因为多个 UAC 绕过方法遵循相同的简单模式:首先注册一些特定的 shell 打开命令,然后执行自动提升的 Windows 二进制文件(内部触发 shell 打开命令)。例如,可以通过向 HKCU\Software\Classes\ms-settings\shell\open\command 写入有效负载命令,然后从 %windir%\system32 执行 fodhelper.exe 来完成 UAC 绕过。基本上,同样的绕过可以通过用其他对替换ms-settings/fodhelper.exe来实现,例如mscfile/eventvwr.exe。Roshtyak使用以下6对来绕过UAC:
现在让我们看看 Roshtyak 用于提升权限的内核漏洞(CVE-2020-1054 和 CVE-2021-1732)。与 Roshtyak 中的常见情况一样,这些漏洞被加密存储,并且仅在需要时才解密。有趣的是,一旦解密,漏洞利用结果是具有完全有效标头的常规 PE 文件,与 Roshtyak 中的其他层不同,它们要么以 shellcode 形式存在,要么以自定义剥离的 PE 格式存储。此外,这些漏洞不像Roshtyak的其他漏洞那样容易混淆,所以它们的代码可以立即反编译,而且只使用了一些基本的字符串加密。我们不知道为什么攻击者让这些漏洞如此暴露,但这可能是由于位数的不同。虽然 Roshtyak 本身是 x86 代码(大段时间在 WoW64 下运行),但漏洞利用是 x64,考虑到它们利用 64 位代码中的漏洞,这是有道理的。可能 Roshtyak 的开发者使用的混淆工具是为 x86 设计的,不能移植到 x64。
Roshtyak利用CVE-2020-1054的代码片段,扫描IsMenu找到HMValidateHandle的偏移量
为了执行漏洞,Roshtyak 生成(AMD64 版本)winver.exe 并使用 KernelCallbackTable 注入方法获取漏洞代码以在其中运行。Roshtyak的这种注入方法的实现基本上与公共PoC相匹配,最大的区别是由于需要跨子系统注入而使用了略微不同的API函数(例如NtWow64QueryInformationProcess64而不是NtQueryInformationProcess或NtWow64ReadVirtualMemory64而不是ReadProcessMemory)。注入winver.exe的代码不是利用PE本身,而是稍微混淆的 shellcode,旨在将漏洞利用 PE 加载到内存中。
内核漏洞针对某些未打补丁的 Windows 版本。具体来说,CVE-2020-1054 仅用于版本号不高于 24552 的 Windows 7 系统。另一方面,CVE-2021-1732 的漏洞利用在 Windows 10 上运行,目标内部版本号范围为16353 到 19042。在利用CVE-2021-1732之前,Roshtyak还会扫描已安装的更新包,以查看是否安装了针对该漏洞的补丁。它通过枚举HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based services \Packages下面的注册表项,并检查KB4601319(或更高)的包是否存在。
横向运动
在横向移动方面,Roshtyak 只使用久经考验的 PsExec 工具。在执行 PsExec 之前,Roshtyak 通过检查与“众所周知的”WinAccountDomainAdminsSid 组匹配的 SID 来确保运行它是有意义的。如果未检测到域管理员权限,Roshtyak 将完全跳过其横向移动阶段。
Roshtyak 试图通过设置 Defender 排除项来绕过检测,因为 PsExec 通常被标记为黑客工具(有充分的理由)。它为 %TEMP% 设置一个路径排除(它将释放 PsExec 和其他用于横向移动的文件)。稍后,它会为执行 PsExec 的确切路径设置一个进程排除。
虽然我们希望PsExec被捆绑到Roshtyak中,但结果是Roshtyak从https://download.sysinternals[.]com/files/PSTools.zip按需下载PsExec。下载的zip归档文件被放入%TEMP%中,后缀名为.zip。然后使用Windows Shell COM接口(IShellDispatch)将PsExec从这个归档文件解压缩到%TEMP%中随机命名的.exe文件中。
PsExec 执行的有效负载是一个自解压包,由名为 IExpress 的工具创建。这是一个古老的安装程序,它是 Windows 的一部分,这可能就是使用它的原因,因为 Roshtyak 可以依赖它已经在受害者设备上。安装程序生成由使用自解压指令 (SED) 语法的文本文件配置。
Roshtyak 的 IExpress 配置模板
Roshtyak 使用具有三个占位符(%1、%2 和 %3)的 SED 配置模板,它在运行时将其替换为实际值。如上所示,配置模板是混合大小写编写的,通常在 Raspberry Robin 中经常使用。准备好SED配置后,它就会被写入 %TEMP% 中随机命名的 .txt 文件。然后,调用 iexpress 以使用 C:\Windows\iexpress.exe /n /q
生成有效负载后,Roshtyak就开始实际运行PsExec。 Roshtyak 可以通过两种方式执行 PsExec。第一个使用命令
分析受害者
USB 蠕虫往往有自己的活动。由于它们的蠕虫行为通常是完全自动化的,因此最初部署蠕虫的攻击者不一定完全控制它的传播位置。这就是为什么攻击者将蠕虫信标返回到他们的 C&C 服务器很重要的原因。有了信标机制,攻击者就可以获知他们控制的所有机器的信息,并可以利用这些信息对蠕虫进行管理。
发出的信标邮件通常包含有关受感染计算机的一些信息。这有助于有经济动机的攻击者决定如何利用攻击获利。Roshtyak 也不例外,它收集了有关每个受感染受害者的大量信息。 Roshtyak 将所有收集到的信息连接成一个大字符串,使用分号作为分隔符。这个大字符串然后被转移到Roshtyak的C&C服务器上。下面按顺序列出了过滤出来的信息。
外部 IP 地址(在 Tor 连接检查期间获得);
一个硬编码到 Roshtyak 代码中的字符串,例如AFF123(我们无法确定这背后的含义,但它看起来像一个附属 ID);
DLL 的 PE 标头的 16 位哈希(一些字段清零)与其 TimeDateStamp 的低 16 位异或。 TimeDateStamp 似乎是经过特殊设计的,因此异或会产生一个已知值。这可以作为篡改检查或水印的功能;
系统驱动器上 System Volume Information 文件夹的创建时间戳;
系统驱动器的卷序列号;
处理器计数 (GetActiveProcessorCount);
IsWow64Process (_PROCESS_EXTENDED_BASIC_INFORMATION.Flags & 2);
Windows 版本 (KUSER_SHARED_DATA.Nt(Major|Minor)Version);
Windows 产品类型 (KUSER_SHARED_DATA.NtProductType);
Windows 构建号 (PEB.OSBuildNumber);
本地管理权限(ZwQueryInformationToken(TokenGroups)/CheckTokenMembership,检查 DOMAIN_ALIAS_RID_ADMINS);
域管理权限(检查 WinAccountDomainAdminsSid/WinAccountDomainUsersSid);
系统时间 (KUSER_SHARED_DATA.SystemTime);
时区 (KUSER_SHARED_DATA.TimeZoneBias);
系统区域设置 (NtQueryDefaultLocale(0));
用户区域设置 (NtQueryDefaultLocale(1));
环境变量(username, computername, userdomain, userdnsdomain和logonserver);
Java 版本 (GetFileVersionInfo("javaw.exe") -> VerQueryValue);
处理器信息(获取处理器品牌字符串的 cpuid);
主可执行模块的映像路径 (NtQueryVirtualMemory(MemorySectionName));
主物理驱动器的产品 ID 和序列号 (DeviceIoControl(IOCTL_STORAGE_QUERY_PROPERTY, StorageDeviceProperty));
默认网关的 MAC 地址(GetBestRoute -> GetIpNetTable);
所有网络适配器的 MAC 地址 (GetAdaptersInfo);
安装的防病毒软件(root\securitycenter2 -> SELECT * FROM AntiVirusProduct);
显示设备信息(DeviceId、DeviceString、dmPelsWidth、dmPelsHeight、dmDisplayFrequency)(EnumDisplayDevices -> EnumDisplaySettings);
活动进程 (NtQuerySystemInformation(SystemProcessInformation));
以 base64 编码的屏幕截图(gdi32 方法);
信标
收集过程完成后,Roshtyak将受害者的资料发送到C&C服务器。配置文件通过 Tor 网络发送,使用 Roshtyak 注入新生成的进程的自定义通信模块。 C&C 服务器处理泄露的配置文件,并可能使用 shellcode 有效负载进行响应,以供核心模块执行。
现在让我们仔细看看这整个过程。值得一提的是,在生成任何恶意流量之前,Roshtyak 首先会执行 Tor 连接检查。这是通过以随机顺序联系 28 个合法且知名的 .onion 地址并检查其中至少一个是否响应来完成的。如果他们都没有回应,Roshtyak甚至不会尝试联系C&C,因为它很有可能无法与C&C取得联系。
至于实际的 C&C 通信,Roshtyak 包含 35 个硬编码的 V2 洋葱地址(例如 ip2djbz3xidmkmkw:53148,请参阅我们的 IoC 存储库以获取完整列表)。就像在连接检查期间一样,Roshtyak 以随机顺序遍历它们并尝试联系它们中的每一个,直到其中一个做出响应。请注意,虽然 V2 洋葱地址已被正式弃用,取而代之的是 V3 地址,并且 Tor 浏览器在其最新版本中不再支持它们,但对于Roshtyak的邪恶目的而言,它们的功能似乎仍然足够。
Roshtyak 的硬编码 C&C 地址
受害者配置文件以URL路径发送,附加在V2洋葱地址和/字符之后。由于原始概要文件可能包含禁止在url中使用的字符,因此概要文件被封装在自定义结构中,并使用Base64进行编码。自定义结构的第一个0x10字节作为加密密钥,其余的结构将被加密。自定义结构还包含受害者概要文件的64位哈希,它可能用作完整性检查。有趣的是,自定义结构的尾部可能填充了随机字节。注意,完整的路径可能非常大,因为它包含一个双base64编码的截图。Roshtyak的开发者可能意识到URL路径不适合发送大量数据,并决定将受害者配置文件的长度限制在0x20000字节。如果屏幕截图使泄露的配置文件大于此限制,则不包括在内。
构建完整的洋葱 URL 后,Roshtyak 继续启动其 Tor 通信模块。它首先生成一个虚拟进程来托管 comms 模块。这个虚拟进程是随机选择的,可以是 dllhost.exe、regsvr32.exe 或 rundll32.exe 之一。 comms 模块使用共享段注入到新生成的进程中,并通过前面描述的 shellcode 隐藏技巧进行了混淆。然后通过 NtQueueApcThreadEx 执行 comms 模块,使用已经讨论过的 ntdll gadget技巧。注入的 comms 模块是一个开源 Tor 库的自定义构建,包含在三个额外的保护性 shellcode 层中。
核心模块使用共享段作为 IPC 机制与 comms 模块进行通信。两个模块同步使用具有相同种子 (KUSER_SHARED_DATA.Cookie) 的相同 PRNG 来生成相同的段名称。然后,两者都将此命名段映射到各自的地址空间,并通过读取/写入来相互通信。读取/写入该段的数据使用 RC4 加密(密钥也使用同步的 PRNG 生成)。
核心模块和通信模块之间的通信遵循简单的请求/响应模式。核心模块将加密的洋葱 URL(包括要泄露的 URL 路径)写入共享段。 comms 模块然后解密 URL 并通过 Tor 向它发出 HTTP 请求。核心模块等待 comms 模块将加密的 HTTP 响应写回共享段。一旦它在那里,核心模块将其解密并从自定义格式解包,包括再次解密并计算哈希以检查有效负载的完整性。解密后的有效载荷可能包含一个供核心模块执行的 shellcode。如果 shellcode 存在,核心模块分配一大块内存,使用 shellcode 隐藏技巧将 shellcode 隐藏在那里,并在新线程中执行它。这个新线程是使用NtSetInformationThread -> ThreadHideFromDebugger技术隐藏的,包括使用NtGetInformationThread的后续反挂钩检查,以确认NtSetInformationThread调用确实成功。
总结
在这篇文章中,我们对与 Raspberry Robin 相关的后门有效载荷 Roshtyak 进行了深入研究。主要重点是描述如何处理 Roshtyak 的保护机制。我们展示了一些前所未见的反调试器/反沙盒/反虚拟机技巧,并讨论了 Roshtyak 的高度混淆。我们还描述了 Roshtyak 的核心功能。具体来说,我们详细介绍了它如何建立持久性、提升权限、横向移动以及使用 Tor 下载更多有效负载。
我们必须承认,对Roshtyak进行逆向工程绝非易事。严重的混淆和大量先进的反分析技巧的结合使它成为一个相当大的挑战。
本文翻译自:https://decoded.avast.io/janvojtesek/raspberry-robins-roshtyak-a-little-lesson-in-trickery/如若转载,请注明原文地址