点击蓝字 关注我们
日期:2022-10-20 作者:Corl 介绍:Malleable-C2-Profile文件分析
0x00 前言
通过微步查看自己服务器的时候,发现自己的服务器存在明显的Cobalt Strike
特征,于是学习了怎样去除特征以及怎样编写Malleable-C2-Profile
文件。
0x01 Malleable-C2-Profile基本介绍
Cobalt Strike
的Malleable-C2-Profile
配置文件是用来伪装流量和修改流量特征的,目的是让通讯更加隐蔽同时还可以控制Beacon
的一些默认行为。
1.1 检查方法
在使用Malleable-C2-Profile
前,建议使用Cobalt Strike
提供的c2lint
工具进行检查编写的配置文件是否可用、是否存在错误。存在错误时,会显示出错误所在行。
./c2lint [your.Profile]
1.2 使用方法
在启动Cobalt Strike
服务端的时候,指定一个配置文件进行加载。
./teamserver 服务器ip 密码 Profile文件
0x02 Malleable-C2-Profile文件分析
一个较全面的Malleable-C2-Profile
文件包括全局设置、DNS Beacon
、SMB Beacon
、TCP Beacon
、SSH Beacon
、Proxy
、HTTPS-Certificate
、HTTP-Config
、HTTP-Get
、HTTP-Post
、HTTP-Stager
、stage
、Process-Inject
、Post-Ex
部分,下面通过参数、参数描述、Wireshark
抓包的方式,对Malleable-C2-Profile
文件进行分析。
2.1 全局设置
全局设置主要是设置全局的一些属性,包括设置配置文件名称、心跳包时间、抖动值等,一般是写在配置文件的头部,具体参数及描述如下所示:
参数 | 默认值 | 描述 |
---|---|---|
sample_name |
My Profile |
设置配置文件名称 |
sleeptime |
60000 |
设置心跳包时间,单位为毫秒 |
jitter |
0 |
设置抖动值,单位百分比,范围为(0-99% ) |
useragent |
Internet Explorer (Random) |
设置全局useragent 头 |
data_jitter |
0 |
设置数据抖动值,向http get 和http post 服务器输出中附加随机长度字符串 |
host_stage |
true |
如果不需要分阶段传输payload ,就可以在这里将host_stage 的值设置为false |
示例代码:
set sample_name "chrome_browser.Profile";
set sleeptime "38500";set jitter "27";
set useragent "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36";
set data_jitter "50";
set host_stage "true";
通过使用Wireshark
抓包,可以看出HTTP
请求的useragent
头已经设置为Profile
文件中设置的参数内容。
2.2 DNS Beacon
设置DNS Beacon
的属性,包括DNS
请求延时时间、各种请求类型使用的域名等,具体参数描述如下所示:
参数 | 默认值 | 描述 |
---|---|---|
dns_idle |
0.0.0.0 |
Beacon 不用时指定到的dns 地址 |
dns_max_txt |
252 |
设置dns txt 响应的最大长度 |
dns_sleep |
0 |
设置在每个dns 请求之间设置延时,这里没有延时 |
dns_ttl |
1 |
dns 响应的ttl 的值 |
maxdns |
255 |
通过dns 上传数据时的主机名最大长度(0-255) |
dns_stager_prepend |
设置在dns payload 之前插入内容 |
|
dns_stager_subhost |
.stage.123456. |
设置dns txt 记录使用的子域 |
beacon |
用于信标请求的dns 主机前缀 |
|
get_A |
cdn. |
用于A 记录请求的dns 主机前缀 |
get_AAAA |
www6. |
用于AAAA 记录请求的dns 主机前缀 |
get_TXT |
api. |
用于TXT 记录请求的dns 主机前缀 |
put_metadata |
www. |
用于元数据请求的dns 主机前缀 |
示例代码:
dns-beacon {
set dns_idle "8.8.8.8";
set dns_max_txt "220";
set dns_sleep "0";
set dns_ttl "1";
set maxdns "255";
set dns_stager_prepend ".wwwds.";
set dns_stager_subhost ".e2867.dsca.";
set beacon "d-bx.";
set get_A "d-1ax.";
set get_AAAA "d-4ax.";
set get_TXT "d-1tx.";
set put_metadata "d-1mx";
set put_output "d-1ox.";
set ns_response "zero";
}
通过使用Wireshark
抓包,可以看出DNS
请求使用的域名已更改为Profile
文件中设置的参数内容。
2.3 SMB Beacon
设置SMB Beacon
的属性,包括使用的管道名称、stager
管道名称,具体参数如下所示:
参数 | 默认值 | 描述 |
---|---|---|
pipname | msagent_## | smb管道的名字,#表示替换为一个随机十六进制值。 |
pipename_stager | status_## | 设置stager使用的管道名 |
smb_frame_header | 配置是在smb信息前追加的特定字符 |
示例代码:
set pipename "ntsvcs##";
set pipename_stager "scerpc##";
set smb_frame_header "";
通过创建SMB Beacon
,可以看出pipename
已更改为Profile
文件中的pipename
。
2.4 TCP Beacon
设置TCP Beacon
的使用属性,包括使用的端口、配置是在TCP
信息前追加特定字符,具体参数如下所示:
参数 | 默认值 | 描述 |
---|---|---|
tcp_port |
4444 |
TCP 监听端口 |
tcp_frame_header |
配置是在TCP 信息前追加特定字符 |
示例代码:
set tcp_port "8000";
set tcp_frame_header "";
TCP Beacon
,可以看出tcp_port
已更改为Profile
文件中的tcp_port
。2.5 SSH Beacon
设置SSH Beacon
属性,包括ssh
的指纹信息、管道名称,具体参数如下所示:
选项 | 默认值 | 描述 |
---|---|---|
ssh_banner |
Cobalt Strike 4.2 |
SSH 客户端指纹信息 |
ssh_pipename |
postex_ssh_#### |
SSH 会话的管道名称。每个#都替换为一个随机十六进制值。 |
示例代码:
set ssh_banner "Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-1065-aws x86_64)";
set ssh_pipename "SearchTextHarvester##";
2.6 Proxy
设置代理属性,具体参数及描述如下所示:
参数 | 默认值 | 描述 |
---|---|---|
tasks_max_size |
1048576 |
设置任务和代理数据的最大大小(以字节为单位) |
tasks_proxy_max_size |
921600 |
设置在签入时通过通信通道传输的代理数据的最大大小(以字节为单位) |
tasks_dns_proxy_max_size |
71680 |
设置在签入信标时通过DNS 通信通道传输的代理数据的最大大小(以字节为单位) |
示例代码:
set tasks_max_size "1048576";
set tasks_proxy_max_size "921600";
set tasks_dns_proxy_max_size "71680";
2.7 HTTPS-Certificates
设置使用HTTPS
证书的属性,此选项会对全部的请求数据内容进行加密,虽然对数据进行了加密,但是仍然具有Cobalt Strike
特征,具体参数及描述如下所示:
参数 | 描述 |
---|---|
keystore |
store 文件 |
password |
store 文件密码 |
C |
国家 |
CN |
域名 |
O |
组织名 |
ST |
州或省 |
OU |
组织单位名称 |
L |
地区 |
validity |
证书有效天数 |
示例代码:
https-certificate {
set C "US";
set CN "jquery.com";
set O "jQuery";
set ST "CA";
set OU "Certificate Authority";
set L "Mountain View";
set validity "365";
}
code-signer {//代码签名
set keystore "your_keystore.jks";
set password "your_password";
}
通过Wireshark
抓包,可以看出请求数据已全部进行加密,也不会显示出服务器的ip
地址。
2.8 HTTP-Config
设置全局HTTP
请求的属性,当进行HTTP
请求时,会使用当前设置的内容,具体参数及说明如下所示:
参数 | 描述 |
---|---|
headers |
响应头字段,当有多个字段时,以逗号进行分隔 |
header |
字段内容 |
trust_x_forwarded_for |
决定Cobalt Strike 是否使用X-Forwarded-For HTTP 头来确定请求的远程地址 |
block_useragents |
配置一个阻止或回复404 的UA 列表。默认阻止curl、 lynx、wget |
示例代码:
http-config {
set headers "Server, Content-Type";
header "Content-Type" "text/html;charset=UTF-8";
header "Server" "nginx";
set trust_x_forwarded_for "false";
set block_useragents "curl*,lynx*,wget*";
}
通过使用Wireshark
抓包,可以看出响应头的Server
和Content-Type
字段已更改为Profile
文件中设置的参数内容。
2.9 HTTP-Get
设置GET
请求的参数值,此设置将会影响GET
请求内容,具体参数及说明如下所示:
参数 | 描述 |
---|---|
uri |
请求uri 地址,当有多个时,以空格进行分割,会进行随机请求 |
header |
字段内容 |
base64 |
使用base64 方式编码 |
prepend |
前置字符串,当有多个prepend 时,先执行后面的 |
append |
结尾字符串 |
print |
将数据进行输出 |
示例代码:
http-get {
set uri "/async/newtab_promos /async/newtab_ogb /async/ddljson";
client {
header "Sec-Fetch-Site" "none";
header "Sec-Fetch-Mode" "no-cors";
header "Sec-Fetch-Dest" "empty";
header "Accept-Language" "en-US,en;q=0.5";
metadata {#设置Cookie字段内容
base64;
prepend "NID=";
prepend "1P_JAR=2022; ";
header "Cookie";
}
}
server {
header "Version" "420932473";
header "Content-Type" "application/json; charset=UTF-8";
header "X-Content-Type-Options" "nosniff";
header "Strict-Transport-Security" "max-age-31536000";
header "Bfcache-Opt-In" "unload";
header "Server" "gws";
header "Cache-Control" "private";
header "X-Xss-Protection" "0";
header "X-Frame-Options" "SAMEORIGIN";
output {
base64url;
prepend "
)
]
}'
{
"ddljson":"";
append ""
{
}
}";
print;
}
}
}
通过使用Wireshark
抓包,可以看出GET
请求的请求头、响应头、响应内容已更改为Profile
文件中设置的参数内容。
2.10 HTTP-Post
设置POST
请求的参数值,这将会影响POST
请求的请求头以及响应头以及响应内容,具体参数及描述如下所示:
参数 | 默认值 | 描述 |
---|---|---|
verb |
GET,POST |
设置请求模式 |
base64url |
对url 进行Base64 编码 |
|
netbios |
NetBIOS 编码 |
示例代码:
http-post {
set uri "/service/update2/json /gen_204 ";
set verb "POST";
client {
header "Sec-Ch-Ua" "" Not;A Brand";v="99", "Google Chrome";v="97", "Chromium";v="97"";
header "Sec-Ch-Ua-Mobile" "?0";
header "Sec-Ch-Ua-Platfrom" "Windows";
header "Accept" "*/*";
header "Origin" "https://www.google.com";
header "Sec-Fetch-Site" "same-origin";
header "Sec-Fetch-Mode" "no-cors";
header "Sec-Fetch-Dest" "empty";
header "Referer" "https://www.google.com";
header "Accept-Language" "en-US,en;q=0.9";
output {
base64url;
header "X-Client-Data";
}
id {
base64url;
parameter "ei";
}
}
server {
header "Content-Type" "text/html; charset=UTF-8";
header "Bfcache-Opt-In" "unload";
header "Server" "gws";
header "X-Xss-Protection" "0";
header "X-Frame-Origins" "SAMEORIGIN";
header "Alt-Svc" "h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"";
output {
netbios;
prepend "n";
prepend "{";
append "n";
append "}";
print;
}
}
}
通过使用Wireshark
抓包,可以看出POST
请求的请求头、响应头、响应内容已更改为Profile
文件中设置的参数内容。
2.11 HTTP-Stager
设置Stager
的请求地址以及请求头、响应头、响应内容,具体参数及描述如下所示:
参数 | 描述 |
---|---|
uri_x86 |
设置用于下载 x86 payload stage 的 URI |
uri_x64 |
设置用于下载 x64 payload stage 的 URI |
示例代码:
http-stager {
set uri_x86 "/async_newtab_pro";
set uri_x64 "/async/Newtab_promos";
client {
header "Sec-Fetch-Site" "none";
header "Sec-Fetch-Mode" "no-cors";
header "Sec-Fetch-Dest" "empty";
header "Accept-Language" "en-US,en;q=0.5";
}
server {
header "Version" "420932473";
header "Content-Type" "application/json; charset=UTF-8";
header "X-Content-Type-Options" "nosniff";
header "Strict-Transport-Security" "max-age-31536000";
header "Bfcache-Opt-In" "unload";
header "Server" "gws";
header "Cache-Control" "private";
header "X-Xss-Protection" "0";
header "X-Frame-Options" "SAMEORIGIN";
output {
print;
}
}
}
通过使用Wireshark
抓包,可以看出stager
的请求的请求头、响应头、响应内容已更改为Profile
文件中设置的参数内容。
2.12 stage
设置stage
的相关属性,具体参数及描述如下所示:
参数 | 描述 |
---|---|
checksum |
Beacon 的PE 标头中的CheckSum 值 |
compile_time |
Beacon 的PE 标头中的构建时间 |
entry_point |
Beacon 的PE 头中的入口点值 |
image_size_x86 |
x86 Beacon 的PE 头中的镜像大小值 |
image_size_x64 |
x64 Beacon 的PE 头中的镜像大小值 |
userwx |
反射加载时是否要把内存设置为可读可写可执行 |
cleanup |
释放反射加载的dll 的内存 |
sleep_mask |
是否在sleep 前在内存中混淆beacon |
stomppe |
在加载Beacon 负载后,要求ReflectiveLoader 停止MZ 、PE 和e_lf 新值 |
obfuscate |
是否混淆反射调用dll 的导入表,覆盖无用的header 内容,请求反射加载器copy beacon 到新的内存没有dll 头 |
rich_header |
编译器插入的元信息 |
smartinject |
使用嵌入式函数指针提示引导Beacon 代理程序,而无需遍历kernel32 EAT |
magic_mz_x86 |
覆盖Beacon 反射DLL 的第一个字节 |
magic_mz_x64 |
与magic_mz_x86 相同;影响x64 DLL |
module_x86 |
要求x86 反射加载器加载指定的库并覆盖其空间,而不是使用VirtualAlloc 分配内存 |
module_x64 |
与module_x86 相同;影响x64 加载器 |
prepend |
在Beacon 反射调用dll 之前插入一些数据 |
strrep |
查找并替换字符串 |
示例代码:
stage {
set checksum "0";
set compile_time "12 Dec 2019 02:52:11";
set entry_point "170000";
#set image_size_x86 "6586368";
#set image_size_x64 "6586368";
set userwx "false";
set cleanup "true";
set sleep_mask "true";
set stomppe "true";
set obfuscate "true";
set rich_header "";
set smartinject "true";
set magic_mz_x86 "MZRE";
set magic_mz_x64 "MZAR";
set magic_pe "EA";
set module_x86 "wwanmm.dll";
set module_x64 "wwanmm.dll";
transform-x86 {
prepend "x90x90x90";
strrep "ReflectiveLoader" "";
strrep "beacon.dll" "";
strrep "This program cannot be run in DOS mode" "";
}
transform-x64 {
prepend "x90x90x90";
strrep "ReflectiveLoader" "";
strrep "beacon.x64.dll" "";
strrep "This program cannot be run in DOS mode" "";
}
}
2.13 Process-Inject
设置进程注入的相关内容,具体参数及描述如下所示:
参数 | 描述 |
---|---|
allocator |
在远程进程中分配内存的方式,有两种方式VirtualAllocEx 和NtMapViewOfSection |
bof_allocator |
在当前进程中分配内存以执行BOF 的首选方法。指定VirtualAlloc、MapViewOfFile或HeapAlloc |
bof_reuse_memory |
为后续的BOF 执行重用分配的内存,否则释放内存。不使用时,内存将被清除。如果可用内存量不够大,则会释放内存并以较大的大小进行分配 |
min_alloc |
最小的分配内存的大小 |
userwx |
是否使用rwx 作为代码内存的默认权限,默认rx |
startrwx |
是否使用rwx 作为代码内存的初始权限,默认rx |
示例代码:
process-inject {
set allocator "NtMapViewOfSection";
set bof_allocator "VirtualAlloc";
set bof_reuse_memory "true";
set min_alloc "16700";
set userwx "false";
set startrwx "true";
transform-x86 {
prepend "x90x90x90";
}
transform-x64 {
prepend "x90x90x90";
}
execute {
CreateThread "ntdll.dll!RtlUserThreadStart+0x1000";
SetThreadContext;
NtQueueApcThread-s;
CreateRemoteThread "kernel32.dll!LoadLibraryA+0x1000";
CreateRemoteThread;
RtlCreateUserThread;
}
}
2.14 Post-Ex
设置后渗透模块的相关属性,新建会话注入位置、启用混淆、键盘记录使用的函数等,具体参数及描述如下所示:
参数 | 描述 |
---|---|
spawnto_x86 |
设置spawnto32 进程注入位置 |
spawnto_x64 |
设置spawnto64 进程注入位置 |
obfuscate |
对dll 的内容进行加密,并且将post-ex 功能建立到内存中 |
smartinject |
提示beacon 将关键的函数指针嵌入到相同架构的post-ex dll 中 |
amsi_disable |
指示powerpick 、execute assembly 和psinject 在加载.NET 或PowerShell 代码之前修补AmsiScanBuffer 函数 |
thread_hint |
允许多线程post-ex DLL 生成具有欺骗起始地址的线程 |
pipename |
使用pipename 更改post-ex DLL 用于将输出发送回Beacon 的命名管道名称 |
keylogger |
设置键盘记录使用的函数GetAsyncKeyState or SetWindowsHookEx |
示例代码:
post-ex {
set spawnto_x86 "%windir%\syswow64\gpupdate.exe";
set spawnto_x64 "%windir%\sysnative\gpupdate.exe";
set obfuscate "true";
set smartinject "true";
set amsi_disable "true";
set thread_hint "ntdll.dll!RtlUserThreadStart+0x1000";
set pipename "DserNamePipe##, PGMessagePipe##, MsFteWds##";
set keylogger "SetWindowsHookEx";
}
0x03 总结
其实一个并不困难,在知道参数的含义后,就可以进行随意更改,建议使用自己编写的Malleable-C2-Profile
,使用别人编写的Malleable-C2-Profile
文件时间长了之后,也会被检测出来特征。
Reference
https://github.com/xx0hcd/Malleable-C2-Profiles/blob/master/normal/chrome_browser.Profile
https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/content/topics/malleable-c2_Profile-language.htm#_Toc65482837
原文始发于微信公众号(宸极实验室):『红蓝对抗』Malleable-C2-Profile文件分析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论