[0 DAY IN {REA_TEAM}] 快速分析 Cobalt Strike 加载器和 ShellCode
本文来自:https://kienmanowar.wordpress.com/2021/09/06/quick-analysis-cobaltstrike-loader-and-shellcode/我在 malwareresearchgroup.slack.com 上发现一个样本,为 CS 加载器,样本哈希值为 2569cc660d2ae0102aa74c98d78bb9409ded24101a0eeec15af29d59917265f3,2021-09-01 19:47:50 被人上传到 VT 上,其中有 37 家检测引擎把它标记为恶意,如下所示:
一、分析加载器
这个加载器是 64 位的 Dll 文件,MinGW 编译,有一个导出函数:
在 IDA 下,ServiceMain 函数将生成一个新线程 (我将其重命名为 f_spawn_shellcode_thread),如下所示:
f_spawn_shellcode_thread 函数干以下几件事:
[*] 初始化 xor_key 的值为 jKfXmEkWYshKkZdPhJYS;
[*] 分配用于存储加密 ShellCode 的堆缓冲区,值为最开始声明的的全局字节数组;
[*] 进入解密 ShellCode 循环;
[*] 在新线程中解密 ShellCode;
我编写了一简短脚本来提取 ShellCode,以供后面分析:
import sys
import pefile
xor_key = "jKfXmEkWYshKkZdPhJYS"
def decode_sc(data, key):
key_len = len(key)
data_len = len(data)
decrypted = bytearray(data_len)
for i in range(0, data_len):
decrypted = data ^ key
print("Decode Done!")
return decrypted
def extract_sc(input_file):
encrypted_sc = []
try:
print("\r\nFile: " + input_file)
pe = pefile.PE(input_file)
for section in pe.sections:
if b'.rdata\x00\x00' in section.Name:
rdata_section = bytearray(section.get_data())
size = 0
for i in rdata_section:
if rdata_section == 0x00 and rdata_section == 0x00:
break
else:
size += 1
print("Encrypted bytes size: " + str(size - 24) + " bytes")
encrypted_bytes = rdata_section
for i in range(len(encrypted_bytes)):
if ((i & 1) == 0):
encrypted_sc.append(encrypted_bytes)
key = xor_key.encode('ascii')
decrypted_sc = decode_sc(encrypted_sc, key)
with open(sys.argv+"-decrypted", "wb") as out_file:
out_file.write(decrypted_sc)
print("Shellcode extracted at " + sys.argv+"-decrypted!\r\n")
print("Extract Shellcode Done!")
except Exception as e:
print("Error: " + str(e))
if __name__ == '__main__':
if len(sys.argv) == 2:
extract_sc(sys.argv)
else:
print("Usage: cobalt_extract_sc.py <cobalt_loader_dll>")
跑完脚本后,得到的 ShellCode 如下所示:
二、分析 ShellCode
如果我们将原始 ShellCode 加载到 IDA 中并转换为 asm 代码,它将如下图所示。在这段代码的第一个开头,我们可以看到定位 PEB 结构的代码。这让我想到它会使用 PEB 最终来查找 API 的地址。
进入 sub_D2,第一条语句将返回地址分配给 rbp 寄存器。我们知道这个地址是 0xA (push r9),然后我们看到字符串值 wininet 被加载到 0xD5 处的 r14 寄存器。我们看到一个值被分配给 r10 (726774Ch; 726774Ch) 寄存器,接下来是对 rbp 寄存器指向的地址的调用。我认为这些哈希值是与 api 函数相关,ShellCode 会进行计算并与这些值进行比较,从中获取相关的 API 地址。
为了便于分析和调试,我把 ShellCode 转成 exe,最后得到以下与通过 jmp rax 命令查找 API 函数地址和调用 API 相关的伪代码:
根据上面的伪代码,我们可以看到 ShellCode 会计算两个哈希值,第一个值基于 Dll 的名称,第二个值基于该 Dll 的 API 函数的名称,将这两个值加在一起并与预先计算的哈希值进行比较。
你可以编写脚本来恢复 API 函数,我总是使用 FLARE Team 的 shellcode_hashes_search_plugin.py。 详细信息可以在 这篇文章 中找到。 使用插件后的最终结果:
shellcode_hash: Starting up
Starting up(shellcode_hash_search:run)
shellcode_hash: Processing current segment only: 0x140001000 - 0x140003000
Processing current segment only: 0x140001000 - 0x140003000 (shellcode_hash_search:processCode)
shellcode_hash: 0x1400020e7: ror13AddHash32AddDll:0x0726774c kernel32.dll!LoadLibraryA
0x1400020e7: ror13AddHash32AddDll:0x0726774c kernel32.dll!LoadLibraryA (shellcode_hash_search:lookForOpArgs)
shellcode_hash: 0x1400020ff: ror13AddHash32AddDll:0xa779563a wininet.dll!InternetOpenA
0x1400020ff: ror13AddHash32AddDll:0xa779563a wininet.dll!InternetOpenA (shellcode_hash_search:lookForOpArgs)
shellcode_hash: 0x140002121: ror13AddHash32AddDll:0xc69f8957 wininet.dll!InternetConnectA
0x140002121: ror13AddHash32AddDll:0xc69f8957 wininet.dll!InternetConnectA (shellcode_hash_search:lookForOpArgs)
shellcode_hash: 0x140002140: ror13AddHash32AddDll:0x3b2e55eb wininet.dll!HttpOpenRequestA
0x140002140: ror13AddHash32AddDll:0x3b2e55eb wininet.dll!HttpOpenRequestA (shellcode_hash_search:lookForOpArgs)
shellcode_hash: 0x14000216a: ror13AddHash32AddDll:0x869e4675 wininet.dll!InternetSetOptionA
0x14000216a: ror13AddHash32AddDll:0x869e4675 wininet.dll!InternetSetOptionA(shellcode_hash_search:lookForOpArgs)
shellcode_hash: 0x140002184: ror13AddHash32AddDll:0x7b18062d wininet.dll!HttpSendRequestA
0x140002184: ror13AddHash32AddDll:0x7b18062d wininet.dll!HttpSendRequestA (shellcode_hash_search:lookForOpArgs)
shellcode_hash: 0x140002329: ror13AddHash32AddDll:0x56a2b5f0 kernel32.dll!ExitProcess
0x140002329: ror13AddHash32AddDll:0x56a2b5f0 kernel32.dll!ExitProcess (shellcode_hash_search:lookForOpArgs)
shellcode_hash: 0x140002345: ror13AddHash32AddDll:0xe553a458 kernel32.dll!VirtualAlloc
0x140002345: ror13AddHash32AddDll:0xe553a458 kernel32.dll!VirtualAlloc (shellcode_hash_search:lookForOpArgs)
shellcode_hash: 0x140002363: ror13AddHash32AddDll:0xe2899612 wininet.dll!InternetReadFile
0x140002363: ror13AddHash32AddDll:0xe2899612 wininet.dll!InternetReadFile (shellcode_hash_search:lookForOpArgs)
shellcode_hash: Done
Done (shellcode_hash_search:run)
此时可以进行调试以进行进一步的分析,但是,我很快使用 hasherezade 的 tiny_tracer 工具来跟踪 ShellCode:
样本解压密码:
**** Hidden Message *****
解压密码? 解压密码?
页:
[1]