☰
用 Python 从零构建 C2 Beacon 与命令控制服务器:WebSocket、XOR 编码与操作员面板实战解析
2026/9/29 2:15:25 网站建设 项目流程

【免费下载链接】Cybersecurity-Projects

Building 70 Projects ranging from beginner to advanced so anyone can — learn from, build upon, use as a reference, or even copy directly. Gamified Cybersecurity learning 👇

项目地址:https://gitcode.com/gh_mirrors/cy/Cybersecurity-Projects
点击查看免费下载

本篇技术指南以c2-beacon项目的核心概览文档为主线,完整讲解一个教育级 C2(Command and Control)信标与服务端体系:信标如何通过 WebSocket 回连服务器、流量如何经 XOR + Base64 编码、服务器如何排队并下发任务、操作员如何通过终端式面板实时控制任意信标。读完本文,你将掌握真实 C2 框架(如 Cobalt Strike、Sliver、Mythic)背后的架构模式,并具备直接在本仓库中动手运行、调试和扩展的能力。

项目定位:这是一套教育级 C2 信标与服务器

C2 Beacon / Server 是一套教育用途的命令控制信标与服务器实现,用于演示真实 C2 框架(如 Cobalt Strike、Sliver、Mythic)在底层是如何运作的。它由三个角色构成:

  • 信标(Beacon / Implant):运行在被控目标上,通过 WebSocket 主动回连服务器,接收任务、执行命令、回传结果;
  • 服务器(Server):维护信标注册表、任务队列,并向前端操作员广播事件;
  • 操作员面板(Operator Dashboard):基于 React 的实时仪表盘,操作员可以选中某个信标,在终端式 UI 中下发命令并查看输出。

三条核心特性贯穿整个项目:信标与服务器之间的通信使用XOR + Base64 编码;内置10 个命令并逐一映射到 MITRE ATT&CK 技术;具备任务排队系统与实时操作员面板(terminal-style UI)。对应概览文档为 PROJECTS/beginner/c2-beacon/learn/00-OVERVIEW.md。

需要特别说明的是,本项目是刻意简化的教学实现:它使用 XOR(混淆而非加密)、明文 WebSocket、单文件信标脚本,不包含进程注入、AMSI 绕过、域前置等规避技术。这正是它的价值所在——剥离所有规避复杂度,让学习者专注理解 C2 架构本身。

为什么理解 C2 架构至关重要

现实威胁背景

C2 是被攻击者在渗透中后期建立持久交互通道的核心能力。几个广为人知的案例说明了它的普遍性:

  • Cobalt Strike 在入侵响应中的高频出现:近 70% 的应急响应工作中涉及 Cobalt Strike,它是最常见的 C2 框架。防御者需要理解其信标如何通信、任务如何排队、操作员如何控制植入体——没有这种理解,应急响应就只能是猜测。
  • SolarWinds SUNBURST(2020):使用自定义 C2 协议隧道在 HTTP 之上,植入体伪装成合法的 Orion 软件更新。信标收集系统信息后,休眠最长两周才进行首次回连,之后通过伪装成正常遥测的 DNS 与 HTTP 响应接收任务。其精巧之处在于协议设计,而非漏洞利用本身。
  • APT29(Cozy Bear):被记录使用带抖动(jittered)休眠间隔、域前置和加密通道的自定义 C2 植入体。抖动让回调模式看起来不规则而非机械,从而加大基于网络的检测难度。

本项目如何帮助你建立心智模型

C2 阶段在 Lockheed Martin 网络杀伤链(Cyber Kill Chain)中位列第 6/7 步,MITRE ATT&CK 为它单列了整个战术类别(TA0011)。如果你是蓝队成员、应急响应人员或威胁情报分析师,理解 C2 架构是基础能力——你无法为不理解的东西编写检测规则。本项目的信标实现了与 APT29 相同的抖动休眠技术,你可以直接看到该技术是如何工作的,以及为什么固定间隔的信标极易被指纹识别。

从零构建一个简化但完整可运行的教育版,能让你获得阅读报告无法替代的心智模型。

你将学到什么

安全概念:

  • C2 架构与 Beacon/Server 模型;
  • MITRE ATT&CK 技术映射(T1059 命令执行、T1082 系统发现、T1057 进程发现、T1105 工具传输进入、T1113 屏幕捕获、T1056 输入捕获、T1053 持久化、T1029 计划传输);
  • 基于 XOR 与 Base64 的协议编码;
  • 通过 cron 实现的持久化技术;
  • 检测策略与防御者识别 C2 流量的方法。

技术技能:

  • 连接两端(信标与服务器)的 WebSocket 编程;
  • 异步 Python(asyncio),包括子进程执行与并发任务处理;
  • React 实时 UI 更新、Zustand 状态管理与 Zod 模式校验;
  • Docker Compose 编排:Nginx 反向代理、健康检查与多服务网络。

工具链:FastAPI(服务器)、aiosqlite(数据库)、psutil(系统枚举)、websockets(信标传输层)、Vite(前端构建)、Zod(运行时类型校验)、Pydantic(后端数据建模)。

环境准备

必需项

  • Python 3.13+
  • Node.js 22+
  • Docker 与 Docker Compose
  • 对网络、HTTP 及客户端-服务器通信有基本了解

必需工具

  • uv:Python 包管理工具(本项目约定使用 uv 而非 pip)。安装:curl -LsSf https://astral.sh/uv/install.sh | sh
  • pnpm:Node 包管理工具(约定使用 pnpm 而非 npm)。安装:corepack enable && corepack prepare pnpm@latest --activate
  • just:命令运行器。安装:cargo install just或brew install just
  • Docker Compose(Docker Desktop 自带,或单独安装插件)

有帮助但非必需

  • 熟悉 WebSocket 的连接/发送/接收/关闭生命周期;
  • 有 Python 或 JavaScript 的 async/await 经验;
  • 接触过 React(面板本身并不复杂,但有 React 基础更好)。

快速开始

第一步:启动三服务开发栈

git clone https://github.com/CarterPerez-dev/Cybersecurity-Projects.git cd PROJECTS/beginner/c2-beacon docker compose -f dev.compose.yml up -d

浏览器访问 http://localhost:47430,应能看到操作员面板,此时信标表格为空。开发栈由三个服务组成(见 dev.compose.yml):

  • nginx(nginx:1.27-alpine):统一入口,监听${NGINX_HOST_PORT:-47430}:80,通过 infra/nginx/nginx.conf 中的map $http_upgrade $connection_upgrade指令实现 WebSocket 升级代理,并配置keepalive、限流(limit_req_zone ... rate=10r/s)等参数;
  • backend(FastAPI):监听${BACKEND_HOST_PORT:-47431}:8000,启用开发模式(RELOAD=true),并通过 healthcheck 定时请求/health确保健康后才接受流量;
  • frontend(Vite HMR):监听${FRONTEND_HOST_PORT:-47432}:5173,注入VITE_API_URL(默认/api)与VITE_APP_TITLE环境变量。

后端健康检查在 compose 中被声明为depends_on条件(condition: service_healthy),nginx 只在后端健康后才启动,这正是文档中"三个服务都需要健康"这一要求的来源。

第二步:启动一个信标

在第二个终端中:

cd PROJECTS/beginner/c2-beacon just beacon

信标输出类似:

2026-02-14 10:32:01 INFO: Connecting to ws://localhost:47430/api/ws/beacon 2026-02-14 10:32:01 INFO: Registered as 3a7f1c29-8b42-4e91-a6d3-9f0e5c8d2b17

just beacon这一命令(定义于 justfile)实际执行的是:

cd beacon && C2_SERVER_URL="ws://localhost:${NGINX_HOST_PORT}/api/ws/beacon" C2_XOR_KEY="${XOR_KEY}" uv run python beacon.py

即通过环境变量把信标指向 nginx 代理的 WebSocket 端点,并传入与服务器一致的 XOR 密钥。注意信标不会随 Docker 自动启动,必须手动运行。

第三步:下发命令

回到浏览器,信标应出现在面板表格中,显示其主机名、操作系统、用户名与 IP。点击该行进入会话,在终端输入框输入shell whoami并回车——命令被发送到信标、执行,输出出现在终端 UI 中。

再尝试几个命令:

sysinfo proclist shell ls -la /tmp

每个命令都走完整管道:操作员面板通过 WebSocket 发送 JSON 到服务器 → 服务器排队任务并(以 XOR+Base64 编码)转发给信标 → 信标执行命令 → 编码结果回传 → 服务器广播给操作员面板渲染显示。

项目结构解剖

概览文档给出了完整目录树,这里结合源码逐一说明每个模块的职责:

c2-beacon/ ├── backend/ │ └── app/ │ ├── core/ │ │ ├── encoding.py XOR + Base64 编解码函数 │ │ ├── models.py Pydantic 模型:BeaconRecord、TaskRecord、TaskResult │ │ └── protocol.py 消息信封:带类型校验的 pack/unpack │ ├── beacon/ │ │ ├── registry.py 内存信标注册表 + aiosqlite 持久化 │ │ ├── router.py 信标连接的 WebSocket 端点 │ │ └── tasking.py 任务队列:创建、分配、完成、检索 │ ├── ops/ │ │ ├── manager.py 操作员 WebSocket 连接管理 + 广播 │ │ └── router.py 操作员 WebSocket + REST 端点 │ ├── config.py Pydantic Settings:XOR 密钥、端口、CORS、DB 路径 │ └── database.py aiosqlite 初始化与建表 ├── beacon/ │ └── beacon.py 植入体(约 514 行单文件,10 个命令处理器) ├── frontend/ │ └── src/ │ ├── core/ │ │ ├── ws.ts Zustand store + useOperatorSocket hook │ │ └── types.ts 所有 WebSocket 消息类型的 Zod schemas │ └── pages/ │ ├── dashboard/ 带实时状态更新的信标表格 │ └── session/ 带命令输入与结果展示的终端 UI ├── infra/ │ ├── docker/ dev(热重载)与 prod 的 Dockerfile │ └── nginx/ 反向代理配置(WebSocket 代理) ├── dev.compose.yml 3 服务开发栈:nginx、backend、frontend ├── compose.yml 生产环境 compose ├── justfile 命令运行器:just beacon、just dev-up 等 └── learn/ 学习文档目录(本指南所在)

核心数据模型集中在 backend/app/core/models.py:

  • CommandType:枚举 10 个支持的命令(shell、sysinfo、proclist、upload、download、screenshot、keylog_start、keylog_stop、persist、sleep);
  • BeaconMeta/BeaconRecord:信标注册元数据(hostname、os、username、pid、internal_ip、arch)与含first_seen/last_seen的完整记录;
  • TaskRequest/TaskRecord/TaskResult:从操作员提交任务到信标返回结果的完整生命周期类型。

工作原理详解

双通道架构

┌──────────┐ WebSocket ┌──────────┐ WebSocket ┌──────────┐ │ Beacon │ ──XOR+Base64──> │ Server │ <──JSON──────── │ Operator │ │ (target) │ <──XOR+Base64── │ (FastAPI)│ ──JSON────────> │ (React) │ └──────────┘ └──────────┘ └──────────┘

两条独立的 WebSocket 通道将关注点分离:

  • 信标通道(/api/ws/beacon):使用 XOR+Base64 编码,模拟加密的 C2 通信;
  • 操作员通道(/api/ws/operator):使用明文 JSON,属于受信的内部通信。

服务端入口实现位于 backend/app/beacon/router.py 与 backend/app/ops/router.py。

信标连接与注册

信标(beacon/beacon.py)通过 WebSocket 连接到服务器/ws/beacon。连接建立后立即发送REGISTER消息,携带系统信息:hostname、OS、username、PID、内网 IP 与架构(采集逻辑见collect_system_info,约 beacon.py,其中内网 IP 通过"UDP socket 连接技巧"获取,失败时回退为127.0.0.1)。

服务端在 backend/app/beacon/router.py 的/beacon端点中校验 REGISTER 握手:如果首条消息不是 REGISTER,则关闭连接(code 4001)。注册信息写入BeaconRegistry(内存 dict 键为 beacon_id + SQLite 持久化),并广播beacon_connected事件给所有在线操作员。

BeaconRegistry(backend/app/beacon/registry.py)的设计是内存 + 磁盘双存储:register/unregister同时更新内存连接表与 SQLitebeacons表(INSERT ... ON CONFLICT(id) DO UPDATE实现 upsert);is_active/get_connection只读内存以保证实时性;get_all/get_one查询数据库以支持信标离线后的历史查看。

心跳与抖动休眠

注册完成后,信标进入主循环:周期性地发送HEARTBEAT消息,并使用抖动(jittered)定时——基础间隔 + 随机抖动百分比——保持连接存活并更新服务器上的 "last seen" 时间戳。两次心跳之间等待来自服务器的 TASK 消息。

抖动休眠的实现:

async def jittered_sleep() -> float: jitter = config.sleep_interval * config.jitter_percent return config.sleep_interval + random.uniform(-jitter, jitter)

(见 beacon.py)默认 3 秒间隔 + 30% 抖动意味着实际休眠在 2.1 到 3.9 秒之间随机波动,使回连时序显得"不规则"。这正是 APT29 等组织使用抖动的原因:固定间隔信标是网络监控可以轻易指纹化的机械模式。作为对照,Cobalt Strike 默认 60 秒休眠、0% 抖动,有经验的操作员会立刻调高(长期运营通常使用 300 秒 + 30%–50% 抖动)。权衡点在于响应速度与隐蔽性:短休眠响应快但易暴露,长休眠加高抖动更难检测但命令执行可能延迟数分钟。

每个心跳会调用registry.update_last_seen(registry.py)更新数据库中的last_seen时间戳,面板据此实时展示哪些信标正在活跃回连、哪些已经失联。心跳循环实现见 beacon.py。

断线重连:指数退避

网络不可靠:服务器重启、防火墙重置连接、网络路径变化。信标采用指数退避策略优雅处理:

Attempt 1: wait 2 seconds Attempt 2: wait 4 seconds Attempt 3: wait 8 seconds Attempt 4: wait 16 seconds ...持续翻倍... Attempt N: wait up to 300 seconds(5 分钟上限)

实现见 beacon.py:连接成功后backoff重置为基数 2 秒;失败后backoff = min(backoff * 2, config.reconnect_max),上限 300 秒防止无限增长。捕获的异常类型包括ConnectionRefusedError、websockets.exceptions.ConnectionClosed与OSError。指数退避的意义在于:如果服务器宕机且同时有 50 个信标重连,全部 2 秒一次地锤击服务器会产生大量网络噪声、形似 DDoS;退避把重连尝试在时间上摊开。

任务队列与结果回传

操作员在面板终端输入命令后,前端通过操作员 WebSocket 发送 JSON 消息到服务器。ops/router.py的/operator端点收到submit_task消息后创建TaskRecord(id 为uuid4,command 经CommandType(...)强类型校验),调用task_manager.submit持久化并入队,然后向操作员回发task_submitted确认。

TaskManager(backend/app/beacon/tasking.py)维护每个信标一个 asyncio.Queue:

  • submit:写入 SQLitetasks表 + 入队;
  • get_next:阻塞等待直到有可用任务(供服务端向信标推送);
  • store_result:持久化结果并把任务状态置为completed;
  • get_history:LEFT JOIN 任务与结果,返回某信标的完整历史。

在beacon/router.py中,每个已注册信标并发运行两个协程(asyncio.create_task):_send_tasks从队列取任务并编码发送给信标;_receive_messages处理信标回传的 RESULT(持久化 + 广播task_result)与 HEARTBEAT(更新 last_seen + 广播)。信标端收到 TASK 消息后,通过dispatch(beacon.py)路由到对应 handler,执行完毕后以 RESULT 消息回传。

信标内部的 10 个命令处理器全部定义在 beacon/beacon.py 的COMMAND_HANDLERS字典中:

命令处理器实现说明
shellhandle_shell通过asyncio.create_subprocess_shell执行命令,捕获 stdout/stderr
sysinfohandle_sysinfo基于 psutil 采集 CPU、内存、磁盘分区、网卡等详细信息
proclisthandle_proclistpsutil.process_iter枚举进程(PID、名称、用户,最多 100 个)
uploadhandle_upload接收 JSON(文件名 + base64 内容)并写入/tmp/
downloadhandle_download读取文件、base64 编码后经 C2 通道回传
screenshothandle_screenshot用mss截取全屏并返回 base64 PNG
keylog_start/keylog_stophandle_keylog_start/stop用pynput后台线程钩取键盘输入并缓冲
persisthandle_persist追加@rebootcron 条目实现 Linux 持久化
sleephandle_sleep运行时修改sleep_interval与jitter_percent

协议编码:XOR + Base64

XOR 原理。XOR(异或)是最简单的可逆二进制运算:相异为 1、相同为 0。核心性质是同一密钥应用两次即还原:

data XOR key = encoded encoded XOR key = data

本项目在 backend/app/core/encoding.py 中实现:

def xor_bytes(data: bytes, key: bytes) -> bytes: return bytes(b ^ key[i % len(key)] for i, b in enumerate(data)) def encode(payload: str, key: str) -> str: raw = payload.encode("utf-8") xored = xor_bytes(raw, key.encode("utf-8")) return base64.b64encode(xored).decode("ascii") def decode(encoded: str, key: str) -> str: xored = base64.b64decode(encoded) raw = xor_bytes(xored, key.encode("utf-8")) return raw.decode("utf-8")

i % len(key)使短密钥循环重复(如密钥 "abc" 处理 10 字节数据时按 a,b,c 循环 4 次),这与经典维吉尼亚密码(Vigenère)同构,只是作用在比特上而非字母上。

为什么 XOR 单独很弱。两个主要问题:

  1. 已知明文攻击:由于协议消息总是以{"type":开头的 JSON,攻击者截获编码输出后,用已知明文 XOR 密文即可恢复密钥,进而解码所有历史与未来消息;
  2. 频率分析:短循环密钥会让明文统计特征泄漏。例如英语文本中 "e" 出现约 13%,若密钥每 32 字节循环,可把密文分成 32 个流、对每个流独立做频率分析。

为什么仍要 XOR + Base64 组合。三者各司其职:

  • XOR 提供基础混淆:不是真加密,但至少协议消息不会以可读 JSON 形式裸露在线路上,字符串匹配型 IDS 规则一眼看不到{"type":"TASK","payload":{"command":"shell"}};
  • Base64 让二进制安全地走文本传输:XOR 后是任意字节(可能含空字节等破坏文本协议的取值),Base64 将其转换为安全 ASCII 字母表(A-Z、a-z、0-9、+、/)。WebSocket 文本帧要求合法文本,没有 Base64 就得改用二进制帧,徒增复杂度;
  • 真实 C2 框架使用真正的加密:Cobalt Strike 用 AES-256-CBC,Sliver 用 mTLS,Brute Ratel 用 RC4 与 AES 组合。本项目用 XOR 是为了教学——先理解混淆/加密的概念骨架,再理解密钥交换、初始化向量与密码模式。

编码流水线(发送方向):Plaintext JSON → UTF-8 bytes → XOR with key → Base64 → WebSocket text frame。

解码流水线(接收方向):WebSocket text frame → Base64 decode → XOR with key → UTF-8 string → JSON parse。

协议层 backend/app/core/protocol.py 在其上叠加了 Pydantic 校验:MessageType枚举五种协议状态(REGISTER、HEARTBEAT、TASK、RESULT、ERROR);pack把Message序列化为 JSON 再编码;unpack解码、解析并校验,任一步失败(坏 Base64、XOR 产生非法 UTF-8、JSON 畸形、Pydantic 校验失败)都会抛出ValueError。服务端 config.py 中XOR_KEY的默认值是c2-beacon-default-key-change-me(min_length = 8校验),并明确建议替换。

操作员通道与事件广播

OpsManager(backend/app/ops/manager.py)维护活跃操作员 WebSocket 连接集合,broadcast把事件 dict 序列化为 JSON 并推送给所有操作员,发送失败(ConnectionError/RuntimeError)的连接会被静默清理。它会广播的事件包括:

  • beacon_connected/beacon_disconnected:信标上下线;
  • heartbeat:信标心跳;
  • task_result:任务执行结果。

ops/router.py还提供三条 REST 端点:GET /beacons(列出全部信标 + 活跃状态)、GET /beacons/{id}(单信标查询,404 兜底)、GET /beacons/{id}/tasks(任务历史)。操作员 WebSocket 端点连接时会先推送一次beacon_list快照。

信标配置参数

信标(BeaconConfig,beacon.py)通过环境变量可调:

环境变量默认值说明
C2_SERVER_URLws://localhost:8000/ws/beacon服务器 WebSocket 地址
C2_XOR_KEYc2-beacon-default-key-change-me与服务器一致的 XOR 密钥
C2_SLEEP3.0心跳/任务轮询基础间隔(秒)
C2_JITTER0.3抖动百分比(0–1 之间的小数)

服务器端(Settings,backend/app/config.py,从.env与系统环境变量加载)的可配项包括HOST(默认0.0.0.0)、PORT(默认 8000)、DATABASE_PATH(默认data/c2.db)、XOR_KEY、CORS_ORIGINS(默认包含http://localhost、http://localhost:47430、http://localhost:47432)、LOG_LEVEL、ENVIRONMENT与DEBUG。compose 层则通过${NGINX_HOST_PORT:-47430}、${BACKEND_HOST_PORT:-47431}、${FRONTEND_HOST_PORT:-47432}、${APP_NAME:-c2-beacon}等变量控制端口与服务名。

常见问题排查

浏览器控制台报 "WebSocket closed before established":这是 React StrictMode 开发模式的二次挂载(double-mount)导致的:第一个 WebSocket 连上后立即断开,第二个连接保持。属无害现象,开发模式下每次刷新页面都会出现。

信标无法连接服务器:确认 Docker 容器确实在运行,用just dev-ps检查。信标经 nginx 的 47430 端口接入,因此 nginx、backend、frontend 三个服务都必须健康。若后端显示 unhealthy,用just dev-logs backend查看其日志。

面板显示 "No beacons connected":信标不会随 Docker 自动启动,需在第二个终端运行just beacon。信标应在数秒内完成注册并出现在面板表格中。

命令返回空输出:部分命令有环境依赖:

  • screenshot需要显示服务器(在无头环境或 Docker 容器中会失败);
  • keylog_start需要 pynput,且要求 X11 或 Wayland 会话;
  • persist仅在 Linux 上可用(代码中显式检查platform.system() != "Linux");
  • shell在所有平台上均可工作。

后续学习路径

本文对应learn目录中的第 00 篇概览。后续文档构成完整的渐进学习链条:

  • 01 - Concepts:C2 理论、每个命令的 MITRE ATT&CK 映射、防御者如何检测信标(网络签名、行为分析、端点工件、金字塔之痛 Pyramid of Pain);
  • 02 - Architecture:协议设计、数据流、编码决策及其原因;
  • 03 - Implementation:从信标植入体到 React 面板的每个组件代码走读;
  • 04 - Challenges:扩展与进阶练习(AES 加密、DNS 隧道、规避技术)。

配套的仓库测试(backend/tests)覆盖了编码(test_encoding.py)、协议往返(test_protocol.py)、注册表(test_registry.py)、任务生命周期(test_tasking.py)与整体应用(test_app.py),是验证你理解的绝佳素材。

【免费下载链接】Cybersecurity-Projects

Building 70 Projects ranging from beginner to advanced so anyone can — learn from, build upon, use as a reference, or even copy directly. Gamified Cybersecurity learning 👇

项目地址:https://gitcode.com/gh_mirrors/cy/Cybersecurity-Projects
点击查看免费下载
上一篇:探索经典,重燃激情:PCSX-Redux——PlayStation 1模拟器的新生
下一篇:ngx-quill自定义模块开发:从零构建图片大小调整功能

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询