感谢<<安全的矛与盾>>星球大佬让我白嫖了许多东西,知识、思路等等。没有这些白嫖,不可能完成快乐星球的构建。本人是一个脚本小子,大佬们轻喷。
CS <= 4.3
漏洞存在在beacon.BeaconC2.process_beacon_callback_decrypted中对beacon端发送过来的任务处理结果的长度进行判断,直接按照beacon端的结果进行分配内存,导致teamserver端崩溃。
该函数为common.DataParser.readCountedBytes
可以看到,readCountedBytes函数首先读取一个4字节的数据并转换为int类型,然后根据这个int类型的变量申请内存buffer用来读取接下来的数据,这里就存在一个问题,如果攻击者可以控制这个4字节的数据,就可以控制接下来申请的buffer的长度,从而导致teamserver端申请过大内存导致陷入僵死。
之所以叫做缓解方案,是因为并没有真正的修复,而是对beacon行为进行了判断,限制如果是新session,拒绝其直接发送截屏和键盘记录的结果。之所以只对这俩分支进行判断,是因为只有这俩分支调用了readCountedBytes这个函数。判断的关键代码为denyFirstAttack。
private byte[] denyFirstAttack(String var1, DataInputStream var4, int var16) {
byte[] var17;
if (this.data.isNewSession(var1)) {
this.getCheckinListener().output(BeaconOutput.Error(var1, "Dropped responses from session. Didn't expect " + var16 + " prior to first task."));
CommonUtils.print_error("Dropped responses from session " + var1 + " [type: " + var16 + "] (no interaction with this session yet)");
return null;
}
var17 = CommonUtils.readAll(var4);
return var17;
}
data.isNewSession判断当前任务队列里,是否包含该session,如果没有,就直接发任务处理数据,那这里就存在问题。
然后就是把这段判断放到截屏和键盘记录处理分支里面。
这里贴下4.3版本的验证效果。未修复前使用poc测试https://github.com/M-Kings/CVE-2021-36798
可以看到直接把teamserver打宕机了。修改完后再测试,防护生效,teamserver没有崩溃。
CS <= 4.5
beacon.http-get
beacon.http-post
stager
stager64
对请求uri进行判断,不是/开头都直接返回400 Bad Request。具体修复位置在cloudstrike.WebServer._serce
if (!(uri.startsWith("/"))) {
return this.processResponse(uri, method, header, param, false, null,
new Response("400 Bad Request", "text/plain", ""));
}
beacon.http-get
beacon.http-post
stager
stager64
绕过原理这里简单记录下:cs在填充profile数据时,数据格式:x64为8字节+8字节,x86为4字节+4字节,前面的字节是数据长度类型,后面的字节是数据,由于数据长度类型这里只使用了一个字节,剩下7个或3个字节都为0。这个就是beaconEye的yara规则,据此绕过只需要把前面没用的字节设置为非0即可。
IDA中打开beaconx64.dll,来到DLLMain,找到profile解析的函数,函数位置为sub_180018694。
跟进该函数,首先申请profile数据所在堆内存块,然后赋值为0,这里可以对这个0进行修改,让他不为0,即可绕过beaconEye的yara规则。
这里测试用mov edx, eax,其机器指令为89 C2,正好为2字节,经测试,使用mov edx, ebx patch,仍然会被检测到。
patch之后,再看下反编译效果。
没什么问题。x86的dll修改,可以改成push eax,1字节指令,原push 0是2字节,这样不会影响原指令长度。使用其他寄存器可能还会被检测到,这里测试eax的值不会被检测到。
需要修改的DLL如下,修改位置和原理是类似的,不再赘述。
beacon.dll、beacon.x64.dll -- http listener的beacon
dnsb.dll、dnsb.x64.dll -- dns listener的beacon
extc2.dll、extc2.x64.dll -- external listener的beacon
pivot.dll、pivot.x64.dll -- bind tcp、smb listener的beacon
绕过前使用beaconeye扫描进程内存,成功发现beacon所在进程。
在patch过beacon之后,再次进行测试,发现已无法找到beacon进程,成功绕过。
这个比较简单,就不多写了,记录下修改位置在beacon/BeaconPayload的beacon_obfuscate方法。
这个比较简单,就不多写了,记录下修改位置在ssl/SecureServerSocket的authenticate方法和ssl/SecureSocket的authenticate方法。
这个比较简单,就不多写了,记录下修改位置在aggressor.Aggressor的A方法。
bypass 360核晶的思路借鉴星球大佬分享的一篇文章的思路,就是将DLL注入beacon所在进程执行。在CS 4.4版本需要对DLL导入表进行Patch,但在CS 4.5版本不需要,具体原因没有分析,原因是太菜了。。。
这里需要对Java端进行修改,主要修改的地方是beacon/TaskBeacon.java,界面功能实现原理与下个小节的setchar类似。
Desktop command
logonpasswords command
hashdump command
printscreen command
screenshot command
思路来源于先知上深蓝实验室一篇文章,不得不说先知这个社区还是不错的。https://xz.aliyun.com/t/11055
首先按照原文给的思路,在增加了修改按钮和功能后确实可以修改BeaconEntry对象的chst属性数据,但是使用扫描工具扫描的输出结果还是乱码的。暂时陷入困局,这时候去看了下cs的注册编码的过程,发现了问题。
调试teamserver端,在上图当中注册beacon对象编码信息处下断点,发现每次beacon callback回来都会经过process_beacon_metadata这个函数,也就是说每次都要重新生成BeaconEntry对象,这里生成的BeaconEntry对象会保存在teamserver端,与client端的BeaconEntry对象是不同的。由于每次都要从beacon的metadata里解析编码信息,就会导致每一次callback回来都是目标环境的编码,这就是只修改client chst属性的数据无法完成编码切换的原因。
只需要在每次注册编码信息前,判断当前BeaconID的编码有没有被修改就行,没有从全局维护的customCharsets中找到或者为空字符串,那就按照目标环境的编码进行注册,否则注册client自定义的编码数据。
console设置命令: setchar [charset]
界面的下拉框选择
扫描输出UTF-8数据,显示正常
此处省略1w字。
beacon的右键菜单中选择Soldier,Setchar可以设置返回数据的编码,EnableBypass360开启绕过核晶模式,DisableBypass360切换回一般模式。
Last Soldier<Memory Evasion>
•https://www.sentinelone.com/labs/hotcobalt-new-cobalt-strike-dos-vulnerability-that-lets-you-halt-operations/•https://github.com/Sentinel-One/CobaltStrikeParser•https://hosch3n.github.io/2021/08/06/%E5%85%B3%E4%BA%8E%E4%BF%AE%E5%A4%8DHotcobalt%E7%9A%84%E4%B8%80%E4%BA%9B%E5%B0%8F%E6%83%B3%E6%B3%95/•https://github.com/M-Kings/CVE-2021-36798•https://xz.aliyun.com/t/10832•https://github.com/CCob/BeaconEye•https://donghuangt1.com/writings/Stager/