吉沃运营专员 发表于 2021-9-8 15:56:50

[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 *****

niklaus 发表于 2021-9-23 22:51:00

解压密码?

DJ5FmB5YnWR8 发表于 2021-9-29 11:17:35

解压密码?
页: [1]
查看完整版本: [0 DAY IN {REA_TEAM}] 快速分析 Cobalt Strike 加载器和 ShellCode