C2通信协议解析(一):HTTP(s)、mTLS、WebSocket、DNS
字数 6083 2025-10-01 14:05:44
C2通信协议解析教学文档
概述
本文档详细解析了四种常用于C2(Command and Control,命令与控制)框架的通信协议:HTTP(s)、mTLS、WebSocket和DNS。内容涵盖各协议的工作原理、在C2中的实现思路、关键代码示例及流量分析,旨在深入理解C2通信的隐匿与对抗技术。
一、HTTP/HTTPS
1.1 思路构建
HTTP(S)因其高带宽、普遍性及加密特性(HTTPS)成为主流C2通信协议。
- 任务获取:C2服务器(Server)启动HTTP(S)监听器,注册自定义URI的路由。Beacon(受控端)通过GET请求该URI获取任务。任务数据经加密后嵌入HTML模板的占位符中返回。
- 任务执行:Beacon通过正则匹配提取HTML中的加密任务数据,解密后执行命令(示例中为
cmd命令)。 - 结果回传:Beacon将任务执行结果加密后,通过POST请求同一URI回传给Server。
- 数据序列化:示例中使用JSON序列化任务和结果数据,简化开发但扩展性不足。
- 流量伪装:通过自定义多项参数使通信流量更像正常Web流量,包括:
- 协议类型(HTTP/HTTPS)
- 主机地址(HOST)
- 端口(PORT)
- 请求URI
- SSL证书(若为HTTPS)
- 返回的HTML页面内容
- 自定义HTTP响应头(如
X-Session-Id)
- 简化设计:示例中未实现任务队列,采用硬编码命令;未实现Beacon注册机制。
1.2 代码实现 (核心摘要)
Server端 (Go - Gin框架)
- 可控参数:定义HOST, PORT, URI, IS_HTTPS, 证书路径, HTML模板路径, 自定义Header, 加密密钥, 占位符, 硬编码任务等。
- ListenerStart函数:根据
IS_HTTPS配置,启动HTTP或HTTPS服务器,在指定URI上注册processRequest(GET)和processResponse(POST)处理函数。 - processRequest函数 (处理GET - 任务下发):
- 调用
parseBeat解析Beacon心跳包(Metadata)。 - 读取HTML模板文件。
- 将加密(示例为RC4)后的任务数据替换模板中的占位符。
- 设置自定义响应头。
- 返回包含任务数据的HTML页面。
- 调用
- processResponse函数 (处理POST - 结果回传):
- 调用
parseBeat解析心跳包。 - 读取请求Body,解密后得到任务执行结果。
- 将结果输出到Server控制台。
- 调用
- parseBeat函数:从自定义HTTP头(如
X-Session-Id)中提取值,进行Base64解码和RC4解密,得到原始Metadata(心跳包)。
Beacon端 (Go)
- HttpGet函数 (拉取任务):
- 将Metadata加密(RC4)并Base64编码。
- 将编码后的数据放入预定义的HTTP请求头(如
X-Session-Id)。 - 向Server的指定URI发起GET请求。
- 接收响应(HTML),使用正则匹配提取加密的任务数据。
- HttpPost函数 (回传结果):
- 将Metadata和任务结果分别加密、Base64编码。
- 将编码后的Metadata放入HTTP请求头。
- 将编码后的结果数据作为POST请求的Body。
- 向Server的指定URI发起POST请求。
- Main函数:循环执行
HttpGet-> 提取任务 -> 执行命令 ->HttpPost回传结果。
1.3 流量分析
- Beacon → Server (GET):请求自定义URI,心跳包在自定义Header中。
- Server → Beacon (Response):返回200 OK,数据为包含加密任务数据的HTML。
- Beacon → Server (POST):请求同一URI,心跳包在Header,加密结果在Body。
- Server → Beacon (Response):返回200 OK。
- 所有关键数据(心跳、任务、结果)均经加密,但协议本身特征明显。
1.4 域前置 (Domain Fronting)
- 目的:隐藏C2服务器的真实IP地址。
- 原理:利用CDN服务。Beacon配置中设置回调地址为CDN提供的CNAME域名。Beacon实际与CDN边缘节点通信,CDN根据配置将流量转发(回源)至真实的C2 Server。
- 流量特征:DNS查询解析到CDN节点IP而非真实Server IP。后续HTTP(S)通信目的IP也是CDN节点。通信内容仍加密。
- 实施:
- 注册域名。
- 在云厂商配置CDN,添加源站(真实Server IP)和CNAME记录。
- 在域名DNS设置中,添加一条NS记录,将特定子域(如
c2.example.com)的解析权委托给第2步中CDN提供的CNAME域名(或另一个A记录指向CDN)。 - Beacon的回调地址设置为该子域。
二、mTLS (Mutual TLS)
2.1 思路构建
mTLS在标准TLS基础上要求客户端与服务器相互验证证书,实现双向认证。
- 证书体系:需搭建私有PKI,生成自签名CA证书,并用其签发Server和Beacon(客户端)证书。
- 连接管理:Server为每个Beacon连接创建独立goroutine处理,实现长连接交互式会话。
- 流量分帧:为避免TCP粘包,自定义应用层协议:先发送4字节(大端序)表示数据长度,再发送实际数据。接收方先读长度,再读取指定长度的数据。
- 通信模式:示例为实时交互式。也可改造为Beacon模式(短连接+任务队列)。
2.2 代码实现
2.2.1 生成证书
使用Go代码或openssl命令生成:
- CA:自签名根证书及私钥 (
ca.crt,ca.key)。 - Server:由CA签发证书 (
server.crt) 和私钥 (server.key)。证书中需设置Subject Alternative Name (SAN)为Server的IP或域名。 - Beacon:由CA签发客户端证书 (
client.crt) 和私钥 (client.key)。
2.2.2 Server端
- ListenerStart函数:
- 加载Server证书、私钥及CA证书(用于验证Beacon证书)。
- 配置
tls.Config,设置ClientAuth: tls.RequireAndVerifyClientCert(关键,开启mTLS)。 - 调用
tls.Listen启动TLS监听。
- handleConnection函数:
- 接受连接后,进行TLS握手(包含双向证书验证)。
- 循环:读取Beacon发来的数据帧 -> 处理(示例中直接输出)-> 从标准输入读取命令 -> 将命令写入数据帧发送给Beacon。
2.2.3 Beacon端
- 加载Beacon(客户端)证书、私钥及CA证书(用于验证Server证书)。
- 配置
tls.Config,设置ServerName为Server的SAN中指定的域名或IP。 - 使用
tls.Dial连接Server。 - 成功连接后,发送初始元数据。
- 循环:读取Server发来的数据帧(命令)-> 执行命令 -> 将结果写入数据帧发送回Server。
2.3 流量分析
- 初始为TCP三次握手。
- 后续为TLS握手过程,包含Certificate Request、Client Certificate等mTLS特有报文。
- 应用层数据全部由TLS记录协议加密。
- 可使用域名连接,Beacon需先解析域名得到Server IP。
三、WebSocket
3.1 思路构建
WebSocket提供全双工通信,通过HTTP(S)升级建立,使用80/443端口,易于伪装。
- 协议升级:Beacon发送包含
Upgrade: websocket头的HTTP请求,Server响应101状态码完成升级。 - 内置分帧:WebSocket协议自身有帧格式(操作码+长度+载荷),无需自行解决粘包问题。
- 通信模式:示例实现类交互式会话。长连接,实时性强。
3.2 代码实现
3.2.1 Server端 (使用gorilla/websocket)
- ListenerStart函数:启动HTTP(S)服务器,在指定路径(如
/ws)上挂接处理函数。 - 处理函数:
- 使用
Upgrader将HTTP连接升级为WebSocket连接。 - 在新goroutine中
handleConnection。
- 使用
- handleConnection函数:
- 读取Beacon发来的消息(如心跳)。
- 循环:从标准输入读命令 ->
conn.WriteMessage(websocket.TextMessage, []byte(cmd))发送 ->conn.ReadMessage()读取Beacon回显。
3.2.2 Beacon端
- 使用
websocket.Dialer连接Server的WebSocket端点(WS或WSS)。 - 成功连接后,可发送初始消息。
- 循环:
conn.ReadMessage()接收命令 -> 执行 ->conn.WriteMessage(websocket.TextMessage, []byte(result))发送结果。
3.3 流量分析
- HTTP Upgrade请求:可见
Connection: Upgrade和Upgrade: websocket头。 - HTTP 101响应:协议切换成功。
- 后续通信:为WebSocket二进制帧,载荷内容加密后不可读。
- 改进方向:
- 使用WSS(WebSocket Secure)。
- 伪装Upgrade路径和HTTP头。
- 部署在正常Web服务下。
- 结合域前置。
四、DNS
4.1 前置知识
- DNS隧道:将数据封装在DNS查询和响应中进行传输。利用UDP 53端口通常开放且检查宽松的特点。
- 记录类型:
- A (IPv4地址):4字节载荷。常用于控制信号或小数据。
- TXT (文本记录):≤255字节/记录。常用于传输任务数据。
- AAAA (IPv6地址):16字节载荷。
- 限制:域名标签长度≤63字符,总域名长度≤253字符。需编码(如Hex、Base32无填充)以适应域名格式。
- 实现模式:反向连接。Beacon主动向Server(权威DNS服务器)发起查询。
4.2 Cobalt Strike DNS Beacon使用 (参考)
- 域名配置:
- 注册域名(如
example.com)。 - 添加一条A记录:将子域(如
ns1.example.com)指向C2 Server IP。 - 添加一条NS记录:将子域(如
c2.example.com)委托给ns1.example.com解析。
- 注册域名(如
- CS配置:DNS监听器的
DNS Hosts设置为NS记录的子域(c2.example.com)。 - 通信流程:
- 心跳/拉取任务:Beacon查询
[agentId].[c2.example.com]的A记录。Server返回的IPv4地址的最后一个字节作为控制信号(如0无任务,非0则需TXT查询取任务)。 - 获取任务:Beacon查询
[agentId].[c2.example.com]的TXT记录。Server在TXT响应中返回任务数据。 - 回传数据:Beacon将数据分片编码后,放入查询子域的名称中(如
[data].[agentId].[c2.example.com]),发起A查询。Server记录查询名即可提取数据。需实现分片、重组、序号机制。
- 心跳/拉取任务:Beacon查询
4.3 思路构建
- 反向连接:Beacon作为DNS客户端,向Server(权威DNS服务器)发起查询。
- 任务获取:Beacon通过TXT查询获取任务。
- 结果回传:Beacon通过A查询,将编码后的数据嵌入查询域名中回传。
- 数据分片:因域名长度限制,大数据需分片传输。Server需重组。
- 编码:使用Hex或Base32无填充将二进制数据编码为域名合法字符。
- 多Beacon:通过查询域名中的
agentId区分不同Beacon。
4.4 代码实现 (简化概念)
(一)发送心跳包/回传数据 (Beacon - A查询)
- DNSPut函数:
- 将待发送数据(如Metadata、结果)进行Hex编码。
- 根据数据长度,按预定义档位(如104B, 84B, 56B, ... 4B)分片。
- 对于每一片数据,构造查询域名:
[档位标识][分片数据][序号][Nonce][agentId].[委托域]。 - 发起A记录查询。Server端记录查询域名即可提取数据。
- 实现重传机制。
- 心跳包:上线时发送一次。
(二)解析回传数据 (Server - 处理A查询)
- 检查查询域名前缀(如
www,post)。 - 提取
agentId、Nonce、序号、分片数据。 - 如果是首包(序号0),提取总长度信息。
- 根据Nonce和序号将数据分片存入缓存。
- 收齐所有分片后,Hex解码重组原始数据。
(三)获取任务 (Beacon)
- 获取控制信号:向
api.[agentId].[domain]发起A查询。Server返回IP,最后一字节为信号。 - 获取任务数据:向
api.[agentId].[domain]发起TXT查询。Server返回TXT记录,其中包含任务数据(可分片)。Beacon拼接TXT记录得到完整任务。
(四)Server响应
- 对A查询:根据场景返回预设IP(如控制信号)。
- 对TXT查询:返回包含(分片)任务数据的TXT记录。
4.4 实验注意事项
- Server需监听UDP 53端口,并拥有公网IP。
- 确保VPS安全组/防火墙放行UDP 53端口。
- 关闭可能占用53端口的本地服务(如
systemd-resolved)。 - 客户端DNS服务器需设置为可解析互联网DNS的地址(如
8.8.8.8)。
五、下一步计划
作者表示后续可能研究方向:
- 免杀技术(二进制相关)。
- 深入分析公开的Cobalt Strike Beacon源码。
- 继续完善C2协议研究(本篇为第一篇)。
参考资料
- Sliver C2 框架源码 (mtls, dns)
- Gorilla WebSocket 库文档
- DNS 协议规范 (RFC 1035)
- 域前置技术文章(先知社区、长亭)
- Cobalt Strike DNS Beacon 技术分析文章(FreeBuf、博客园等)
- Cobalt Strike 官方文档