原文链接:对云函数隐藏C2技术的防御反制思路
前言 随着云函数概念越来越火热,最近几次攻防演练经常能看见云函数扫描器以及云函数隐藏C2服务器,网上只有使用云函数攻击的技术,而基本没有防御的技术,于是我想着就总结一下,如有差错,欢迎斧正 环境复现 关于环境的搭建,前人之述备矣 https://xz.aliyun.com/t/10764 我这里补充一些版本更新过后可能会出现的一些坑 对于腾讯云函数,如果你的python选择了比较新的python3.7,它是不带request库的,需要你自己安装(python3.6自带这个库)所以建议用3.6版本的python 现在安装库可以不用自己上传zip包了,可以直接在终端使用pip下载 腾讯云只有新版本在线编辑器才能使用终端指令,而且会特别慢特别卡 安装完成后访问80显示404是正常现象,访问后腾讯云出现日志记录就代表成功了 全部安装完成后 cs中的两个上线地址 必须去掉http:// 和 :80,比如service-xxxxxxxx-xxxxxxxxxx.sh.apigw.tencentcs.com这样的格式,否则不会成功 流量分析 现在我的环境已经配置好了,我们先从流量方面分析,cs的流量可以简单的分为三个阶段 stage下载 beacon的心跳包阶段 执行C2服务器的命令并将结果回传阶段 如果是unstage则只有俩个(因为unstage相当于stage+payload,所以unstage的大小比stage大很多,stage才17KB多,unstage直接上了200) beacon的心跳包阶段 执行C2服务器的命令并将结果回传阶段 stage下载 当你执行bean文件时(我用的是这个stager,他可以远程下载一个 payload),它会注入到当前被执行服务器内存,然后执行C2的命令 beacon的心跳包阶段 beacon按照在profile里面的配置以get方法向c2发起心跳请求,同时将宿主机的信息经过公私钥加密后再通过配置文件的加密混淆方式加密再发出 执行C2服务器的命令并将结果回传阶段 C2服务器不会主动请求客户端,当客户端向C2服务端发送心跳包的时候,C2会把命令放入http心跳请求返回包中 然后当beacon端处理完成后,通过post方法回传数据。 stage下载 请求包 这个地方有一个特点,就是 符合一个checksum8规则,即:路径的ascii之和与256取余计算值等于92。 返回包 相对应的profile文件 这一阶段分析措施主要是看这个大流量包,流量包的大小差不多是在210kb左右,通过解析后可以看到回连地址、加密字段、公钥等配置信息 对加解密有兴趣的可以看看这个工具 https://github.com/WBGlIl/CS_Decrypt set uri_x86 就是 32位的机子发送的 set uri_x64 就是64位的机子发送的 我的靶机是64位所以Get请求包是访问 /bootstrap-2.min.js 此外,返回包里面还包括了云函数特有的几个属性 X-Request-Id: 请求的id X-Api-FuncName: 函数名,比如我在云函数里面设置的就是 test,这个是会被看出来的,所以建议红队伪装一个业务名字 X-Api-AppId: 对应账号但是不是账号,后面说明 X-Api-ServiceId: 服务id X-Api-HttpHost: 就是把appid 账号id 还有腾讯云函数的域名放一起 X-Api-Status: 200 返回值 X-Api-UpstreamStatus: 200 返回值 但凡看到有这个格式,基本可以判断是云函数了(但具体是不是业务需要和甲方业务组沟通) 心跳包阶段 这是cs的心跳包,心跳包通过cookie传输机器信息(使用了公私钥加密),先经过一次base64编码,再添加"SESSIONID=",最后添加 header "Cookie"; 对于云函数配置下的cs配置文件(此处可以更改) http-get { set uri "/api/getit"; client { header "Accept" "*/*"; metadata { base64; prepend "SESSIONID="; header "Cookie"; } } X-Api-AppId 不是账号啊ID,但是是对应着账号ID的, X-Api-ServiceId 我在控制台没找到,应该是对应test云函数服务的id 的 命令执行阶段 执行了两次命令 一次是whoami 一次是pwd 流量包是这样的 可以看出请求头依旧会带有很明显的云函数特征,Host头带有请求云函数的api的url,header中带有云函数的各种参数 profile文件分析 红队对cs魔改大部分是profile文件,这是一个比较常见的云函数的profile文件 set sample_name "t"; set sleeptime "3000"; set jitter "0"; set maxdns "255"; set useragent "Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/5.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" "Nodejs"; 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; } } } 您可以通过配置文件配置 Beacon 的默认值。有两种类型的选项:全局选项和局部选项。全局选项更改全局的信标设置。 本地选项是特定于事务的 (这句话的翻译自cs的官方手册,原文是 Local options are transaction specific 在我看来,在这里的意思是专注于方式的配置,比如对于http协议应该如何配置,对于https又应该选择如何配置) 全局选项 如 1 set sleeptime set sleeptime "3000"; 是设置默认的睡眠时间,注意此处是以毫秒为单位的 2 set jitter set jitter "0"; 这个是设置数据抖动 官方给出的解释是 Append random-length string (up to data_jitter value) to http-get and http-post server output. 就是让返回包的大小在一定范围内随机抖动,单位是百分比 在一些文章中,会通过它cs流量包的默认大小来溯源,建议修改 3 set maxdns ` set maxdns 是 通过 DNS 上传数据时主机名的最大长度 (0-255) 详情见于 https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/content/topics/malleable-c2_dns-beacons.htm?Highlight=maxdns 4 set useragent set useragent 这个显而易见 设置UA 如果你对这个感兴趣,可以参考 https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/content/topics/malleable-c2_profile-language.htm#_Toc65482842 局部选项 首先它会有一个模板 # this is a comment 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" "Nodejs"; output { base64; print; } } } 这是一个对get请求方式的局部选项配置 # 是代表注释 set uri set uri 分配客户端和服务器在此事务期间将引用的 URI, set 语句需要出现在客户端和服务器代码块之外,因为它适用于它们两者。 client header 添加header metadata { base64; prepend "SESSIONID="; header "Cookie"; } 是代表metadata先经过一次base64编码,再在编码后的数据前面添加"SESSIONID=",最后在修改过的数据后添加 header头 "Cookie"; server output { base64; print; } 输出的metadata进行base64编码,再打印 分析与反制思路 所以 综上所述 有几个分析与反制的思路 判断流量特征 如果是stage,会有一个payload下载阶段,大小约为210kb,payload未解密之前间隔有大批量重复字符串(cs本身特征) 未经魔改的云函数配置在stage下载阶段访问/bootstrap-2.min.js (配置文件特征),同时返回包有很大一串加密数据,且路径的ascii之和与256取余计算值等于92(cs本身特征) 未经魔改的云函数会访问/api/getit这样类似api的模式,可以重点关注(配置文件特征) 云函数的host是service-173y3w0z-xxxxxxxxxx.sh.apigw.tencentcs.com这样的格式,有点类似域前置,host为白域名,可以着重注意host为apigw.tencentcs.com格式的流量,如果业务部门没有这样的业务,特殊时期,可以直接封禁这个域名apigw.tencentcs.com(云函数特征) 请求头中会有云函数的特有特征,如 X-Request-Id: 请求的id X-Api-FuncName: 函数名 X-Api-AppId: 对应账号但是不是账号 X-Api-ServiceId: 服务id X-Api-HttpHost: 就是把appid 账号id 还有腾讯云函数的域名放一起 X-Api-Status: 200 返回值 X-Api-UpstreamStatus: 200 返回值 抓包看流量,通信的IP是腾讯云的CDN服务器IP 反制手段 截图举报 收集好证据,主要是 host名 X-Api-FuncName X-Api-AppId 这些带有明显云函数的特征的证据,(X-Api-AppId这个很重要)说明该人正在使用云函数对我司进行恶意攻击,请求对其暂时封禁. 虚假上线 重放心跳包进行上线,但是红队无法执行任何命令 消耗云函数额度 云函数隐藏C2 和 cdn很像,都有同一个弱点,就是访问是需要计费的,所以可以使用脚本把红队的额度跑掉就好,这样红队的所有马都无法上线 批量上线钓鱼马 从cs客户端可以看出,上线后的ip过一会就会自动变一次(云函数特性),一次性上线大量ip会让红队直接无法分辨(直接放同一个虚拟机都行,因为每次云函数的特性,所以每个心跳包都是一个新的请求,都会分配一个新ip)
|