mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-05-15 21:08:01 +02:00
259 lines
10 KiB
Go
259 lines
10 KiB
Go
// Package c2 实现 CyberStrikeAI 内置 C2(Command & Control)框架。
|
||
//
|
||
// 设计概述:
|
||
// - Manager 作为统一入口,被 internal/app 实例化并注入到所有需要操控 C2 的组件
|
||
// (HTTP handler、MCP 工具、HITL 桥、攻击链记录器等)。
|
||
// - Listener 是抽象接口,下挂 tcp_reverse / http_beacon / https_beacon / websocket
|
||
// 等不同传输方式的具体实现,全部通过 listener.Registry 工厂创建。
|
||
// - 任务调度走数据库(c2_tasks 表)+ 内存事件总线(EventBus)混合:
|
||
// * 状态变化与历史记录靠 SQLite 实现持久化与重启恢复;
|
||
// * 高频实时通知(如新任务结果)通过 EventBus 推送给 SSE/WS 订阅者,避免轮询。
|
||
// - Crypto 层固定 AES-256-GCM,每个 Listener 独立 32 字节密钥;密钥仅服务端持有
|
||
// 和编译期注入到 implant,事件流不允许导出明文密钥。
|
||
package c2
|
||
|
||
import (
|
||
"errors"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
// ListenerType 监听器类型,与 c2_listeners.type 字段一致
|
||
type ListenerType string
|
||
|
||
const (
|
||
ListenerTypeTCPReverse ListenerType = "tcp_reverse"
|
||
ListenerTypeHTTPBeacon ListenerType = "http_beacon"
|
||
ListenerTypeHTTPSBeacon ListenerType = "https_beacon"
|
||
ListenerTypeWebSocket ListenerType = "websocket"
|
||
)
|
||
|
||
// AllListenerTypes 列出所有受支持的监听器类型,便于校验与前端枚举
|
||
func AllListenerTypes() []ListenerType {
|
||
return []ListenerType{
|
||
ListenerTypeTCPReverse,
|
||
ListenerTypeHTTPBeacon,
|
||
ListenerTypeHTTPSBeacon,
|
||
ListenerTypeWebSocket,
|
||
}
|
||
}
|
||
|
||
// IsValidListenerType 校验前端/MCP 入参是否为合法 type
|
||
func IsValidListenerType(t string) bool {
|
||
t = strings.ToLower(strings.TrimSpace(t))
|
||
for _, lt := range AllListenerTypes() {
|
||
if string(lt) == t {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// SessionStatus 与 c2_sessions.status 一致
|
||
type SessionStatus string
|
||
|
||
const (
|
||
SessionActive SessionStatus = "active"
|
||
SessionSleeping SessionStatus = "sleeping"
|
||
SessionDead SessionStatus = "dead"
|
||
SessionKilled SessionStatus = "killed"
|
||
)
|
||
|
||
// TaskStatus 与 c2_tasks.status 一致
|
||
type TaskStatus string
|
||
|
||
const (
|
||
TaskQueued TaskStatus = "queued"
|
||
TaskSent TaskStatus = "sent"
|
||
TaskRunning TaskStatus = "running"
|
||
TaskSuccess TaskStatus = "success"
|
||
TaskFailed TaskStatus = "failed"
|
||
TaskCancelled TaskStatus = "cancelled"
|
||
)
|
||
|
||
// TaskType 任务类型(与 beacon 端协商,避免硬编码字符串)
|
||
type TaskType string
|
||
|
||
const (
|
||
// 通用任务
|
||
TaskTypeExec TaskType = "exec" // 执行任意命令(shell -c)
|
||
TaskTypeShell TaskType = "shell" // 交互式命令(保持 cwd)
|
||
TaskTypePwd TaskType = "pwd" // 当前目录
|
||
TaskTypeCd TaskType = "cd" // 切目录
|
||
TaskTypeLs TaskType = "ls" // 列目录
|
||
TaskTypePs TaskType = "ps" // 列进程
|
||
TaskTypeKillProc TaskType = "kill_proc" // 杀进程
|
||
TaskTypeUpload TaskType = "upload" // 推文件到目标
|
||
TaskTypeDownload TaskType = "download" // 拉文件回本机
|
||
TaskTypeScreenshot TaskType = "screenshot" // 截图
|
||
TaskTypeSleep TaskType = "sleep" // 调整心跳节律
|
||
TaskTypeExit TaskType = "exit" // 让 implant 退出(不会自删二进制)
|
||
TaskTypeSelfDelete TaskType = "self_delete" // 退出 + 自删二进制(持久化清理)
|
||
// 高级任务
|
||
TaskTypePortFwd TaskType = "port_fwd"
|
||
TaskTypeSocksStart TaskType = "socks_start"
|
||
TaskTypeSocksStop TaskType = "socks_stop"
|
||
TaskTypeLoadAssembly TaskType = "load_assembly"
|
||
TaskTypePersist TaskType = "persist"
|
||
)
|
||
|
||
// AllTaskTypes 全部 task_type,便于工具 schema 列出 enum
|
||
func AllTaskTypes() []TaskType {
|
||
return []TaskType{
|
||
TaskTypeExec, TaskTypeShell,
|
||
TaskTypePwd, TaskTypeCd, TaskTypeLs, TaskTypePs, TaskTypeKillProc,
|
||
TaskTypeUpload, TaskTypeDownload, TaskTypeScreenshot,
|
||
TaskTypeSleep, TaskTypeExit, TaskTypeSelfDelete,
|
||
TaskTypePortFwd, TaskTypeSocksStart, TaskTypeSocksStop, TaskTypeLoadAssembly,
|
||
TaskTypePersist,
|
||
}
|
||
}
|
||
|
||
// IsDangerousTaskType 标记需要 HITL 二次确认的任务类型;
|
||
// 与 internal/handler/hitl.go 现有的 tool_whitelist 概念呼应:白名单外 → 走审批。
|
||
func IsDangerousTaskType(t TaskType) bool {
|
||
switch t {
|
||
case TaskTypeKillProc, TaskTypeUpload, TaskTypeSelfDelete,
|
||
TaskTypePortFwd, TaskTypeSocksStart, TaskTypeLoadAssembly, TaskTypePersist:
|
||
return true
|
||
}
|
||
return false
|
||
}
|
||
|
||
// ListenerConfig 解码后的监听器运行配置(来自 c2_listeners.config_json)
|
||
type ListenerConfig struct {
|
||
// HTTP/HTTPS Beacon 公共字段
|
||
BeaconCheckInPath string `json:"beacon_check_in_path,omitempty"` // 默认 "/check_in"
|
||
BeaconTasksPath string `json:"beacon_tasks_path,omitempty"` // 默认 "/tasks"
|
||
BeaconResultPath string `json:"beacon_result_path,omitempty"` // 默认 "/result"
|
||
BeaconUploadPath string `json:"beacon_upload_path,omitempty"` // 默认 "/upload"
|
||
BeaconFilePath string `json:"beacon_file_path,omitempty"` // 默认 "/file/"
|
||
// HTTPS 专属
|
||
TLSCertPath string `json:"tls_cert_path,omitempty"`
|
||
TLSKeyPath string `json:"tls_key_path,omitempty"`
|
||
TLSAutoSelfSign bool `json:"tls_auto_self_sign,omitempty"` // true:找不到证书时自动生成自签
|
||
// 客户端默认参数(写到 c2_sessions 初值,beacon 也可在 check-in 时覆写)
|
||
DefaultSleep int `json:"default_sleep,omitempty"` // 秒,默认 5
|
||
DefaultJitter int `json:"default_jitter,omitempty"` // 0-100,默认 0
|
||
// OPSEC:可选命令黑名单(正则)
|
||
CommandDenyRegex []string `json:"command_deny_regex,omitempty"`
|
||
// 任务并发上限(每个会话同时下发的最大任务数,0 表示不限制)
|
||
MaxConcurrentTasks int `json:"max_concurrent_tasks,omitempty"`
|
||
// CallbackHost 植入端/Payload 使用的回连主机名(可选);与 bind_host 分离,便于 NAT/ECS 等场景
|
||
CallbackHost string `json:"callback_host,omitempty"`
|
||
}
|
||
|
||
// ApplyDefaults 对未填字段填默认值;调用方负责持久化时序列化新值
|
||
func (c *ListenerConfig) ApplyDefaults() {
|
||
if strings.TrimSpace(c.BeaconCheckInPath) == "" {
|
||
c.BeaconCheckInPath = "/check_in"
|
||
}
|
||
if strings.TrimSpace(c.BeaconTasksPath) == "" {
|
||
c.BeaconTasksPath = "/tasks"
|
||
}
|
||
if strings.TrimSpace(c.BeaconResultPath) == "" {
|
||
c.BeaconResultPath = "/result"
|
||
}
|
||
if strings.TrimSpace(c.BeaconUploadPath) == "" {
|
||
c.BeaconUploadPath = "/upload"
|
||
}
|
||
if strings.TrimSpace(c.BeaconFilePath) == "" {
|
||
c.BeaconFilePath = "/file/"
|
||
}
|
||
if c.DefaultSleep <= 0 {
|
||
c.DefaultSleep = 5
|
||
}
|
||
if c.DefaultJitter < 0 {
|
||
c.DefaultJitter = 0
|
||
}
|
||
if c.DefaultJitter > 100 {
|
||
c.DefaultJitter = 100
|
||
}
|
||
}
|
||
|
||
// ImplantCheckInRequest beacon → 服务端的注册/心跳请求体(已解密后的明文)
|
||
type ImplantCheckInRequest struct {
|
||
ImplantUUID string `json:"uuid"`
|
||
Hostname string `json:"hostname"`
|
||
Username string `json:"username"`
|
||
OS string `json:"os"`
|
||
Arch string `json:"arch"`
|
||
PID int `json:"pid"`
|
||
ProcessName string `json:"process_name"`
|
||
IsAdmin bool `json:"is_admin"`
|
||
InternalIP string `json:"internal_ip"`
|
||
UserAgent string `json:"user_agent,omitempty"`
|
||
SleepSeconds int `json:"sleep_seconds"`
|
||
JitterPercent int `json:"jitter_percent"`
|
||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||
}
|
||
|
||
// ImplantCheckInResponse 服务端回执
|
||
type ImplantCheckInResponse struct {
|
||
SessionID string `json:"session_id"`
|
||
NextSleep int `json:"next_sleep"`
|
||
NextJitter int `json:"next_jitter"`
|
||
HasTasks bool `json:"has_tasks"`
|
||
ServerTime int64 `json:"server_time"`
|
||
}
|
||
|
||
// TaskEnvelope 服务端 → beacon 的任务派发载体
|
||
type TaskEnvelope struct {
|
||
TaskID string `json:"task_id"`
|
||
TaskType string `json:"task_type"`
|
||
Payload map[string]interface{} `json:"payload"`
|
||
}
|
||
|
||
// TaskResultReport beacon → 服务端的任务结果回传
|
||
type TaskResultReport struct {
|
||
TaskID string `json:"task_id"`
|
||
Success bool `json:"success"`
|
||
Output string `json:"output,omitempty"`
|
||
Error string `json:"error,omitempty"`
|
||
BlobBase64 string `json:"blob_b64,omitempty"` // 如截图二进制
|
||
BlobSuffix string `json:"blob_suffix,omitempty"` // 如 ".png"
|
||
StartedAt int64 `json:"started_at"`
|
||
EndedAt int64 `json:"ended_at"`
|
||
}
|
||
|
||
// CommonError C2 模块统一错误类型,便于 handler 层映射 HTTP 状态码
|
||
type CommonError struct {
|
||
Code string
|
||
Message string
|
||
HTTP int
|
||
}
|
||
|
||
func (e *CommonError) Error() string {
|
||
if e == nil {
|
||
return ""
|
||
}
|
||
return e.Message
|
||
}
|
||
|
||
// Sentinel errors,便于 errors.Is 比较
|
||
var (
|
||
ErrListenerNotFound = &CommonError{Code: "listener_not_found", Message: "监听器不存在", HTTP: 404}
|
||
ErrSessionNotFound = &CommonError{Code: "session_not_found", Message: "会话不存在", HTTP: 404}
|
||
ErrTaskNotFound = &CommonError{Code: "task_not_found", Message: "任务不存在", HTTP: 404}
|
||
ErrProfileNotFound = &CommonError{Code: "profile_not_found", Message: "Profile 不存在", HTTP: 404}
|
||
ErrInvalidInput = &CommonError{Code: "invalid_input", Message: "参数非法", HTTP: 400}
|
||
ErrAuthFailed = &CommonError{Code: "auth_failed", Message: "鉴权失败", HTTP: 401}
|
||
ErrPortInUse = &CommonError{Code: "port_in_use", Message: "端口已被占用", HTTP: 409}
|
||
ErrListenerRunning = &CommonError{Code: "listener_running", Message: "监听器已在运行", HTTP: 409}
|
||
ErrListenerStopped = &CommonError{Code: "listener_stopped", Message: "监听器未运行", HTTP: 409}
|
||
ErrUnsupportedType = &CommonError{Code: "unsupported_type", Message: "不支持的监听器类型", HTTP: 400}
|
||
)
|
||
|
||
// SafeBindPort 校验端口范围
|
||
func SafeBindPort(port int) error {
|
||
if port < 1 || port > 65535 {
|
||
return errors.New("port must be in 1..65535")
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// NowUnixMillis 统一时间戳工具
|
||
func NowUnixMillis() int64 {
|
||
return time.Now().UnixNano() / int64(time.Millisecond)
|
||
}
|