Cobaltstrike上线过程与蓝队反制

Cobaltstrike上线过程与蓝队反制

CS的流量通道有很多,如http、https、dns、TCP、SMB等,但我们这里主要研究beacon通过http通道的CS上线过程

所以我们创建监听器的时候payload选择Beacon HTTP

Cobaltstrike上线过程

这里用了别人的一张图,能很清晰的看清楚流量交互的大致流程

我们对其中的每一步来具体分析

  1. 通过各种方式将样本(分阶段的)或者恶意代码发送到受害端
    这个比较好理解,就是第一步将木马放到受害者主机上
  2. 运行样本或执行恶意代码
    这步也很好理解,受害者运行我们所生成的木马
  3. 请求特定算法获取到URI
    这里其实出现了第一个问题,什么是特定算法,这里就想到了很多安全公司,能用他们的引擎来查询到相关CS,MSF的特征码,特征流量相关信息,来进行拦截。那么这里的特定算法也是如此

    主要是这里的checksum8方法,其主要实现了转ascii对应十进制,然后求和256取余,最后余数和92,93来对比,92是x86,93是x64,而所谓的特征流量相关信息,也就是对应的uri:YPbR(这里对应的uri每次都不一样,但一般都是4个字符)
    image.png
  4. 校验URI,返回完整的stager beacon
    这里就对应第三步,受害者请求了YPbR的对应URI,然后cs向其发送完整的beacon
  5. 完整的stager beacon文件
    我们将其导出对象,HTTP
  6. 解密stage beacon文件获取到公钥以及相关server的信息

    将我们导出的对象YPbR,进行解密,这里有一个写好的脚本
    将其解密,可以得到如下结果

    在其中可以看到很多关键信息,也是很多安全大厂扫描器扫描之后,能得到的内容
  • 0x0001 payload type 记录了攻击载荷类型windows-beacon_http-reverse_http
  • 0x0002 port记录了端口80
  • 0x0003 sleeptime记录了心跳间隔60000
  • 0x0004 maxgetsize记录了最大数据长度1048579
  • 0x0005 jitter记录了帧的偏差0
  • 0x0007 publickey记录了公钥30819f300d06092a864886f70d010101050003818d0030818902818100a738cde75f1fbb1c18646c377e03016b162b12ba72bdf7dc36b4cd2e4e9bae12205a95c26170bf908105ad7fa4bbccfa798632261bed9870f975f20794e1fe499523d71f08a56cae0315bfde3d6c8a16386b03b7a6551aa1336d50325a3500db27d78ad8fd13b6a73b9fb7c3fb4d7a088e323f07618656ecd83595fa5f823613020301000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
  • 0x0008 server,get-uri记录了获取的uri192.168.152.129,/g.pixel
  • 0x0009 useragent记录了useragent'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Win64; x64; Trident/6.0; MATMJS)
  • 0x000a post-uri记录了执行命令的uri/submit.php
  • 0x000b Malleable_C2_Instructions记录了所执行的命令\x00\x00\x00\x04
  1. 使用公钥加密相关受害端的信息和自己伪随机生成的一个对称加密的密钥生成Cookies字段,通过HTTP请求放在心跳包里面传输

    可以看到,在心跳连接中,cookie承载的就是对应的加密内容,而这里用到的是非对称加密,而去获取对应的私钥,则需要去CSclient的源码里面找,其关键代码如下

    这样我们就可以到CSserver的服务器看一下,找到这个文件,并反序列化得到对应的公私钥

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    package ga0wei.text;  

    import sleep.runtime.Scalar;

    import javax.crypto.Cipher;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.ObjectInputStream;
    import java.security.KeyPair;
    import java.security.PrivateKey;
    import java.security.PublicKey;
    import java.util.Base64;

    public class Getkey {
    public static void main(String\[\] args) throws Exception{
    PrivateKey privateKey;
    Cipher cipher;
    //获取密钥对象
    ObjectInputStream var2 \= new ObjectInputStream(new FileInputStream("keys"));
    Scalar var3 \= (Scalar)var2.readObject();
    var2.close();
    KeyPair keyPair1 \= (KeyPair) var3.objectValue();

    //初始化cipher对象,准备解密
    privateKey \=keyPair1.getPrivate();
    cipher \=Cipher.getInstance("RSA/ECB/PKCS1Padding");
    cipher.init(2,privateKey);

    //元数据
    String ciphertext \= "WTbGz2y0K24UJovEX+proVDR+jInn7C/H8JwIa3+DCdm+qkSbquSRU2/n/ss8dMUHogaPFIn/N+xaAOW/gmfvu4HfVNF8Kk/XsRN35By03QWKIbhVbNGyZOBwCYGWs3f9XjUa8rqbiHbmRnRppbEpVv/+pvlVqYUh53bFQP9O7E=";
    byte\[\] cipherbyte \= Base64.getDecoder().decode(ciphertext);

    //解密
    byte\[\] text \= cipher.doFinal(cipherbyte);

    //输出文件 和控制台
    try(FileOutputStream fos \= new FileOutputStream(new File("Text"))) {
    System.out.println("解密成功");
    fos.write(text);
    System.out.println(new String(text));
    System.out.println("privatekey :"+new String(Base64.getEncoder().encode(keyPair1.getPrivate().getEncoded())));
    System.out.println("publickey : "+new String(Base64.getEncoder().encode(keyPair1.getPublic().getEncoded())));
    }
    }
    }

    而我们现在得到的公钥与我们之前解密beacon所获取的0x0007 publickey公钥相同
    将私钥编码,传入RSA私钥对,根据CS里面元数据的结构体,将解密后的内容进行整理
    解密之后的结果,就可以看到受害机器信息,主机名、用户名、样本名

  2. 使用私钥解密cookies字段的内容,获取到对称密钥和相关受害段信息并判断aggressor端是否有要执行的相关任务

  3. 有任务:在相应题里面发送使用对称密钥AES加密待执行命令的内容,没有任务:响应空

    可以看到在一个心跳包的来回中,响应流量会带有类似乱码的信息,而这其实是C2在发送任务给受害主机
    由于这两部分流量都是由对应的对称密钥加密得,所以我们用之前获取到的解密元数据中的rawkey,即可进行解密

    接着我们进行相应的解密,就可以得到其对应的直接通信的明文流量
    !(https://s2.loli.net/2022/11/28/TbL1qgaHumWd8F3.png)

  4. 使用生成的对称密钥,AES解密响应体,执行对应任务

  5. 通过Post请求里面的请求体来将回显请求体内容为使用对称密钥AES加密执行结果

Cobaltstrike蓝队反制

上面我们分析完了Cobaltstrike的上线过程,接下来就是蓝队如何利用CS这个上线的过程来进行反制,主要是以下四种方式

伪造流量批量上线(欺骗防御)

伪造流量批量上线这个手段是属于技战法里面的欺骗防御,通过伪造上线心跳流量,发送至攻击者的c2,使攻击者的c2同时上线的大量终端
通常有两种常见场景:
第一种是,发现攻击者对我们单位在进行精准钓鱼,那么我们可以通过这个欺骗防御,来混淆攻击者的视听,让攻击者的c2server上线大量机器,但是攻击者却执行不了任何命令
第二种是,发现我们内部已经存在被钓鱼上线的机器,那么此时我们通过这种欺骗防御就是来拖延攻击者,使攻击者难辨真假,从而争取一些排查处置的时间

而对于伪造上线流量,就是构造心跳流量,也就是伪造cookie字段,那我们就根据上面所抓的心跳包,构造相应的流量,而其构造结构主要是

标志头(4)+Size(4)+Rawkey(16)+字体(4)+beacon ID(4)+ 进程ID(4)+port(2)+内核(4)+09 +失陷IP + 09 + 主机名+ 09 + 用户名+09+进程名
CS的监听器判断是否是同一个心跳是通过beacon ID这个属性来判断的,只要这个属性不一样就会被识别成不同的上线流量,接下来,我们拿到公钥,对伪造的明文流量进行加密,就可以生成cookie字段了,这里作者也实现了批量上线的工具

可以看到,伪造的心跳流量已经批量上线了

通过漏洞反制

对于CS的CVE,有CVE-2021-36798、CVE-2022-23317等,但这里我们用到的是CVE-2022-39197
其主要是XSS
元数据格式:标志头(4)+Size(4)+Rawkey(16)+字体(4)+beacon ID(4)+ 进程ID(4)+port(2)+内核(4)+09 +失陷IP + 09 + 主机名+ 09 + 用户名+09+进程名
而XSS的注入点就在于这个用户名
在这里可以注入一些东西,但需要注意的是,我们需要将其他字段的长度缩短,因为最终被加密时,所对应的长度是有限制的,因为通过模n同余计算时,结果都是要受限制与n的长度
这里XSS倒是不难,但在漂亮鼠师傅的文章中,实现了从XSS到RCE
其过程主要是通过swing里面引用html渲染的时候,如果我们引用的相应标签的时候,会通过javax.swing.text.html.HTMLEditorKit类中create方法来创建对应的元素,当我们传入的标签是一个HTML.Tag.OBJECT类型的标签的时候会调用new ObjectView()来生成对应的元素,这里面解析object标签的时候会根据其Classid来解析,在这个过程中会通过Class.forname加载对应类然后通过newinstance获取classid传入类的实例,并且当该类继承了Component时,会调用setParameters方法,在这个方法里面一定情况下会反射调用对应类的对应参数的set方法(这里的条件是:该方法的传入参数只有一个且是String类型),并且该set方法传入的参数也是我们可控的,从而这里就出现了一个漏洞利用的可能

这种反制类似于内网中的蜜罐,让攻击者打进来,然后反向获取攻击者的一些信息或者权限来反制

爆破server口令

这种方式是当我们返现一个vpn运行了cs server的时候,我们通过口令字典对server端实现爆破,从而登录server,获取攻击者的相关信息
但这种方式会遇到一些问题

  1. 攻防中,不容易找到真实的c2,大多被隐藏,例如:域前置技术、云函数转发等
  2. 使用cs的红队,自身出现弱口令的概率并不高
  3. 攻防中,团队使用的cs,会出现各种改版过的登录协议,难以攻击
  4. cs自身做过相应的处理,对这种爆破做了一定的防御措施

旁路反制

这个就比较泛泛而谈了,好比渗透测试或者是rt打项目的时候,如果目标找不到利用点进去,就可以从旁站看看对吧,所以这种旁路反制亦是这样,我们发现一个c2上运行着cobaltstrike server了,然后上述的其他反制手段都行不通,这时我们就可以看看,这个c2上是不是还有其他的服务,我们对其端口进行扫描,获取相关信息,从其他服务的缺陷来实现反制,举个例子,很对rt或者攻击者在遇到weblogic、fastjson、log4j2等jndi漏洞的时候,要进行漏洞利用就得起rmi或者ldap,server,自己手动起是很麻烦的,所以网上会有很多的自动化工具,这对于攻击者来说是一个不错的选择。那么如果我们发现网上这类工具的一些rce了,就可以通过这个来反制。

前段时间参加某次演习活动的时候,通过一些手段拿到了一个c2,对c2进行扫描后发现,其相关端口搭建的服务是nps的web控制端服务,所以后续就可以通过爆破该服务来实现反制,虽然后续爆破无果,后续的话正好当时nps是爆出来了个鉴权的漏洞,通过这个漏洞我们实现反制,拿到了攻击者的一些信息,以及其掌握的相关权限。

总而言之,旁路反制的这个概念是非常广泛的,手段也是层出不朽的。在近些年的攻防的博弈中,防守方的防守体系已经逐渐体系成熟化,并且也逐渐开启了一些反制的号角,这里面蜜罐是最具有里程碑意义的。笔者认为一方攻一方守并不是所谓的攻防,攻防也者,应该是来回交战,攻中带防(攻击者要能掌握反反制手段),防中带攻(防守者要能抓住攻击者露出的马脚,进行反制),就和古代武侠比武一样。


参考文章:
https://forum.butian.net/share/1861
https://forum.butian.net/share/1975
https://mp.weixin.qq.com/s/l5e2p_WtYSCYYhYE0lzRdQ


Cobaltstrike上线过程与蓝队反制
https://glacierrrr.online/2022/11/28/Cobaltstrike上线过程与蓝队反制/
作者
Glacier
发布于
2022年11月28日
许可协议