0x00概述
202108,网上曝出cobaltstrike的DOS漏洞CVE-2021-36798,又名hotcobalt。
https://blog.cobaltstrike.com/2021/08/04/cobalt-strike-dos-vulnerability-cve-2021-36798/
原因是对截屏(或keylogger)功能的返回数据解析处理不当,可被攻击者控制截屏大小,使teamserver不断申请内存以致outofmemory,从而被DOS。
0x01 影响范围
cobaltstrike4.2/4.3
0x02 前置知识
先安装一些要用的东西
https://files.pythonhosted.org/packages/2c/52/c35ec79dd97a8ecf6b2bbd651df528abb47705def774a4a15b99977274e8/M2Crypto-0.38.0.tar.gz
sudo
cd M2Crypto-0.38.0
python setup.py install
pip install pycryptodome
pip3 install hexdump
pip3 install pycryptodome
//pip install M2Crypto
pip install typing
pip install --upgrade setuptools
pip install hexdump
sudo apt-get install jq
sudo apt-get install python-dev
//710 sudo apt-get install python-m2crypto
sudo apt-get install libssl-dev swig
sudo apt-get install ghex
stage和stageless/unstage/full staged
Beacon是Cobalt Strike运行在目标主机上的payload,Beacon在隐蔽信道上我们提供服务,用于长期控制受感染主机。它的工作方式与Metasploit Framework Payload类似。在实际渗透过程中,我们可以将其嵌入到可执行文件、添加到Word文档或者通过利用主机漏洞来传递Beacon
很多攻击框架都是使用分段的shellcode,以防止shellcode过长,覆盖到了上一函数栈帧的数据,导致引发异常。要说分段shellcode就不得不提stager,stager是一段很精短的代码,它可以连接下载真正的payload并将其注入内存。我们使用stager就可以解决shellcode过长的问题。
The payload stagers in Cobalt Strike do not authenticate the controller or verify the payload they download
Cobalt Strike 3.5.1后的版本可以通过在Malleable C2中添加host_stage选项,以限制分段payload
在Cobalt Strike 4中应该尽可能多的使用unstage
一方面以保证安全性(因为你无法确保stager下载的stage是否受到中间人攻击,除非像MSF一样使用SSL保证安全性)。另一方面如果我们通过层层的代理,在内网进行漫游,这个时候使用分段的payload如果网络传输出现问题,stage没有加载过去,可能就会错失一个Beacon,unstage的payload会让人放心不少Stageless Beacon artifacts include: an executable, a service executable, DLLs, PowerShell, and a blob of shellcode that initializes and runs the Beacon payload.
payload staging : The first stage is called a stager. The stager is a very tiny program, often written in hand-optimized assembly, that: connects to Cobalt Strike, downloads the Beacon payload (also called the stage), and executes it.
//上述内容引用自:
https://cloud.tencent.com/developer/article/1595548
https://blog.cobaltstrike.com/2016/06/15/what-is-a-stageless-payload-artifact/
https://blog.cobaltstrike.com/2016/06/22/talk-to-your-children-about-payload-staging/
简单说:
stage就是分段下载payload,类似先小马(stager)后大马(stage/beacon-payload)的操作。
stageless就是包含了所有的payload,类似直接传大马。
beacon交互
.cobaltstrike.beacon_keys这个文件里有teamserver生成的公私钥,每一个beacon都内嵌了公钥。
beacon解析
python3 parse_beacon_config.py http://192.168.57.88/ --json --version 4 | zsh -c jq *
通过这个listener/host_stage就可以获取到beacon的设置信息,就可以伪造beacon/session上线。
在目标受害机器运行cs生成的后门时,会向c2发出一个get的checksum8格式的请求下载剩余的payload(shellcode分段,另一种是stageless)
beacon在目标受害机器运行时会通过http get向cs的c2传回(元数据metadata)目标机器的一些信息如cpu,ip,AES密钥等(用该rsa公钥加密),姑且称为beacon注册。
之后攻击者就可以和beacon交互了,通常是用http get接收指令,用http post返回信息。这些任务用了之前beacon注册请求发送的AES key加密。
先获取公私钥:
https://gist.github.com/olliencc/af056560e943bafa145120103a0947a3#file-dump-java
javac -cp "cobaltstrike.jar" DumpKeys.java
java -cp ".:./cobaltstrike.jar" DumpKeys
抓包:
用rsa私钥解密的数据:
可以看到部分信息,更具体的解析要逆出cs的通信格式。
//beacon会不停发这个get请求获取teamserver的任务信息
解密beacon的metadata:
https://github.com/WBGlIl/CS_Decrypt/blob/main/Beacon_metadata_RSA_Decrypt.py
AES key:1f6a1085fc9544467b78546215e97282
HMAC key:6b7712a4ab24b25e9347ab82fc073438
解密teamserver->beacon的任务:
通过wireshark抓包保存数据包为bin文件,这是个文件浏览的任务
再利用ghex提取body数据,这是一个下载phpinfo.php文件的任务。
解密之:
https://github.com/WBGlIl/CS_Decrypt/blob/main/CS_Task_AES_Decrypt.py
该请求对应的beacon响应解密(beacon->teamserver):
https://github.com/WBGlIl/CS_Decrypt/blob/main/Beacon_Task_return_AES_Decrypt.py
同理解密一个文件浏览请求的beacon响应:
0x03 漏洞重现
https://github.com/Sentinel-One/CobaltStrikeParser/blob/master/extra/communication_poc.py
用这个poc可以注册一个假beacon
exp:
https://github.com/JamVayne/CobaltStrikeDos
python3 CobaltStrikeDos.py http://192.168.57.88/
成功DOS!
0x04 EXP流量分析
先请求checksum8 url
接着发出大量beacon注册请求
再发出大量beacon响应的截屏任务
尝试解密一个metadata
Rhm3p3/UZFiJbU0fOjQKPHcD3AoYy7OyB8p+3Py7l6WDazCa/fl/V4gCsdIhKYAT4XN60kNzUndaDbCflqqmsSjJts0rK70SjRGRdfTkBhNOASLVR34/+Cy3SuiO0CPL30yhHBDBAKRNZVo+inA3Qjvtyvu9emD9hVWwy7gkwlU=
用这个exp要注释掉process变量。
找到有96m截屏的一个流量:
再通过beaconid找到对应的submit.php
0x05 漏洞分析
decompiled-src/beacon/BeaconC2.java
public void process_beacon_callback_decrypted(final String s, final byte[] array) {
int int1 = -1;
if (array.length == 0) {
return;
}
if (!AssertUtils.TestIsNumber(s)) {
return;
}
if (!AssertUtils.TestNotNull(this.getCheckinListener().resolve(s + ""), "process output for beacon session")) {
return;
}
try {
final DataInputStream dataInputStream = new DataInputStream(new ByteArrayInputStream(array));
int1 = dataInputStream.readInt();
if (int1 == 0) {
final String process = this.getCharsets().process(s, CommonUtils.readAll(dataInputStream));
this.getCheckinListener().output(BeaconOutput.Output(s, "received output:\n" + process));
this.runParsers(process, s, int1);
}
......
else if (int1 == 3) {
final DataParser dataParser2 = new DataParser(CommonUtils.readAll(dataInputStream));
dataParser2.little();
final byte[] countedBytes = dataParser2.readCountedBytes(); //取头4个字节整数作为截图大小
final int int3 = dataParser2.readInt();
final String process5 = this.getCharsets().process(s, dataParser2.readCountedBytes());
final String process6 = this.getCharsets().process(s, dataParser2.readCountedBytes());
if (countedBytes.length == 0) {
this.getCheckinListener().output(BeaconOutput.Error(s, "screenshot from desktop " + int3 + " is empty"));
return;
}
final BeaconEntry resolve2 = this.getCheckinListener().resolve(s + "");
if (resolve2 == null) {
return;
}
final Screenshot screenshot = new Screenshot(s, countedBytes, process6, resolve2.getComputer(), int3, process5);
this.getCheckinListener().screenshot(screenshot);
if (process5.length() > 0) {
this.getCheckinListener().output(BeaconOutput.OutputB(s, "received screenshot of " + process5 + " from " + process6 + " (" + CommonUtils.formatSize(countedBytes.length) + ")"));
this.getResources().archive(BeaconOutput.Activity(s, "screenshot of " + process5 + " from " + process6));
}
else {
this.getCheckinListener().output(BeaconOutput.OutputB(s, "received screenshot from " + process6 + " (" + CommonUtils.formatSize(countedBytes.length) + ")"));
this.getResources().archive(BeaconOutput.Activity(s, "screenshot from " + process6));
}
this.getResources().process(new ScreenshotEvent(screenshot));
}
decompiled-src/common/DataParser.java
public byte[] readCountedBytes() throws IOException {
final int int1 = this.readInt(); //取4个字节整数
if (int1 > 0) {
return this.readBytes(int1); //返回这4个字节整数的大小
}
return new byte[0];
}
接着会分配一个足够大的缓冲区来读取截屏数据。
0x06 修复方案
1.更新至4.4版本。
/
2.host_stage=false
防止beacon设置信息被获取从而防御被dos。
/
3.只允许可信的源访问teamserver。
/
4.添加防御代码:(未测试是否可行)
在用
https://github.com/Sentinel-One/CobaltStrikeParser/blob/master/extra/communication_poc.py
和
https://github.com/M-Kings/CVE-2021-36798/blob/main/CVE-2021-36798.py
这两个poc测试时候dos不成功。
发现teamserver会出现
Dropped responses from session 111 [type: 222] (no interaction with this session yet)
搜索源代码:
decompiled-src/beacon/BeaconC2.java
else if (int1 == 29) {
this.parts.put(s, CommonUtils.readAll(dataInputStream));
if (this.parts.isReady(s)) {
this.process_beacon_callback_decrypted(s, this.parts.data(s));
}
}
else {
if (this.data.isNewSession(s)) {
this.getCheckinListener().output(BeaconOutput.Error(s, "Dropped responses from session. Didn't expect " + int1 + " prior to first task."));
CommonUtils.print_error("Dropped responses from session " + s + " [type: " + int1 + "] (no interaction with this session yet)");
return;
}
这个好像是对cobaltstrike3.5的rce的修复方案之一,判断beacon和c2要有至少一次交互,而cobaltstrikeparser中parse_beacon_config这个库的poc是没有交互直接发payload的。
//from parse_beacon_config import cobaltstrikeConfig
所以这两个poc不成功应该就是利用了parse_beacon_config库从而被这段代码防住了。
所以或许可以用这个代码来防御利用了parse_beacon_config的poc,复制代码到截屏和keylogger的if分支即可
else if (int1 == 3) //截图功能
else if (int1 == 1) { //keylogger
0x07 参考资料
https://www.sentinelone.com/labs/hotcobalt-new-cobalt-strike-dos-vulnerability-that-lets-you-halt-operations/
https://f5.pm/go-81984.html
https://hub.fastgit.org/Sentinel-One/CobaltStrikeParser
https://hub.fastgit.org/JamVayne/CobaltStrikeDos
https://www.cobaltstrike.com/help-malleable-c2
https://blog.cobaltstrike.com/2016/06/15/what-is-a-stageless-payload-artifact/
https://blog.cobaltstrike.com/2013/06/28/staged-payloads-what-pen-testers-should-know/
https://blog.cobaltstrike.com/2016/06/22/talk-to-your-children-about-payload-staging/
https://wbglil.gitbook.io/cobalt-strike/cobalt-strike-yuan-li-jie-shao/cs-mu-biao-shang-xian-guo-cheng
https://github.com/WBGlIl/CS_Decrypt