腾讯云第二节黑客松自动化渗透赛开发思路文档
ATK 系统架构与开发文档
第二届腾讯云黑客松 · 智能渗透挑战赛
主语言: Go 1.25 · 依赖: AstrBot + Kali 执行环境
Intro
先总结一下,我这边比赛用minimax+gpt-5.4,个人预算严重不足就没用claude了,这一套搭配开局简单题目和赛前测试题目基本一分钟不到就解出了,后面就卡住了,再后面由于minimax tokenplan的额度限制以及一些原因就没接着打了。整场比赛看下来其实最大的决定因素就是模型能力,也就是说如果用cluade opus搭配网上的各种开源项目,其实能取得的成绩也是不错的。
在架构设计上,通过subagent来实现各类角色已经是既定的主流方案,在长任务场景下,几乎所有的架构都需要一个监督者的角色,这个角色作为独立的第三方来监督其他各agent是否存在思考过度、思维漂移等现象,并且我还引入了summary_agent这个角色,进行复盘,提取当前轮次有效信息做上下文持久化,再将持久化信息传入下一轮中。agent的通信我也采用了一种自定义的Card格式进行传输,这一点在第一届的思路中也有提到。
此外,gpt-5.4也存在一些问题(在我写这篇文章时5.5已经发布了,效果提升很不错),比如上下文腐烂速度相较于其他模型来说非常快,在上下文占用超百分之五十时,模型的性能就会大幅下降,并且5.4还存在一个很致命的点就是过度思考有些严重,并且在我的架构中,负责信息收集的agent把信息传递给5.4时,由于recon侦测到的信息很复杂,它会在众多路径中陷入一个不可行的路径越陷愈深,因此后面我设计了一套评分标准,根据侦测到信息的置信度对每个攻击路径进行打分,优先对分数最高的路径进行尝试,并且在尝试次数达到规定次数后就放弃该路径,但其实效果不是很理想。
一开始设计思路的时候,跟朋友一起聊天,想到了一个好玩的点,关于ai的上下文问题,直接用QQ群聊来作为各个subagent的上下文,我新建了很多QQ群作为不同的分工,这样就可以根据角色来隔绝上下文,并且能够将上下文在qq群中持久化,后面这个也设计成功了,但其实我思考了一会,发现根本就没必要,持久化存储使用本地存储根据目录分割就可以了,前面的尝试可能更多是一个玩着试试的想法。
然后大概说一下我的设计思路吧,我在设计项目之前参考了第一届的几个项目,比较核心的观点就是less is more,这个说法成立的前提是模型的能力够强,准确来说是当模型能力够强时,过多的干扰只会扰乱模型的解决问题的思路。用我的项目来说明,因为我用的是minimax,所以我设计了大量的core agent和swarm agent分工,并针对不同的漏洞类型进行专攻,但如果将这一结构套用在opus上,一定会导致opus的效能大大降低。因此对于后续的迭代优化,我的建议就是不要把agent的角色划分的太细,尤其是对于能力强的模型越少的过度干扰才能发挥真正的作用,要做的只是规范与监督,也就是所谓的harness engine。
后面的就是整个项目的设计思路,对于比赛中这种flag的提交,我是通过监听sse的输出,识别到flag的格式就提取出来进行提交,关于为什么没有代码开源这件事,由于某些不可抗因素,导致代码全部丢失,最后开赛前一天我剩下的只有赛方服务器上的golang编译产物,所以只剩下思路和这篇开发文档了。
目录
- 系统定位与总体架构
- 组件分层
- 核心数据模型
- Agent 体系
- 完整数据流
- Channel 路由系统
- HTTP API 参考
- 配置参考
- 知识系统
- 持久化与存储布局
- Go 包结构
- 开发规范
- 测试策略
- 部署说明
1. 系统定位与总体架构
ATK 是一个多 Agent 并发智能渗透测试系统。系统由三个独立进程组成:
┌──────────────────────────────────────────────────────────────────┐
│ AstrBot (端口 6185) │
│ LLM 编排平台,管理 14 个 persona,负责思考/推理/委派 │
│ 接受 /run /next /summary /critic 等前缀命令 │
└──────────────────┬───────────────────────────────────────────────┘
│ HTTP POST /api/v1/chat (kickoff)
│ HTTP streaming SSE (reply)
┌──────────────────▼───────────────────────────────────────────────┐
│ atk-sidecar (端口 8090) │
│ Go HTTP 服务,负责: │
│ - 与 AstrBot 的所有通信(kickoff/recovery/swarm dispatch) │
│ - Card/Event/Channel 持久化 │
│ - 自动化调度(recovery loop、swarm dispatch、challenge 管理) │
│ - Flag 提交与比赛 API 对接 │
│ - Shell/Python 执行(通过 runner) │
│ - 知识库检索(指纹阶段可主动查询;恢复轮次注入 KNOWLEDGE_HINT) │
└──────────────────┬───────────────────────────────────────────────┘
│ run_shell / run_python (via MCP → HTTP)
┌──────────────────▼───────────────────────────────────────────────┐
│ Kali Linux 执行环境 │
│ 本地模式 (mode=local) 直接执行 shell/python 命令 │
│ Docker 模式 (mode=docker) 在容器内执行 │
└──────────────────────────────────────────────────────────────────┘
核心设计原则:
- sidecar 是哑管道 + 自动化控制器,不包含渗透测试逻辑
- 所有渗透决策在 AstrBot Agent 侧(通过 persona system prompt)
- AstrBot Agent 通过 MCP server 调用 sidecar 提供的工具(
run_shell、run_python、read_artifact、upsert_card) - sidecar 观察 card 流,自动触发 recovery/swarm/flag 提交等自动化行为
2. 组件分层
atk-sidecar 内部分层:
┌─────────────────────────────────┐
│ httpapi (HTTP 层) │ ← 21 个端点,无业务逻辑
├─────────────────────────────────┤
│ service (核心业务逻辑层) │ ← 所有自动化调度在此
│ ┌─────────────────────────────┐│
│ │ card_pipeline swarm_disp ││ ← card 处理管道 / 蜂群分发
│ │ recovery branch_ctl ││ ← 自动恢复 / 分支控制
│ │ pioneer_dispatch session_reg││ ← Pioneer 并发 / session 生命周期
│ │ challenge_manager ││ ← 多题并发管理
│ │ astrbot_postprocess ││ ← AstrBot 回复解析,提取 card
│ └─────────────────────────────┘│
├─────────────────────────────────┤
│ 基础设施包 │
│ cards channelbus events │
│ kickoff officialapi runner │
│ knowledge submissions router │
└─────────────────────────────────┘
2.1 service 包内文件职责
| 文件 | 行数 | 职责 |
|---|---|---|
service.go |
1258 | Service struct 定义、公共方法(UpsertCard、Publish、QueryCards 等)、初始化 |
astrbot_postprocess.go |
1141 | AstrBot 回复解析:提取 atk_card JSON block、heuristic card 检测、PlanIR 解析 |
branch_controller.go |
1062 | 多路径分支管理:PathCandidateCard 追踪、dominant_branch 锁定、stall 检测 |
recovery.go |
1189 | Recovery 控制器、recovery kickoff 构建、KNOWLEDGE_HINT 注入、官方 hint 收集 |
card_pipeline.go |
262 | card upsert 管道:ObserveRecovery/Branch、FlagCandidate 自动提交、SecurityMatcher 触发 |
session_registry.go |
265 | Session 生命周期(running/stop_requested/stopped/superseded/solved) |
session_control.go |
214 | session 状态变更:markSolved、stopAllForStage(flag 找到后取消同 stage 其他 session) |
swarm_dispatcher.go |
191 | HypothesisCard → 对应 vuln 专项 Agent dispatch,含 per-stage 并发上限 |
challenge_manager.go |
197 | 多题并发:轮询比赛 API,自动 start challenge,dispatch commander+pioneer |
pioneer_dispatch.go |
328 | Pioneer 独立 dispatch 逻辑,使用独立 kickoff store 和 recovery controller |
signal_extract.go |
214 | runner 输出中提取 flag(正则匹配 flag{...}),生成 FlagCandidateCard |
knowledge_zone.go |
66 | QueryKnowledge 接口,封装 knowledge.Retriever.QueryScoped |
helpers.go |
117 | 类型转换辅助(stringFromAny、stringSliceFromAny 等) |
3. 核心数据模型
3.1 Card(结构化知识单元)
所有 agent 输出的结构化信息以 Card 形式存储。Card 通过 atk_card fenced JSON block 从 AstrBot 回复中提取。
// internal/sidecar/types.go
type Card struct {
CardID string // 唯一 ID,格式: "<type>-<nanoid>"
CardType string // 见下方类型表
Stage string // challenge code(多题并发隔离用)
GroupKey string // 目标 channel key
Role string // 产出此 card 的 agent 角色
Title string
Summary string
Status string // proposed/observed/completed/halt/captured/...
Priority string // low/medium/high/critical
Confidence float64 // 0.0-1.0
Tags []string // 用于 routing 规则匹配
Payload map[string]any // 结构化内容,各 card 类型有专属字段
CreatedAt time.Time
UpdatedAt time.Time
}
Card 类型完整表:
| CardType | 生产者 | 关键 Payload 字段 | 触发的自动化行为 |
|---|---|---|---|
AssetCard |
recon_agent | url, tech_stack, interesting_params, tool_needs | → SecurityMatcher(自动假设匹配) → HypothesisCard |
HypothesisCard |
planner_agent, SecurityMatcher | vuln_type(必填), hypothesis, preconditions, validation_steps, dominant_branch | → swarm_dispatcher dispatch 对应专项 Agent |
ActionCard |
executor_agent | action_type, target, selected_tool, result, failure_level, path_id, move_id | → recovery ObserveCard |
RiskCard |
critic_agent, branchController | risk_type, failure_level (L0-L5), need_branch_replan, decision | → recovery trigger(halt 状态优先级最高) |
FlagCandidateCard |
executor/pioneer/swarm | candidate(精确 flag 字符串), method | → markSessionSolved → stopAllForStage → 自动提交比赛平台 |
GroupDigest |
summary_agent, reflector, system | facts, dead_paths, retry_ready_context, dominant_branch, required_next_moves | → recovery trigger |
EvidenceCard |
reflector | evidence_items, timeline, source_cards | 存档,发往 evidence_review channel |
PathCandidateCard |
planner_agent, branchController | path_id, dominant_branch, required_next_moves, move_ids | branchController 追踪路径状态 |
PlanIRCard |
planner_agent(经 astrbot_postprocess 解析) | goal, dominant_branch, required_next_moves, stop_conditions | branchController 锁定分支 |
BranchStateCard |
branchController(system 自动生成) | dominant_branch, lock_state, stall_state, remaining_moves | 发往 main_control |
ToolCapabilityCard |
system(runner 探测后生成) | available_tools, kali_tools | 广播给 main_control |
PathScoreCard |
branchController(内部) | scores | 内部状态管理 |
3.2 Event
type Event struct {
ID string
Type string // "card.upserted" / "system.kickoff.created" / "system.recovery.triggered" / ...
Stage string
Source string
GroupKey string
Role string
Tags []string
Status string
Impact string
Message string
CardType string
CardID string
Payload map[string]any
CreatedAt time.Time
}
Event 通过 events.Bus 发布,存储在 runtime_data/events/*.jsonl,agent 侧不直接消费 event(agent 读 channel messages)。
3.3 Kickoff Envelope
// internal/sidecar/kickoff/store.go
type Envelope struct {
ID string
Source string // "competition_api" / "automation" / "swarm_dispatcher"
Trigger string // 触发原因
TargetRole string // 目标 AstrBot persona ID
TargetChannel string // 期望输出的 channel
Sender string // "system://official_api"
CommandPrefix string // "/run"
CommandText string // 完整 kickoff 消息文本
Summary string
Stage string // challenge code
SnapshotHash string
Snapshot map[string]any // 官方 API 快照
Meta map[string]any
SessionIDOverride string // 非空时覆盖 AstrBot session ID(多题并发用)
CreatedAt time.Time
Status string
}
Session ID 命名约定:
| 场景 | Session ID 格式 |
|---|---|
| 单题 commander | atk-commander-main-v3(yaml 配置) |
| 单题 pioneer | atk-pioneer-v1(yaml 配置) |
| 多题 commander | atk-cmd-{challenge_code_lowercase} |
| 多题 pioneer | atk-pio-{challenge_code_lowercase} |
| 蜂群 agent | atk-swarm-{vuln_type}-{challenge_code_lowercase} |
3.4 PublishedMessage(Channel 消息)
// internal/sidecar/channelbus/publisher.go
type PublishedMessage struct {
ID string
ChannelKey string
Stage string // 从嵌入 card/event 自动提取(多题过滤用)
Text string
Tags []string
Card *sidecar.Card
Event *sidecar.Event
PublishedAt time.Time
}
4. Agent 体系
4.1 Core Agents(8 个)
| 角色 ID(AstrBot persona_id) | 中文定位 | 主要输出 Card | 工具权限 |
|---|---|---|---|
commander_main |
主控、调度、fast_probe | GroupDigest, HypothesisCard, RiskCard | run_shell, run_python, read_artifact |
recon_agent |
低成本侦察、攻击面画像 | AssetCard | run_shell, run_python, read_artifact |
planner_agent |
攻击路径规划、假设建立 | HypothesisCard, PathCandidateCard, PlanIRCard | read_artifact |
executor_agent |
执行批准动作、回传结果 | ActionCard, FlagCandidateCard | run_shell, run_python, read_artifact |
critic_agent |
风险审查、失败分级(L0-L5) | RiskCard | read_artifact |
summary_agent |
上下文压缩、复盘摘要 | GroupDigest | read_artifact |
reflector |
证据归档(solved)/ 经验沉淀(unsolved) | EvidenceCard, GroupDigest | read_artifact |
pioneer |
直攻型并发解题(15 步预算) | FlagCandidateCard, GroupDigest | run_shell, run_python, read_artifact |
4.2 Swarm Agents(6 个)
| 角色 ID | 专项漏洞 | 预算 | vuln_type 触发值 |
|---|---|---|---|
sqli_agent |
SQL 注入 | 10 步 | sqli |
ssrf_agent |
SSRF | 10 步 | ssrf |
auth_bypass_agent |
认证绕过/IDOR | 10 步 | auth_bypass |
file_inclusion_agent |
文件包含/路径遍历 | 10 步 | file_inclusion |
rce_agent |
RCE/命令注入 | 10 步 | rce |
xss_agent |
XSS/客户端注入 | 10 步 | xss |
蜂群 agent 与主链路并发运行,不通过 transfer_to_*,找到 flag 后 sidecar 自动取消同 stage 其他 session。
4.3 Persona 文件结构
Persona 以 persona/assembled/*.md 作为最终交付物,直接复制到 AstrBot Web。
最终交付目录:
persona/assembled/commander_main.md
persona/assembled/recon_persona.md
persona/assembled/summary_persona.md
persona/assembled/planner_persona.md
... 共 14 个完整 prompt 文件
使用方式:
# 打开对应文件并复制完整 prompt
persona/assembled/<role>.md
4.4 失败分级体系(L0-L5)
critic_agent 使用,recovery 触发优先级依据:
| 级别 | 含义 | recovery 行为 |
|---|---|---|
| L0 | 仅有原始现象,不足以下结论 | 不触发 recovery |
| L1 | 工具/命令/请求本身失败 | 触发 recovery,重试 |
| L2 | 前提条件不成立(认证、会话缺失) | 触发 recovery,补前提 |
| L3 | 外部环境干扰(WAF、限速) | 触发 recovery,绕过策略 |
| L4 | 假设本身被证伪 | 触发 recovery,换分支 |
| L5 | 整体路径设计错误 | 触发 recovery + 注入 reference layer 知识 |
5. 完整数据流
5.1 题目 Kickoff 流程(单题模式)
官方 API 变更检测(scheduler, 每 10s)
↓
official.FetchStageSnapshot()
↓ 检测到 hash 变化
dispatchKickoff(ctx, snapshot)
├── kickoff.NewEnvelope(cfg.Automation.Kickoff, trigger, snapshot)
│ CommandText: "/run [SYSTEM][competition_api] stage=X target_url=Y ..."
│ → AstrBot POST /api/v1/chat { session_id: "atk-commander-main-v3" }
│ → SSE streaming reply → astrbot_postprocess → extractReplyCards
│
└── go dispatchPioneerKickoff(snapshot) ← 并发,独立 goroutine
CommandText: "/run [SYSTEM][pioneer] stage=X target_url=Y ..."
→ AstrBot POST /api/v1/chat { session_id: "atk-pioneer-v1" }
5.2 多题并发流程(challenge_manager)
challengeManager.tick() ← 每 30s
↓
official.FetchChallengeList()
↓ 发现未解且未 active 的题目(按 difficulty 升序)
official.StartChallenge(code) → entrypoints
↓
dispatchChallenge(ch, entrypoints)
├── cmdEnv.SessionIDOverride = "atk-cmd-" + code
│ dispatchKickoffEnvelope(cmdEnv)
└── pioEnv.SessionIDOverride = "atk-pio-" + code
go dispatchPioneerEnvelope(pioEnv)
5.3 Swarm Agent 分发流程
planner_agent 输出 HypothesisCard { vuln_type: "sqli" }
↓
AstrBot reply → astrbot_postprocess → extractReplyCards
↓
upsertCard() → card_pipeline
↓
swarmDisp.MaybeDispatch(card)
├── 检查 card.CardType == "HypothesisCard"
├── 检查 vuln_type 在已知 6 种之内("unknown" 不触发)
├── 检查同 stage+vuln_type 未有 active session
├── 检查 stageCount[stage] < MaxConcurrentPerStage (默认 3)
└── go dispatch(agentRole="sqli_agent", vulnType="sqli", stage, card)
↓
swarmCfg.TargetRole = "sqli_agent"
swarmCfg.TargetChannel = "exec_feedback"
snapshot.Normalized = { stage, vuln_type, target_url, hypothesis, validation_steps, ... }
env.SessionIDOverride = "atk-swarm-sqli-" + sanitize(stage)
loadDomainSkill("sqli") → env.CommandText += "[DOMAIN_SKILL]\n..."
dispatchKickoffEnvelope(env)
另一触发路径(SecurityMatcher,专用于指纹到漏洞家族假设的自动匹配):
AssetCard 到达 card_pipeline
↓
securityMatcher.MatchBySignals(signals)
↓ 命中高置信条目
自动生成 HypothesisCard { vuln_type: "rce", source: "security/*" }
↓ 同上 swarm dispatch 路径
5.4 Recovery 流程
agent 输出 GroupDigest(status=unsolved)或 RiskCard(status=halt)
↓
upsertCard() → recovery.ObserveCard(card)
├── recoveryTriggerFromCard(card) → recoveryTrigger{ Stage, CardType, CardID, Reason, FailureLevel }
└── 更新 stageRecoveryState.queued(高优先级 trigger 覆盖低优先级)
dispatchKickoffEnvelope 完成回调 → maybeStartRecoveryRound
↓
recovery.CompleteKickoff(envelope) → returns queued trigger(若有)
↓
buildRecoveryEnvelope(trigger, previous)
├── CommandText 包含:
│ - [SYSTEM][recovery_loop] stage=X round=N failure_level=L4 reason=...
│ - 恢复策略指令(先 summary → critic → reflector → planner)
│ - [RETRY_READY_CONTEXT] 块(最近 GroupDigest 内容)
│ - [OFFICIAL_HINT] 块(来自比赛平台 /api/hint)
│ └── [KNOWLEDGE_HINT] 块(知识库检索结果,按 trigger/runbook/reference 分层)
└── 新 kickoff → AstrBot(同 session)
recovery 轮次限制:
- commander: max_rounds = 5(yaml 配置)
- pioneer: max_rounds = 2
- swarm: 无 recovery(10 步结束即结束)
- competition.auto_hint = true 时:round >= 2 且 hint_viewed=false 才请求 hint(pioneer 不请求)
5.5 Flag 提交流程
任意 agent 输出 FlagCandidateCard { candidate: "flag{xxx}", stage: "BwAMWQ..." }
↓
upsertCard() → card_pipeline
├── markSessionSolved(sessionID, "flag candidate captured")
│ └── stopAllForStage(stage, exceptSessionID)
│ → 取消同 stage 其他 session 的 HTTP context(best-effort)
│ → 标记为 stop_requested
│
└── maybeAutoSubmitFlagCandidate(card)
├── extractFlagValue(candidate) ← 正则提取 flag{...}
├── 检查 confidence >= min_confidence (默认 0.85)
├── 检查未重复提交
├── [Competition 模式] official.SubmitCompetitionFlag(stage, flag)
│ → POST /api/submit { code: stage, flag: flag }
└── [Legacy 模式] official.SubmitFlag(stage, flag, sourceCardID)
→ POST {flag_submission.endpoint_path}
6. Channel 路由系统
6.1 6 个 Channel
| Channel Key | 默认入口 | 读权限角色 | 用途 |
|---|---|---|---|
main_control |
commander_main | summary, planner, critic, reflector, 6 swarm | 主控决策中心,沉淀摘要/计划/风险 |
recon_raw |
recon_agent | summary, planner, reflector | 侦察原始数据,AssetCard/OBS |
exec_feedback |
executor_agent | summary, planner, critic, reflector, 6 swarm | 执行反馈,ActionCard/RESULT/FlagCandidateCard |
evidence_review |
reflector | critic, commander_main, reflector | 证据归档,EvidenceCard/REPORT |
direct_solve |
pioneer | commander_main, summary | Pioneer 独立解题通道 |
swarm_feedback |
sqli_agent | commander_main, summary, planner | 蜂群专项输出汇总 |
6.2 Publish 规则(tag/card_type → channel)
| 匹配条件 | 目标 Channel |
|---|---|
tag: OBS 或 CardType: AssetCard |
recon_raw |
tag: SUMMARY 或 CardType: GroupDigest |
main_control |
tag: PLAN 或 CardType: HypothesisCard |
main_control |
tag: CRITIC 或 CardType: RiskCard |
main_control |
tag: ACTION 或 tag: RESULT |
exec_feedback |
CardType: FlagCandidateCard |
exec_feedback + swarm_feedback |
tag: REPORT 或 CardType: EvidenceCard |
evidence_review |
tag: SKILL |
evidence_review |
tag: SWARM |
swarm_feedback |
tag: OfficialAPI |
main_control |
6.3 Mirror 规则(额外复制到其他 channel)
| 匹配条件 | 额外发往 |
|---|---|
| AssetCard + confidence >= 0.85 | main_control |
| RiskCard + status=halt | evidence_review |
| tag: RESULT + impact=high | main_control |
6.4 Ingress 模式
main_control:command_only,只接受以/run /next /summary /critic开头的命令- 其余 channel:
none,不接受外部写入(只由 sidecar 内部 publish 写入)
6.5 Stage 过滤(多题并发隔离)
GET /v1/channels/messages?role=summary_agent&channel_key=main_control&stage=BwAMWQ
→ channelbus.Store.List(filter{Stage: "BwAMWQ"})
→ 只返回 PublishedMessage.Stage == "BwAMWQ" 的消息
Stage 在 filePublisher.Publish 时自动从嵌入的 Card.Stage 或 Event.Stage 提取,调用方无需显式传递。
7. HTTP API 参考
所有端点均无认证(内网部署,sidecar 信任所有请求)。
| 方法 | 路径 | 说明 | 关键参数 |
|---|---|---|---|
| GET | /healthz |
健康检查 | — |
| GET | /dashboard |
Web Dashboard HTML | — |
| GET | /v1/dashboard/progress |
Dashboard 数据(JSON) | — |
| GET | /v1/channels |
列出所有 channel(按 role 过滤) | ?role= |
| GET | /v1/channels/messages |
查询 channel 消息 | ?role= &channel_key= &stage= &after_id= &limit= |
| GET | /v1/cards |
查询 card 列表 | ?card_type= &stage= &group_key= &tag= &limit= |
| GET | /v1/cards/{type}/{id} |
获取单张 card | — |
| POST | /v1/cards/upsert |
插入/更新 card(agent 通过 MCP 调用) | {card, publish, publish_text, preferred_channels} |
| POST | /v1/events |
发布事件 | {event} |
| POST | /v1/publish |
发布消息到 channel | {text, tags, card, event, preferred_channels} |
| POST | /v1/ingress/local |
本地消息入站 | {channel_key, message, sender} |
| GET | /v1/ingress/resolve |
解析 channel 入站路由 | ?channel_key= |
| POST | /v1/official-api/poll |
手动触发官方 API 轮询 | — |
| POST | /v1/official-api/submit-flag |
手动提交 flag | {flag, stage, source_card_id} |
| GET | /v1/system/kickoffs |
列出 kickoff envelope | ?target_role= &limit= &after_id= |
| POST | /v1/sessions/{session_id}/stop |
手动停止 session | — |
| GET | /v1/knowledge/query |
查询知识库 | ?q= &zone= &zones= &layers= &tags= &limit= |
| POST | /v1/runner/shell |
执行 shell 命令 | {command, timeout} |
| POST | /v1/runner/python |
执行 Python 代码 | {code, timeout} |
| GET | /v1/runner/artifacts/{job_id} |
获取执行结果 | — |
8. 配置参考
配置文件:configs/atk-sidecar.yaml(主配置)
8.1 顶层配置段
server: # HTTP 监听地址
storage: # 持久化根目录(默认 runtime_data/)
scheduler: # 官方 API 轮询调度(interval 默认 10s)
official_api: # 比赛/题目平台 API(snapshot, hint, flag 提交)
automation: # kickoff + recovery + pioneer 配置
challenge_manager: # 多题并发管理(默认 disabled)
swarm_dispatcher: # 蜂群分发配置(默认 enabled, max 3/stage)
competition: # 比赛平台直连(独立于 official_api,默认 disabled)
knowledge: # 知识库检索(inject_on_recovery, top_k, paths)
runner: # Shell/Python 执行器(local/docker 模式)
channels: # Channel bus 配置(publisher, ingress)
routing: # Channel 路由规则(channels, publish_rules, mirror_rules)
8.2 关键配置项说明
多题并发开关:
challenge_manager:
enabled: true # 启用后接管 challenge 生命周期
poll_interval: "30s"
max_concurrent: 3 # 比赛平台最大并发题目数
蜂群分发:
swarm_dispatcher:
enabled: true
max_concurrent_per_stage: 3 # 每道题同时运行的蜂群 agent 上限
cooldown: "0s" # 同 vuln_type 重新 dispatch 的冷却时间
skills_dir: "skills/domain" # domain skill 文件路径
比赛平台直连(Competition 模式):
competition:
enabled: true
auth_token: "Agent-Token 值"
base_url: "https://competition-api.example.com"
auto_submit: true # FlagCandidateCard → POST /api/submit
auto_hint: true # recovery round >= 2 → POST /api/hint(pioneer 除外)
AstrBot 连接(kickoff 部分):
automation:
kickoff:
mode: "astrbot"
astrbot:
base_url: "http://127.0.0.1:6185"
api_key: "abk_xxx"
session_id: "atk-commander-main-v3"
enable_streaming: true # SSE 流式回复,启用实时卡片解析
8.3 配置 Struct 索引
| struct 名 | yaml key | 文件 |
|---|---|---|
ServerConfig |
server |
config.go:34 |
OfficialAPIConfig |
official_api |
config.go:47 |
AutomationConfig |
automation |
config.go:93 |
PioneerKickoffConfig |
automation.pioneer_kickoff |
config.go:101 |
ChallengeManagerConfig |
challenge_manager |
config.go:107 |
SwarmDispatcherConfig |
swarm_dispatcher |
config.go:113 |
CompetitionConfig |
competition |
config.go:26 |
KnowledgeConfig |
knowledge |
config.go:120 |
KickoffConfig |
automation.kickoff |
config.go:132 |
AstrBotKickoffConfig |
automation.kickoff.astrbot |
config.go:142 |
RoutingConfig |
routing |
config.go:172 |
9. 知识系统
9.1 知识库结构
knowledge/
indexes/ # 索引文件(已构建,直接被 Retriever 加载)
zone1_ctf_web/
trigger.jsonl # 触发规则:看到信号 X → 建立分支 Y
runbook.jsonl # 操作手册:按步骤执行 A/B/C
reference.jsonl # 参考资料:工具、CVE、服务特性
zone2_src_component/
zone3_multi_network_oa/
zone4_ad_pentest/
raw/ # 原始知识文档(供重新构建索引用)
security/ # SecurityMatcher 数据(特征匹配型)
apache/httpd-path-traversal.md
redis/unauthorized-access.md
tomcat/manager-default-creds.md
9.2 知识层语义
| Layer | 作用 | 触发时机 |
|---|---|---|
trigger |
信号→分支映射(看到 X,考虑 Y 漏洞) | 所有 recovery 轮次 |
runbook |
分支确认后的步骤手册(如何利用 Y) | 所有 recovery 轮次 |
reference |
工具/CVE/服务特定参考 | L5_STRATEGIC_FAILURE 或 hard_stall |
Recovery 注入的 [KNOWLEDGE_HINT] 格式:
[KNOWLEDGE_HINT]
以下为可选战术参考,不是事实。当前目标的真实观测优先级高于任何知识提示。
[TRIGGER SIGNALS] — 匹配到以下信号时触发对应漏洞分支:
- ref=... score=0.82 title=... hint=...
[RUNBOOK] — 如果确认漏洞存在,按以下步骤执行:
- ref=... score=0.71 branch=sqli hint=...
[REFERENCE] — 工具/CVE/服务特定参考(仅 L5/hard stall 时包含):
- ref=... score=0.65 hint=...
9.3 SecurityMatcher
独立于 Retriever,专门处理特征指纹匹配:
- 加载
knowledge/security/**/*.md(YAML frontmatter + Markdown body) - 特征字段:
signals(版本字符串、服务指纹)、category(漏洞类别)、cve - 触发:AssetCard 到达 card_pipeline 时,
MatchBySignals(tech_stack + notes + url) - 命中(score >= 1.0)→ 自动生成 HypothesisCard → 触发 swarm dispatch
9.4 Domain Skills
skills/domain/
sqli/SKILL.md # SQL 注入战术手册(~107 行)
ssrf/SKILL.md
auth-bypass/SKILL.md
file-inclusion/SKILL.md
rce/SKILL.md
xss/SKILL.md
web-recon/SKILL.md # Web 侦察技术(recon_agent 使用)
Domain skill 已直接内联到对应的 assembled persona system prompt 中。
同时,swarm_dispatcher.go 的 loadDomainSkill() 也会在 dispatch 时动态注入 CommandText(备份路径)。
10. 持久化与存储布局
所有持久化使用本地 JSONL 文件,无数据库依赖。
runtime_data/ # 运行时数据根目录(yaml: storage.root_dir)
cards/
<CardType>.jsonl # 每种 card 类型一个文件,按 card_id dedup
events/
events.jsonl # 事件流,追加写入
channels/
main_control.jsonl # channel 消息,追加写入
recon_raw.jsonl
exec_feedback.jsonl
evidence_review.jsonl
direct_solve.jsonl
swarm_feedback.jsonl
system_kickoff/
commander_main.jsonl # kickoff envelope 镜像(commander)
pioneer_kickoff/
pioneer.jsonl # kickoff envelope 镜像(pioneer)
flag_submissions/
submissions.jsonl # flag 提交记录
runner_artifacts/
<job_id>.txt # shell/python 执行输出
runtime_exec/ # runner 工作目录(临时文件)
Card 存储特点:
- 同一 (CardType, CardID) 做 upsert(新版本覆盖旧版本)
- 查询通过
CardFilter{CardType, Stage, GroupKey, Tag, Limit}过滤 - Channel 消息只追加,不修改;分页通过
AfterID+Limit实现
11. Go 包结构
atk/
cmd/atk-sidecar/
main.go # 入口:初始化所有组件,启动 HTTP 服务 + 调度 goroutine
internal/sidecar/
types.go # 核心类型:Card, Event, PublishRequest, OfficialSnapshotKickoff
id.go # NewID(prefix) — nanoid 生成
cards/store.go # JSONL card 存储(Upsert, List, Get)
channelbus/
publisher.go # PublishedMessage 定义 + filePublisher(写 JSONL)
store.go # List(ListFilter) — 读 channel 消息,支持 Stage 过滤
config/config.go # 全部 Config struct + Load() + applyDefaults()
events/
bus.go # 事件总线(Publish, Subscribe)
store.go # 事件 JSONL 持久化
httpapi/
server.go # HTTP 路由注册 + 所有 handler
dashboard.go # /v1/dashboard/progress 数据聚合
kickoff/store.go # Envelope 定义 + fileStore/httpStore/astrBotStore 实现
knowledge/
retriever.go # TF-IDF 知识检索(New, Query, QueryScoped)
security_matcher.go # 特征指纹匹配(NewSecurityMatcher, MatchBySignals)
officialapi/client.go # 比赛/题目平台 API 客户端
planning/ir.go # PlanIR 解析(atk_plan XML-like 结构)
router/router.go # 路由规则引擎(ResolvePublish, ResolveIngress)
runner/
executor.go # Shell/Python 执行(local/docker 模式)
safety.go # 命令安全检查
types.go # RunRequest, RunResult
service/ # 核心业务逻辑(见 2.1 节文件职责表)
submissions/store.go # Flag 提交记录 JSONL 存储
包依赖原则:
service包依赖所有基础设施包,基础设施包之间不互相依赖httpapi只依赖service,不直接操作 storageconfig包被所有其他包依赖,不依赖任何内部包
12. 开发规范
12.1 Card 输出规范
agent 通过 fenced code block 输出 card,sidecar 自动解析:
```atk_card
{
"card_type": "HypothesisCard", // 必填,使用上方表格中的类型名
"card_id": "hypothesis-sqli-1", // 必填,格式: <type>-<描述>[-<序号>]
"group_key": "main_control", // 目标 channel(可选,有默认值)
"role": "planner_agent", // 产出角色
"summary": "...",
"status": "proposed",
"priority": "medium",
"confidence": 0.75, // 0.0-1.0
"tags": ["PLAN"],
"payload": { ... } // 类型专属字段
}
`stage` 字段由 sidecar 从 envelope 自动填充,agent 通常不需要手动指定。
### 12.2 FlagCandidateCard 规范(关键)
```json
{
"card_type": "FlagCandidateCard",
"card_id": "pioneer-flag-abc123",
"group_key": "exec_feedback",
"role": "pioneer",
"status": "captured",
"confidence": 0.95,
"tags": ["FLAG", "PIONEER"],
"payload": {
"candidate": "flag{exact_flag_string_here}", // 只放精确 flag,不加任何额外文字
"method": "SQL union-based injection",
"session_id": "atk-pioneer-v1" // 用于 markSessionSolved
}
}
session_id 字段用于 sidecar 的 markSessionSolved。如果 agent 不知道自己的 session_id,sidecar 会 fallback 到 DispatchResult.SessionID。
12.3 Recovery 上下文块规范
sidecar 在 recovery kickoff 的 CommandText 中注入以下块(按顺序):
[RETRY_READY_CONTEXT]
<最近 GroupDigest 的 retry_ready_context 字段内容>
[OFFICIAL_HINT]
<比赛平台 hint>
[KNOWLEDGE_HINT]
<知识库检索结果>
agent 应优先消费 [RETRY_READY_CONTEXT](最高优先级),[KNOWLEDGE_HINT] 视为可选参考。
12.4 Go 编码约定
- 错误处理:公共方法返回
error,内部 helper 返回值类型或零值 - context 传播:所有 IO 操作必须接受
ctx context.Context,async goroutine 使用context.Background() - 并发安全:共享状态用
sync.Mutex(参考 sessionRegistry、swarmDispatcher) - 日志:使用
s.logger.Printf(),不使用全局 log;agent/component 名作前缀[challenge_manager] ... - 空值防御:所有方法第一行检查 receiver 是否为 nil(参考
recoveryController系列方法) - 向后兼容:新增可选字段用零值作 no-op(参考
SessionIDOverride、ListFilter.Stage)
12.5 Kickoff CommandText 格式
/run [SYSTEM][<source>] stage=<code> target_url=<url> <key1>=<val1> ...
<newline>
<optional block 1>
<newline>
<optional block 2>
键值对中不能有空格(sidecar 用空格分割为 parts)。多词值用 _ 连接。
13. 测试策略
13.1 现有测试文件
| 文件 | 覆盖内容 |
|---|---|
service/service_test.go |
端到端集成测试:channel routing, card pipeline, recovery, swarm dispatch |
httpapi/competition_flow_test.go |
完整比赛流程:kickoff → card → flag → submit |
kickoff/store_test.go |
AstrBot kickoff command text 构建 |
knowledge/retriever_test.go |
知识检索:zone/layer 过滤、BM25 评分 |
config/config_test.go |
配置加载、角色白名单验证 |
planning/ir_test.go |
PlanIR XML 解析 |
runner/executor_test.go |
Shell/Python 执行、超时、输出裁剪 |
runner/safety_test.go |
危险命令检测 |
13.2 测试原则
service_test.go使用httptest.NewServer模拟 AstrBot,不需要真实 AstrBot- 每个测试用
t.TempDir()作为 storage root,测试间完全隔离 - config_test.go 的
allowedRolesmap 是新增 agent 角色的契约检查——新增角色后必须更新
13.3 运行测试
go build ./... # 编译检查
go test ./... # 全量测试
go test ./internal/sidecar/service/... -v -run TestServiceChannelMessages
14. 部署说明
14.1 进程启动顺序
1. 启动 Kali 执行环境(如 Docker 容器)
2. 启动 AstrBot(端口 6185)
- 确认 14 个 persona 已从 `persona/assembled/*.md` 粘贴到 AstrBot Web
- 确认 MCP server(atk-sidecar MCP)已配置
3. 启动 atk-sidecar(端口 8090)
ATK_SIDECAR_CONFIG=configs/atk-sidecar.yaml ./atk-sidecar
14.2 Persona 配置
# 直接复制 persona/assembled/<role>.md 到 AstrBot Web
# 例如:
sed -n '1,40p' persona/assembled/commander_main.md
14.3 构建
go build -o atk-sidecar ./cmd/atk-sidecar/
14.4 多题并发模式启用
# configs/atk-sidecar.yaml
competition:
enabled: true
auth_token: "<Agent-Token>"
base_url: "https://hackathon-api.example.com"
auto_submit: true
auto_hint: true
challenge_manager:
enabled: true
poll_interval: "30s"
max_concurrent: 3
# 单题模式的 scheduler 可以保留(用于快速测试),
# 但 challenge_manager 开启后会接管完整的题目生命周期
scheduler:
enabled: false # 建议在 challenge_manager 模式下关闭
14.5 环境变量
| 变量 | 说明 | 默认 |
|---|---|---|
ATK_SIDECAR_CONFIG |
配置文件路径 | configs/atk-sidecar.yaml |
14.6 运行时状态检查
# 健康检查
curl http://localhost:8090/healthz
# 当前 session 状态
curl http://localhost:8090/v1/sessions/atk-commander-main-v3
# 最近 FlagCandidateCard
curl "http://localhost:8090/v1/cards?card_type=FlagCandidateCard&limit=10"
# Dashboard
open http://localhost:8090/dashboard
附录:完整 Card 字段速查
FlagCandidateCard.payload
candidate string 精确 flag 字符串(仅此,不加任何额外内容)
method string 利用方式简述
session_id string 当前 AstrBot session id(用于 markSessionSolved)
vuln_type string (蜂群输出时填写)
HypothesisCard.payload
vuln_type string 必填,触发 swarm dispatch 的关键字段
hypothesis string 假设描述
preconditions []string 前提条件
validation_steps []string 验证步骤
success_signals []string 成功信号
failure_signals []string 失败信号
dominant_branch string 当前最强主线
required_next_moves []string 必要的下一步动作
path_id string 路径 ID(稳定、跨轮复用)
tool_requirements []string 工具需求描述
GroupDigest.payload
facts []string 已验证事实
unknowns []string 待确认项
priorities []string 优先级
dead_paths []string 已证伪路径
repeat_failures []string 重复失败模式
retry_ready_context []string 下一轮可直接消费的摘要
knowledge_candidates []string 候选知识提示(降噪后)
dominant_branch string
required_next_moves []string
active_move_id string
stall_state string "soft_stall" / "hard_stall" / ""
RiskCard.payload
risk_type string
reason string
failure_level string L0-L5
decision string "proceed" / "require_revision_before_execute" / "halt"
need_branch_replan bool L4/L5 时通常为 true
retry_advice string
anti_pattern []string
ActionCard.payload
action_type string
target string
selected_tool string
result string
failure_level string L1-L4(成功时为空)
failure_reason string
observed_deltas []string 与预期的差异
path_id string
move_id string
evidence_gain string