分析Cobalt Strike 威胁情报分析之Cobalt Strike

分析Cobalt Strike 威胁情报分析之Cobalt Strike

分析Cobalt Strike 威胁情报分析之Cobalt Strike

我不确定今年会发生什么,但是从现在开始,从APT41APT32,Cobalt Strike似乎是全球使用最广泛的恶意软件,甚至上一次SolarWinds供应链攻击都涉及Cobalt Strike。在不重新发布有关发布攻击性工具的激烈辩论的情况下,此博客文章旨在总结分析人员需要了解的有关Cobalt Strike的知识,以便在事件发生时快速进行识别和分析。

查找Cobalt Strike服务器

几个月前,Salesforce安全团队发布了一个名为JARM的新的活动指纹工具。它等效于他们去年发布的JA3。它基于远程服务器的TLS配置(例如TLS版本或TLS扩展)生成指纹,而无需考虑证书。识别某些工具使用的自定义Web服务器特别有用,Cobalt Strike就是其中之一。

这是Cobalt Strike JARM签名: 

07d14d16d21d21d07c42d41d00041d24a458a375eef0c576d23a7bab9a9fb1

JARM已经添加到ShodanBinaryEdgeSecurityTrails中,Shodan最近在上添加了索引ssl.jarm,因此很容易在野外找到Cobalt Strike服务器。

我们来Shodan上找答案

ssl.jarm:07d14d16d21d21d07c42d41d00041d24a458a375eef0c576d23a7bab9a9fb1:
分析Cobalt Strike 威胁情报分析之Cobalt Strike

Shodan使用此JARM指纹Cobalt Strike服务器确定了5623个IP,主要是在Amazon和Digital Ocean上。如果限制为端口443,则将获得3423个IP。

我们可以使用JARM轻松确认Cobalt Strike仍在第一个IP的端口443上运行:

$ python jarm.py 78.152.61.71
Domain: 78.152.61.71
Resolved IP: 78.152.61.71
JARM: 07d14d16d21d21d07c42d41d00041d24a458a375eef0c576d23a7bab9a9fb1

(此JARM签名实际上是Java Web服务器的签名,并且特定于JAVA 11堆栈,因此它包括与Cobalt Strike不相关的其他工具(例如Burp Suite),并且不包括使用不同Java版本的CobaltStrike。

获取Cobalt Strike的payloads

Cobalt Strike使用称为checksum8的算法使用url的校验和来提供32b或64b版本的有效负载(与metasploit服务器相同)。Cobalt Strike的反编译代码已在GitHub或其他地方发布了几次,它提供了有关此校验和的信息:

public static long checksum8(String text) {
    if (text.length() < 4) {
        return 0L;
    }
    text = text.replace("/", "");
    long sum = 0L;
    for (int x = 0; x < text.length(); x++) {
        sum += text.charAt(x);
    }

    return sum % 256L;
}

public static boolean isStager(String uri) {
    return (checksum8(uri) == 92L);
}

public static boolean isStagerX64(String uri) {
    return (checksum8(uri) == 93L && uri.matches("/[A-Za-z0-9]{4}"));
}

我们可以轻松地通过暴力破解算法来找到与python相匹配的网址:

from itertools import product
import string

def checksum8(strr):
    j = 0
    if len(strr) < 4:
        return 0
    strr = strr.replace("/", "")
    for c in strr:
        j += ord(c)
    return j % 256

chars = string.ascii_letters + string.digits
to_attempt = product(chars, repeat=4)
for attempt in to_attempt:
    word = ''.join(attempt)
    r = checksum8(word)
    if r == 92:
        print("{:30} - 32b checksum".format(word))
    elif r == 93:
        print("{:30} - 64b checksum".format(word))
$ python bf_checksum8.py
aaa9                           - 32b checksum
aab8                           - 32b checksum
aab9                           - 64b checksum
aac7                           - 32b checksum
aac8                           - 64b checksum
aad6                           - 32b checksum
aad7                           - 64b checksum
[...]

因此/aaa9应返回32位信标(如果可用),并/aab9应返回64位信标(如果可用)。让我们测试一下Shodan列表中的其中一台Cobalt Strike服务器103.39.18.184(AS136800-ICIDC NETWORK-中国)(要知道的一件事是Cobalt Strike服务器阻止了异常的用户代理)。

$ wget --no-check-certificate https://103.39.18.184/aaa9
--2020-12-19 17:44:32--  https://103.39.18.184/aaa9
Connecting to 103.39.18.184:443... connected.
WARNING: cannot verify 103.39.18.184's certificate, issued by ‘CN=gmail.com,OU=Google Mail,O=Google GMail,L=Mountain View,ST=CA,C=US’:
  Self-signed certificate encountered.
    WARNING: certificate common name ‘gmail.com’ doesn't match requested host name ‘103.39.18.184’.
HTTP request sent, awaiting response... 404 Not Found
2020-12-19 17:44:33 ERROR 404: Not Found.


$ wget --no-check-certificate --user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36" https://103.39.18.184/aaa9
--2020-12-19 17:44:52--  https://103.39.18.184/aaa9
Connecting to 103.39.18.184:443... connected.
WARNING: cannot verify 103.39.18.184's certificate, issued by ‘CN=gmail.com,OU=Google Mail,O=Google GMail,L=Mountain View,ST=CA,C=US’:
  Self-signed certificate encountered.
    WARNING: certificate common name ‘gmail.com’ doesn't match requested host name ‘103.39.18.184’.
HTTP request sent, awaiting response... 200 OK
Length: 208980 (204K) [application/octet-stream]
Saving to: ‘aaa9’

aaa9                    100%[============================>] 204.08K   655KB/s    in 0.3s

2020-12-19 17:44:53 (655 KB/s) - ‘aaa9’ saved [208980/208980]


$ wget --no-check-certificate --user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36" https://103.39.18.184/aab9
--2020-12-19 17:44:58--  https://103.39.18.184/aab9
Connecting to 103.39.18.184:443... connected.
WARNING: cannot verify 103.39.18.184's certificate, issued by ‘CN=gmail.com,OU=Google Mail,O=Google GMail,L=Mountain View,ST=CA,C=US’:
  Self-signed certificate encountered.
    WARNING: certificate common name ‘gmail.com’ doesn't match requested host name ‘103.39.18.184’.
HTTP request sent, awaiting response... 200 OK
Length: 260679 (255K) [application/octet-stream]
Saving to: ‘aab9’

aab9                    100%[============================>] 254.57K   872KB/s    in 0.3s

2020-12-19 17:44:59 (872 KB/s) - ‘aab9’ saved [260679/260679]

因此,该IP103.39.18.184给了我们两个Cobalt Strike信标:

分析Cobalt Strike 威胁情报分析之Cobalt Strike
分析Cobalt Strike 威胁情报分析之Cobalt Strike

解密Cobalt Strike信标

服务器返回的文件实际上不是PE文件:

$ file *
aaa9:     data
aab9:     data

在执行Cobalt Strike漏洞利用期间,它将下载此信标并直接在内存中运行。因此,此文件是一小段数据,在开头包含shellcode,该shellcode解码并执行信标。

我们可以使用miasm轻松地绘制此shellcode:

分析Cobalt Strike 威胁情报分析之Cobalt Strike

第一个JMP在加密密钥和加密信标之前直接进入呼叫。调用返回到Shellcode,下一个POP EDX获得密钥的地址。中的代码loc_f获取EBX中的密钥,EAX中有效负载的长度,并将其存储在堆栈上最终信标的地址中。循环loc_1d进入信标,然后用密钥对其进行异或。

我们可以轻松地在python中重现它,挑战是找到基址。这loc_47是紧接密钥,长度和加密有效负载之前的调用地址,因此基址为0x47 + 5(调用指令的长度)。基地址随有效负载的不同而变化,但是可以通过搜索最后一个调用指令轻松找到它。

import struct

def xor(a, b):
    return bytearray([a[0]^b[0], a[1]^b[1], a[2]^b[2], a[3]^b[3]])

with open("aaa9", "rb") as f:
    data = f.read()

ba = 0x4c
key = data[ba:ba+4]
print("Key : {}".format(key))
size = struct.unpack("I", xor(key, data[ba+4:ba+8]))[0]
print("Size : {}".format(size))

res = bytearray()
i = ba+8
while i < (len(data) - ba - 8):
    d = data[i:i+4]
    res += xor(d, key)
    key = d
    i += 4

with open("a.out", "wb+") as f:
    f.write(res)

我们得到一个PE文件:3c9a06b2477694919b1c77d3288984cb793a47dd328ef39e15132cd0cfb593ab

分析Cobalt Strike 威胁情报分析之Cobalt Strike

令人惊讶的是直接在此看到PE文件,因为它是由上一次调用直接执行的。诀窍在于,实际上将PE文件修改为一个有效的PE文件,并且可以直接直接执行(Cobalt Strike称为无级有效负载)。我们在这里看到正在执行的MZ标头:

分析Cobalt Strike 威胁情报分析之Cobalt Strike

修改了DOS标头,使其包含跳至二进制文件中地址0x8157的有效指令。此地址是导出_ReflectiveLoader@4函数的地址,该函数基于RefelctiveDLLInection软件,负责在调用入口点之前再现一个简单的PE加载器以加载和映射导入函数。

(请注意,这仅在Cobalt Strike中是可选的,许多Cobalt Strike有效负载不具有PE文件格式,而是直接类似于Shellcode格式的有效负载)。

提取配置

Cobalt Strike配置在有效负载中进行了加密,并根据Cobalt Strike版本使用不同的密钥(0x23或0x69)。解码后,配置以type-length-value格式存储:

  • 一个简短的表示数据密钥的列表(可以在Cobalt Strike源代码中找到该列表)
  • 两个短字节代表数据类型(Int,Short,String等)及其长度
  • 数据本身

要找到配置的起始地址,我们可以查找第一个密钥的编码值,即1(DNS / SSL),1(Short),2(2个字节),并ihihik使用密钥0x69或././.,使用键0x23。

然后,我们可以解码信标的配置:

dns                            False
ssl                            True
port                           443
.sleeptime                     60000
.http-get.server.output        00000004000000010000017700000001000000fa0000000200000004000000020000001c000000020000002400000002000000120000000200000004000000020000001c0000000200000024000000020000001100000002000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
.jitter                        15
.maxdns                        255
publickey                      30819f300d06092a864886f70d010101050003818d0030818902818100aef69a6fb8f21092c01a95cbdcac0f03f79738adecda36cffc6c5cf607943e72663865f8f69d84961910201ffde089b24cd4352c766414d0665537956b8ec8f4e23df0cd79e9284c16c899fde818758a22c53947e3dd52f440be86f71cdf8abb79adb3b8afaf9f80af028d823f1d70fcdbb34b0b5f5293f74dbb184a3c9109f3020301000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
.http-get.uri                  156.226.191.234,/_/scs/mail-static/_/js/,djiqowenlsakdj.com,/_/scs/mail-static/_/js/
.user-agent                    Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; MALCJS)
.http-post.uri                 /mail/u/0/
.http-get.client               OSID=Cookie
GAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
ui=d3244c4707ient
                hop=6928632	start=0
=Content-Type: application/x-www-form-urlencoded;charset=utf-8OSID=Cookie
.spawto
.post-ex.spawnto_x86           %windir%\syswow64\notepad.exe
.post-ex.spawnto_x64           %windir%\sysnative\notepad.exe
.pipename
.cryptoscheme                  0
.dns_idle                      134743044
.dns_sleep                     0
.http-get.verb                 GET
.http-post.verb                POST
shouldChunkPosts               0
.watermark                     305419896
.stage.cleanup                 0
CFGCaution                     0
host_header
cookieBeacon                   1
.proxy_type                    2
funk                           0
killdate                       0
text_section                   0
process-inject-start-rwx       64
process-inject-use-rwx         64
process-inject-min_alloc       0
process-inject-transform-x86
process-inject-transform-x64
process-inject-stub            a56c813864af878a4c10083ca1578e0a
process-inject-execute
process-inject-allocation-method 0

合并结果

既然我们已经解码了所有内容,那么很容易执行请求,直接提取信标和配置。我把所有这些都放在这个github仓库中的脚本中:

$ python scan.py https://103.39.18.184/
Checking https://103.39.18.184/
Unknown config command 55
Configuration of the x86 payload
dns                            False
ssl                            True
port                           443
.sleeptime                     60000
.http-get.server.output        00000004000000010000017700000001000000fa0000000200000004000000020000001c000000020000002400000002000000120000000200000004000000020000001c0000000200000024000000020000001100000002000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
.jitter                        15
.maxdns                        255
[SNIP]

x86_64: Payload not found

通常会为许多不同的样本找到相同的配置,因为CS使用了他们所谓的可锻C2配置文件,这些配置文件实际上是CS信标的配置,可以通过配置文件轻松共享。例如,Ocean Lotus使用模仿Google Safebrowsing url公共配置文件。该存储库列出了不同的APT或网络犯罪组使用的配置文件。

配置中一个有趣的值是水印,它是从许可证文件生成的数字。由于它是客户特有的,因此可用于将多个CobaltStrike实例枢轴连接和链接在一起(就像Trickbot所做的那样。因此,许多CobaltStrike的破解版本都禁用了此水印。该水印在技术上与Cobalt Strike客户相关联id,因此应该可以将此ID报告给Cobalt Strike并为使用付费许可证的人员标识客户,但是我从未听说过有人这样做(我猜很少有APT组拥有有效的CS许可证)。

提取1000个Cobalt Strike服务器的配置

基于相同的代码,我扫描了Shodan中用JARM标识的3424台服务器,并使用此脚本扫描了所有服务器,并发现了520个使用Cobalt Strike信标的服务器。

我在GitHub上传了一个csv,其中列出了这些信标的IP和配置,这是一个简短的摘录:

host获取URIPOST URI用户代理水印
54.66.253.14454.66.253.144,/s/ref=nb_sb_noss_1/167-3294888-0262949/field-keywords=books/N4215/adj/amzn.us.sr.apsMozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko562884990
103.243.183.250103.243.183.250,/search.js/hrMozilla/5.0 (Linux; Android 6.0; HTC One X10 Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0305419896
185.82.126.47185.82.126.47,/pixel/submit.phpMozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; MASB)305419896
94.156.174.12194.156.174.121,/watch/ptrackingMozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko)76803050
194.36.191.118194.36.191.118,/visit.js/submit.phpMozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; InfoPath.2; .NET CLR 2.0.50727)305419896
23.106.160.198repshd.com,/us/ky/louisville/312-s-fourth-st.html,pinglis.com,/us/ky/louisville/312-s-fourth-st.html,stargut.com,/us/ky/louisville/312-s-fourth-st.html/OrderEntryService.asmx/AddOrderLineMozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko)0
23.81.246.46contmetric.com,/s/ref=nb_sb_noss_1/167-3294888-0262949/field-keywords=books/N4215/adj/amzn.us.sr.apsMozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko0
108.174.193.11qw.removerchangefile.monster,/media.html,as.removerchangefile.monster,/media.html,zx.removerchangefile.monster,/media.html/akMozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/601.3.9 (KHTML, like Gecko) Version/9.0.2 Safari/601.3.9305419896
213.217.0.218213.217.0.218,/visit.js/submit.phpMozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; NP06)305419896
213.252.247.311nubjgrcfjhjhkjftdd.com,/s/ref=nb_sb_noss_1/167-3294888-0262949/field-keywords=books/N4215/adj/amzn.us.sr.apsMozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko0

其中有523个中的165个没有水印,160个IP使用了另一个水印(305419896),因此它可能是默认值。然后,一些水印具有5个以上的服务器,例如1580103814、1873343027或16777216。

520个使用Cobalt Strike信标服务器列表下载地址

雨苁网盘: https://w.ddosi.workers.dev/

分析Cobalt Strike 威胁情报分析之Cobalt Strike

我已经在Github上上传了所有这些信标脚本和yara规则,可以在Twitter上直接向我发送DM或向我发送电子邮件,如果您有任何疑问。

from