Cruiser Technical Design Document
Cruiser 技术方案文档
面向 CTF 竞赛评测平台(TSec Benchmark)的自动化 Web/逻辑漏洞挖掘与利用 Agent

| 项目 | 说明 |
|---|---|
| 文档版本 | v1.0 |
| 文档日期 | 2026-08-15 |
| 适用代码基线 | Cruiser 主分支(main.py + cruiser/ 包) |
| 读者对象 | 安全研究人员、Agent 系统开发者、评测平台对接方 |
目录
- 概述
- 总体架构
- 核心子系统设计
- 分层调度机制
- 多会话协作机制
- Flag 权威校验与多 Flag 处理
- LLM 接入与多模型路由
- 平台对接流程(TSec Benchmark SDK)
- 靶场网络接入(VPN)
- 工具链与离线知识库
- 配置体系
- 并发安全与容错设计
- 可观测性
- 部署与运行
- 性能调优建议
- 风险与限制
- 演进方向
- 附录
1. 概述
1.1 背景
CTF(Capture The Flag)竞赛评测平台(TSec Benchmark)以「跑分任务」的形式向被测 Agent 下发一批 Web/逻辑漏洞题目。每道题对应一个按需启动的靶场容器,Agent 需通过靶场 VPN 直连容器地址,完成漏洞挖掘与利用,拿到 flag 并提交评分。
人工解题无法匹配评测的吞吐要求,因此 Cruiser 的设计目标是:以完全自动化的方式完成「拉取题目 → 启动靶场容器 → 驱动 Agent 解题 → 提交 flag → 关闭容器」的完整闭环,并通过多进程并发、分层调度与跨会话共享记忆机制,在平台活跃容器名额约束下最大化解题吞吐与成功率。
1.2 设计目标
| 目标 | 说明 | 对应机制 |
|---|---|---|
| 全自动闭环 | 无需人工干预跑完整轮评测 | 主进程调度循环 + SDK 对接 |
| 高吞吐 | 容器名额(默认 3)始终打满 | 分层调度 + 动态并行 + 僵尸容器回收 |
| 高成功率 | 难题多轮尝试、多视角探索 | 四级晋升调度 + 多会话黑板共享 + 提示分级启用 |
| 崩溃可恢复 | 任意一层进程死亡不影响全局 | 三层进程边界 + 进程组回收 + 孤儿清理兜底 |
| 结果可信 | flag 必须由平台确认,不信任模型自述 | 框架权威校验 + 程序化补交 |
| 资源合规 | 遵守比赛规则(禁联网检索、提示扣分最小化) | 禁用 WebSearch/WebFetch + 提示延迟到三级启用 |
1.3 设计原则
- 进程边界清晰:调度、执行、智能体三层进程各司其职,单层崩溃可独立恢复。
- 文件系统即总线:跨进程协作不引入消息队列/数据库,全部通过
reports/目录下的文本文件完成,以fcntl文件锁 + 临时文件os.replace原子重写保证并发安全。 - 不信任模型自述:flag 有效性、进度完成度均以平台 SDK 的同步返回为唯一事实来源。
- 上下文硬注入:关键协作信息(题目描述/提示/黑板)通过 Claude Code 钩子物理注入模型上下文,不依赖模型自觉读取文件。
- 表驱动可扩展:LLM 提供方接入采用注册表 + 模型名前缀路由,新增一家提供方只需加两行配置。
1.4 术语约定
| 术语 | 含义 |
|---|---|
| 题目 / Challenge | 平台下发的一道 CTF 题,有唯一 unique_code,可能包含多个 flag |
| 会话 / Session | 一次完整的 claude CLI 解题对话 |
| Worker | 执行层子进程(main.py --sessions 1 副本),每个 worker 拉起一个 claude 会话 |
| Solver | 定向 worker:只认领任务板上的一条探索方向并聚焦执行 |
| Watcher | 后台策展 LLM:审阅会话活动,维护黑板质量、发布探索方向 |
| 黑板 / Blackboard | 跨会话共享的关键事实文件 reports/info_<code>.txt |
| 任务板 / Task Board | 待认领探索方向文件 reports/tasks_<code>.txt |
[COUNT] |
worker 打印的步数计数(每个 assistant 事件 +1),调度器据此判定层级阈值 |
| turn | claude CLI 的回合数(--max-turns),与 [COUNT] 不同口径,约为数倍关系 |
2. 总体架构
2.1 三层进程架构
Cruiser 的解题引擎基于 claude CLI(--output-format stream-json 流式模式)驱动一个自主 Agent,Anthropic 兼容端点默认接入 DeepSeek。系统分为三层进程:
1 | flowchart TB |
进程链:
1 | main.py(调度器)→ main.py --sessions 1(worker)→ claude CLI → bash/python 工具子进程 |
各层职责与崩溃隔离:
| 层 | 进程 | 职责 | 崩溃影响面 |
|---|---|---|---|
| 调度层 | main.py 主进程 |
唯一与平台交互的进程:轮询未解题目、分层调度、spawn worker、监控 [COUNT] 步数、回收容器与孤儿进程 |
全局退出,atexit 整组清理 worker 并关闭活跃容器 |
| 执行层 | worker 子进程(带 CRUISER_WORKER_ID) |
调用 run_auto_scan(),拉起并解析 claude 流式输出,触发 watcher,权威校验 flag |
单题单会话失败,不影响其他题目 |
| Agent 层 | claude CLI 进程 |
真正的解题智能体,用内置 Bash/Read/Write 工具侦察与利用 | 会话结束,worker 收尾后可重启新会话 |
2.2 端到端数据流
1 | sequenceDiagram |
2.3 关键技术选型
| 维度 | 选型 | 理由 |
|---|---|---|
| Agent 运行时 | claude CLI(stream-json headless 模式) |
成熟的工具调用循环、上下文压缩、钩子机制;避免自研 ReAct 循环的可靠性问题(旧 cruiser/agent.py 手写 ReAct 引擎已弃用保留参考) |
| 解题模型 | DeepSeek(默认 deepseek-v4-flash) |
经 Anthropic 兼容端点接入,1M 上下文窗口 |
| 策展模型 | deepseek-v4-pro |
黑板策展与方向规划需要更强推理能力 |
| 进程间通信 | 文件系统 + fcntl 锁 + os.replace |
零外部依赖、崩溃一致性好、可人工检视 |
| 平台对接 | tsec-benchmark SDK(httpx) |
官方封装:VPN 预检、题目/容器/提交生命周期、错误码体系 |
| 包管理 | uv + pyproject.toml |
快速、可锁定(uv.lock);离线镜像整份分发虚拟环境 |
3. 核心子系统设计
3.1 项目结构
1 | Cruiser/ |
3.2 调度层(main.py 主进程)
主进程是系统中唯一与平台交互的进程(worker 仅以 submit_flag.py 形式做权威校验提交),职责包括:
启动自检
ensure_vpn_connected():SDK 预检 VPN,不通则自动用vpn/下最新.ovpn配置拉起 openvpn 并修复推送路由(详见 §9);vpn/为空时跳过 VPN 直接答题。文件锁/tmp/cruiser_vpn.lock防止并发重复连接。close_all_containers():关闭所有平台侧仍在运行的容器(含已完成题目的残留),确保从干净状态开始。
调度主循环(1 秒周期)
fetch_all_unsolved()拉取未解题目及进度;- 与内存中的层级队列(
preprocessed / tier1 / tier2 / tier3 / solved)对账:题目从平台消失时触发对应会话组的强杀(kill_flags[code].set()); - 僵尸容器回收:平台侧仍在运行但本地无在飞线程的容器,由后台线程逐个关闭,避免挤占活跃名额;
- 按层级依次尝试启动各题的执行器线程,受
MAX_INFLIGHT(CRUISER_MAX_ACTIVE,默认 3)严格限流。
worker 生命周期管理
spawn_worker():以main.py --sessions 1 --challenge-code <CODE>形式 fork 子进程,注入CRUISER_WORKER_ID(兼作「跳过 VPN/容器管理」的身份标记)、CRUISER_WORKSPACE_DIR、目标地址、模型(ANTHROPIC_MODEL)等环境变量;worker 以start_new_session启动为独立进程组。reader_thread():逐行读取 worker 输出,解析[COUNT]、flag 进度 X/Y、最终{"flag"}JSON,驱动阈值停止与胜出判定。- 退出清理:
atexit+ SIGINT/SIGTERM 处理器对所有 worker 进程组killpg,并关闭活跃容器;kill_orphans.py作为父进程意外死亡后的悬空进程兜底清理。
冷却与去重
_in_cooldown()防止同一题被频繁重启;- skipped(容器未就绪、本轮未实际执行)与 remaining(实际执行但未解出)严格区分——skipped 不消耗层级进度,留在原层重试。
3.3 执行层(worker 子进程)
worker 是 main.py 自身的副本,因带 CRUISER_WORKER_ID 而跳过 VPN/容器管理,直接调用 cruiser.claude_agent.run_auto_scan():
- 按是否带
solver_task选择系统提示词与任务模板(普通探索 / solver 定向模式); - 在工作空间写入
.claude/settings.json注册黑板钩子(见 §5.2); - 拉起
claudeCLI 子进程(不使用start_new_session,使其留在本进程组内,调度器killpg时可整组回收); - 逐行解析 stream-json 事件流:
assistant事件:[COUNT]步数 +1、提取文本与工具调用、滚动维护最近活动摘要(deque(maxlen=12))、每 6 步触发一次后台 watcher、捕获模型提交的 flag 并当场权威校验;user事件(工具结果):正则收集flag{...}候选,追加观察摘要;result事件:会话结束(success / error_max_turns / error_*),跳出循环;
- 收尾:会话结束时同步触发一次最终 watcher(30s 超时保护),并对全部 flag 候选逐个程序化补交校验(命中即输出
[FLAG RECOVERED])。
3.4 Agent 层(claude CLI 进程)
Agent 层的启动命令形态:
1 | claude -p "<任务提示>" \ |
设计要点:
- 禁联网检索:CTF 比赛禁止联网检索,显式从工具集移除
WebSearch/WebFetch(headless 下bypassPermissions会自动放行,必须显式禁用)。 - 系统提示词(
cruiser/prompt.py):定位「Web 漏洞 + 逻辑漏洞」解题专家,覆盖 SQL 注入、XSS(目标为弹窗XSS字符串)、CSRF、文件包含、文件上传、越权、竞态、业务逻辑等类别的识别与利用套路,并内置工程化守则:- 批量/并发策略:爆破枚举类任务必须写脚本或用
seq | xargs -P N并发,禁止逐请求手工尝试; - 工具纪律:调用安全工具先
-h/--help;目录扫描必须走dirsearch_scan工具(跨会话去重 + 报告落盘,避免上下文溢出);flag 只能经submit_flag工具提交; - 产物落盘:大输出写入
$CRUISER_WORKSPACE_DIR后再读取筛选,避免撑爆上下文。
- 批量/并发策略:爆破枚举类任务必须写脚本或用
- 上下文窗口管理:通过
CLAUDE_CODE_MAX_CONTEXT_TOKENS(默认 1,000,000)声明真实窗口,CLAUDE_CODE_AUTO_COMPACT_WINDOW(默认 800,000)提前触发 auto-compact,留余量避免逼近硬上限。
4. 分层调度机制
4.1 层级模型
新题在四个队列间逐级晋升,每级步数阈值递增;任一会话解出 flag 即整组停止。提示(hint)会按比例扣减得分,因此延迟到三级才启用——先用纯黑盒能力尝试,必要时再付出代价。
1 | stateDiagram-v2 |
| 层级 | 触发条件 | 步数阈值 | 是否带提示 | 未解出去向 |
|---|---|---|---|---|
| 预处理 | 新题 | 50 | 否 | 晋级一级 |
| 一级 | 预处理未解出 | 100 | 否 | 晋级二级 |
| 二级 | 一级未解出 | 150 | 否 | 晋级三级 |
| 三级 | 二级未解出 | 200 | 是 | 放回队尾,按 200 步循环重试 |
补充规则:
- 一级队列按题目难度排序(
DIFF_RANK),优先打简单题,快速积累得分; - skipped 语义:容器未就绪导致本轮根本没执行的题,不算尝试过、不晋级,留在原层等待下一轮;
- 每一级对同一道题并发拉起
--sessions个黑盒 worker 会话(全程黑盒,无源码审计),各会话独立探索、以不同会话编号署名; - 所有 worker 均为主力波(wave=2),全部计入步数阈值;阈值判定以单会话
[COUNT]达到阈值为准。
4.2 单轮执行流程(run_parallel_stage)
1 | flowchart TD |
4.3 活跃名额限流
- 平台限制同时活跃的容器数,
MAX_INFLIGHT = CRUISER_MAX_ACTIVE(默认 3),超过上限的启动请求会被平台拒绝(InvalidState: max active); - 调度循环每轮检查
_inflight_count() >= MAX_INFLIGHT即停止派发新题,剩余题目留待下一轮; - 僵尸容器回收器持续释放被占用的名额,避免「平台侧在跑、本地没跟踪」的泄漏导致新题无法启动。
5. 多会话协作机制
多会话并发的核心矛盾是:既要独立探索(视角多样性),又要共享发现(避免重复劳动)。Cruiser 用「共享黑板 + 任务板 + 硬注入钩子 + 策展 watcher」四件套解决。
5.1 协作机制总览
1 | flowchart LR |
5.2 上下文硬注入(blackboard_hook.py)
不依赖模型自觉去读黑板文件,而是在 worker 工作目录写入 .claude/settings.json 注册 Claude Code 钩子,让内容物理进入模型上下文:
| 钩子事件 | 触发时机 | 注入内容 |
|---|---|---|
SessionStart |
会话开局一次 | 题目描述 + 题目提示 + 当前黑板(各若非空) |
PostToolUse |
每 10 次工具调用 | 上述三项的最新内容,并标注「请关注并利用其他会话的新发现」 |
- 注入通道为
hookSpecificOutput.additionalContext; - 单项截断 3000 字符(黑板取尾部 3000 字符,保留最新发现),防止上下文被协作信息淹没;
- 钩子按
CRUISER_CHALLENGE_CODE定位该题的文件,无内容可注入时不输出任何东西(零开销)。
5.3 共享黑板与策展 Watcher
黑板 reports/info_<code>.txt 保存各会话已发现的关键事实(口令、路径、端点、结论等),条目格式:
1 | [2026-08-15 12:00:00] 会话: 2 |
Watcher 策展(_watcher_curate_blackboard):
- 每个会话每 6 步在后台线程触发一次(单 watcher 并发闸
busy标志防重入);会话结束时强制补一次尾部采集(30s join 超时,防止 daemon 线程随进程退出丢失最后发现); - watcher LLM(
deepseek-v4-pro,策展与方向规划需要更强推理)基于:题目描述 + 提示 + 最近 12 条活动摘要 + 当前黑板 + 任务板(待认领/执行中),产出结构化 JSON:add(≤3 条):提取新关键信息;update(≤3 条):修正过时/错误条目(保留原头部的时间戳与会话归属,仅替换信息内容);remove(≤3 条):删除失效条目;suggest_tasks(≤2 条):向任务板推荐新探索方向;retire_tasks(≤3 条):下架重复/过时方向;
- 并发安全应用变更:LLM 审阅基于无锁快照;应用变更时持文件锁重读最新内容,按内容模糊匹配(归一化包含关系或字符 bigram 重叠系数 ≥ 0.6)定位条目——不用行号,规避并发编辑导致的行号漂移;写回走临时文件 +
os.replace原子替换; - watcher 失败静默吞掉,绝不影响解题主流程;
- 附带职责:从活动与黑板中提取
flag{...}候选并程序化兜底提交——watcher 也能交 flag。
5.4 探索方向任务板(cruiser/taskboard.py)
任务板 reports/tasks_<code>.txt 用于把「接下来值得试什么」显式化,行格式 [t-xxxxxx] 方向内容:
1 | sequenceDiagram |
关键参数与规则:
| 项 | 值 | 说明 |
|---|---|---|
_MAX_PENDING |
5 | 板上最多待认领方向数,超过不再发布 |
_CLAIMED_TTL_S |
45 分钟 | 认领擦除后的方向仍参与判重(防 watcher 重复发布);超时自动解冻,避免认领方异常死亡导致方向永久锁死 |
| 判重算法 | 归一化包含 / bigram ≥ 0.6 | 消除路径分隔符、标点、空白差异的相似方向判定 |
| 认领语义 | 锁内擦除 | 多 worker 并发认领同一方向时只有一个成功 |
5.5 Solver 定向执行
除普通探索 worker 外,每题还有一个 solver_driver 线程:
- 维持 ≤
CRUISER_MAX_SOLVERS(默认 3)个并发 solver; - 每个 solver 从任务板 FIFO 认领一条方向,以聚焦的系统提示词(
CLAUDE_SOLVER_SYSTEM_PROMPT+ 任务模板)启动定向会话,回合上限CRUISER_SOLVER_MAX_TURNS(默认 40),模型CRUISER_SOLVER_MODEL(默认deepseek-v4-flash); - solver 退出即回收补位;整题出 flag 或本轮结束时停止并清杀所有 solver;
- 与探索 worker 的关系:探索 worker 广撒网、自然发现并写黑板;watcher 把「值得深挖但未做」的方向显式化到任务板;solver 按需领任务做定向突破,三者形成「探索 → 策展 → 攻坚」的闭环。
6. Flag 权威校验与多 Flag 处理
6.1 权威校验原则
不信任模型输出的任何文本标记(包括模型自称「提交成功」),flag 有效性唯一以平台 SDK 的同步返回为准:
1 | flowchart TD |
_verify_flag()对同一候选只核实一次(verified集合去重),避免重复提交;- 当场校验:模型一调用提交工具,框架立即亲自向平台核实,命中即停止会话;
- 收尾补交:会话结束(出 flag / 达轮数上限 / 自然结束)时,对全部合法候选按长度降序逐个补交——覆盖「flag 在最后一回合找到、提交命令被
--max-turns切断」等情况,命中打印[FLAG RECOVERED]; - watcher 策展前也先执行一轮候选兜底提交(即便无可用 watcher LLM 也能补交)。
6.2 多 Flag 题目的完成判定
一道题可能有多个 flag(flag_count > 1),规则:
submit_flag的同步返回包含「flag 进度 X/Y」,reader 线程实时解析记录;- 仅当 X ≥ Y(全部 flag 到手)才判定整题解出、置 winner 停止整组;
- worker 输出最终
{"flag"}JSON 时:单 flag 或总数未知视为完成;多 flag 未集齐则继续运行(_json_flag_is_final)。
7. LLM 接入与多模型路由
7.1 表驱动提供方注册表(cruiser/llm.py)
所有「连哪家模型/端点/用哪把 key」的逻辑集中在 llm.py,采用注册表 + 模型名前缀路由:
1 | flowchart LR |
| 提供方 | 密钥环境变量 | 比赛内网端点(默认) | 本地端点(--local) |
|---|---|---|---|
| deepseek | DEEPSEEK_API_KEY |
http://api.deepseek.com.tsecbench.gw/{anthropic,v1} |
https://api.deepseek.com/{anthropic,v1} |
| kimi (moonshot) | KIMI_API_KEY |
http://api.moonshot.cn.tsecbench.gw/{anthropic,v1} |
https://api.moonshot.cn/{anthropic,v1} |
端点解析优先级:显式环境变量覆盖 > 本地模式官方域名 > 比赛内网域名。新接一家提供方只需在 PROVIDERS 注册表加一条配置 + 在 MODEL_PREFIX_TO_PROVIDER 加前缀,无需改任何调用方。
7.2 双通道消费
| 消费方 | 通道 | 配置来源 |
|---|---|---|
| 解题引擎(claude CLI) | Anthropic 兼容端点(ANTHROPIC_BASE_URL / ANTHROPIC_AUTH_TOKEN / ANTHROPIC_MODEL) |
get_claude_provider_env(),密钥缺失时回退显式 ANTHROPIC_AUTH_TOKEN |
| watcher / 旧 ReAct 引擎 | OpenAI 兼容端点(langchain ChatOpenAI) |
_build_chat_openai(),无密钥/依赖时返回 None 静默降级 |
7.3 多模型混编与温度分片
--worker-models deepseek-v4-flash,deepseek-v4-flash,kimi-k3:worker 数量 = 清单长度(覆盖--sessions),第 i 个 worker 用第 i 个模型,不同厂商可混搭(按模型名自动路由端点与密钥);- 默认模型分工:解题
deepseek-v4-flash(DEEPSEEK_MODEL/ANTHROPIC_MODEL覆盖)、watcherdeepseek-v4-pro(WATCHER_MODEL覆盖)、solverdeepseek-v4-flash(CRUISER_SOLVER_MODEL覆盖); - 温度分片(langchain 路径):按 worker 编号在
[CRUISER_TEMP_MIN, CRUISER_TEMP_MAX](默认 0.0 ~ 0.9)线性分配——低编号会话确定性高、高编号会话发散性强,用温度梯度制造探索多样性。
8. 平台对接流程(TSec Benchmark SDK)
平台对接全部走官方 tsec-benchmark SDK(详见 doc/SDK_API.md),Cruiser 在其上做的工程化增强:
| SDK 能力 | Cruiser 的使用方式 |
|---|---|
上下文管理器入口 VPN 预检(VpnCheckError) |
兼作「VPN 是否已连」的探测信号,驱动自动重连逻辑(§9) |
list_challenges() |
1s 周期轮询,过滤 is_completed,同步容器状态做僵尸回收与对账 |
start_challenge(code) |
受 MAX_INFLIGHT 限流;返回 container_addr(IP:端口 数组,可能多个),拼为 http:// 目标串 |
get_hint(code) |
三级才调用(提示按比扣分),落盘 hint_<code>.txt 全会话共享 |
submit_flag(code, flag) |
唯一可信提交通道;DuplicateSubmit 视为幂等成功 |
close_challenge(code) |
每轮结束统一关闭 + 启动时全量清理 + 僵尸后台回收,三道防线防泄漏 |
容器就绪探测(CRUISER_CONTAINER_WARMUP,默认 60s):拿到地址后主动探测目标端口,可连即拉起会话;超时也放行交由 LLM 解题,防止平台侧慢启动卡死调度。
错误处理映射:
| 平台异常 | 处理策略 |
|---|---|
VpnCheckError |
触发自动重连 VPN |
InvalidState(max active) |
名额已满,本轮跳过,下轮重试 |
InvalidState(任务已结束) |
向上抛出,停止流程 |
DuplicateSubmit |
幂等,视为该 flag 已计入 |
ResourceUnavailable |
稍后重试启动或跳过 |
9. 靶场网络接入(VPN)
1 | flowchart TD |
要点:
- 仅主进程执行;spawn 的 worker 子进程带
CRUISER_WORKER_ID会跳过; - 路由修复:本环境 openvpn 2.5 的 sitnl 对部分推送路由添加失败(Network is unreachable),统一改用
ip route replace <net>/<mask> dev tun0直连设备方式兜底; - 手动维护通道:
connect_vpn.sh供人工调试时连接并修复路由。
10. 工具链与离线知识库
10.1 自研 CLI 封装(tools/,供 Agent 经 Bash 调用)
| 工具 | 功能 | 设计要点 |
|---|---|---|
submit_flag.py |
经 SDK 提交并确认 flag | flag 提交的唯一通道;平台同步返回进度 X/Y |
dirsearch_scan.py |
目录扫描 | 跨会话去重:同一 URL 全会话只实扫一次,其余阻塞复用报告;报告落盘防上下文溢出 |
task_board.py |
任务板 list/claim/report |
Agent 侧的命令行入口 |
decompile.py |
PyGhidra 无头反编译 | 输出 C 伪码,并标注被编译器消除的取数、switch 各 case 语义与未确认 opcode、数据引用 |
10.2 预装安全工具集
| 类别 | 工具 |
|---|---|
| Web/渗透 | dirsearch / sqlmap / fenjing(SSTI)/ nuclei(内置模板库)/ ffuf / whatweb / Metasploit + PostgreSQL |
| 逆向/Pwn | Ghidra + PyGhidra / radare2 / pwntools / angr / ropper / one_gadget / GDB |
| 密码/取证 | pycryptodome / gmpy2 / sympy / z3 / steghide / zsteg / binwalk |
| 智能合约 | Foundry(forge/cast/anvil)/ 多版本 solc / slither / web3.py |
list_security_tools 工具供 Agent 探测环境内可用的安全工具及版本。
10.3 离线知识库与字典
kb/:vulhub / nuclei-templates / PayloadsAllTheThings +kb/bin/nuclei可执行文件,支持按 CVE/组件本地检索 PoC(CRUISER_KB_DIR可覆盖路径)——配合禁网规则,全部情报来源本地化;resource/:username.txt/password.txt/xss.txt字典与flag_hunting.txt(flag 线索清单)。
11. 配置体系
11.1 命令行参数
| 参数 | 默认值 | 说明 |
|---|---|---|
--target |
无 | 扫描目标地址(未提供时由 SDK 启动容器获取) |
--challenge-code |
无 | 题目代码 |
--sessions |
1 | 并发工作会话数(≥2 进入分层调度) |
--worker-models |
无 | 各 worker 模型清单,覆盖 --sessions;kimi-* 自动路由 Kimi 端点 |
--max-steps |
0 | 引擎内强制步数上限(0 = 不强制,由调度器按阈值监控) |
--hint |
无 | 题目提示 |
--quiet |
False | 静默中间输出,仅保留最终 JSON |
--local |
False | 本地测试模式:LLM 端点切回官方 https 域名 |
--default-timeout / --max-timeout |
0 | run_command 默认/上限超时秒数 |
11.2 关键环境变量(完整清单见 README)
| 分类 | 变量 | 说明 |
|---|---|---|
| 平台 | BENCHMARK_BASE_URL / BENCHMARK_TOKEN |
平台 API 地址与跑分凭证(必填) |
| 密钥 | DEEPSEEK_API_KEY / KIMI_API_KEY |
按模型名前缀自动选用 |
| 模型 | DEEPSEEK_MODEL / ANTHROPIC_MODEL / WATCHER_MODEL / CRUISER_SOLVER_MODEL |
解题 / watcher / solver 模型 |
| 上下文 | CLAUDE_CODE_MAX_CONTEXT_TOKENS(1M)/ CLAUDE_CODE_AUTO_COMPACT_WINDOW(800K) |
校正 auto-compact 触发时机 |
| 调度 | CRUISER_MAX_ACTIVE(3)/ CRUISER_CONTAINER_WARMUP(60s) |
活跃名额 / 容器就绪探测 |
| 协作 | CRUISER_TEMP_MIN/MAX(0.0/0.9) |
多会话温度分片区间 |
| solver | CRUISER_SOLVER_MAX_TURNS(40)/ CRUISER_MAX_SOLVERS(3) |
solver 回合与并发上限 |
| 逆向 | GHIDRA_INSTALL_DIR / JAVA_HOME |
PyGhidra 运行环境 |
密钥纪律:所有凭证一律经环境变量(可写 .env,不覆盖已有环境变量),源码零硬编码;.env 不入库。
12. 并发安全与容错设计
12.1 并发安全清单
| 场景 | 机制 |
|---|---|
| 黑板/任务板并发读写 | fcntl.LOCK_EX 文件锁包裹「读-改-写」全程;写回走临时文件 + os.replace 原子替换,读者永远看到完整文件 |
| watcher 应用变更 vs 其他会话写入 | LLM 审阅用无锁快照,应用时锁内重读最新内容,按内容模糊匹配定位(规避行号漂移) |
| 任务认领竞争 | 锁内「找到即擦除」,先到先得;.claimed 日志 45 分钟 TTL 参与判重并自动解冻 |
| dirsearch 跨会话重复扫描 | 同一 URL 仅实扫一次,其余会话阻塞等待复用报告 |
| VPN 并发重连 | /tmp/cruiser_vpn.lock 排他锁 + 拿锁后复核 |
| flag 重复提交 | 平台侧 DuplicateSubmit 幂等 + 本地 verified 集合去重 |
12.2 容错与恢复矩阵
| 故障 | 检测 | 恢复 |
|---|---|---|
| worker/claude 崩溃 | reader 线程读到 EOF / 进程退出码 | 该题本轮记 remaining,晋级或重试;其他题不受影响 |
| 主进程退出(Ctrl+C/SIGTERM) | 信号处理器 + atexit |
整组 killpg 所有 worker 并关闭活跃容器 |
| 主进程异常死亡(SIGKILL) | 父进程已死 | kill_orphans.py 清理悬空 worker/claude 进程组 |
| 平台侧容器残留 | 启动时全量扫描 + 调度循环僵尸检测 | close_all_containers() + 后台回收线程 |
| LLM 端点不可用 | SDK/HTTP 异常 | watcher 降级静默跳过;worker 会话自然结束,下轮重试 |
| watcher LLM 失败 | 异常吞没 | 不影响解题主流程;flag 兜底提交先于策展执行 |
| 容器慢启动 | warmup 探测超时(60s) | 放行交由 LLM 自行重试,防调度卡死 |
| 题目从平台移除 | 轮询对账 | kill_flags[code].set() 强杀对应会话组 |
| 上下文逼近上限 | AUTO_COMPACT_WINDOW(800K) |
claude CLI 自动压缩,留 200K 余量 |
13. 可观测性
系统全部通过结构化 stdout 标记输出,便于 tee 落盘与 grep 检索:
| 标记 | 含义 |
|---|---|
[COUNT] N |
跨会话单调递增的步数计数(调度阈值依据) |
[TOOL] ... / [Claude] ... |
工具调用与模型文本摘要 |
[Watcher] 会话 X 维护黑板: 新增/修正/删除 |
黑板策展动作 |
[Watcher] 会话 X 任务板: 发布/下架 |
任务板变更 |
[Stage-Preprocess/Tier1/Tier2/Tier3] |
层级调度事件 |
[STAGE] 步数达到阈值 c/limit |
本轮停止原因 |
[FLAG RECOVERED] |
会话结束后程序化补交成功 |
[Reaper] 回收僵尸容器 / [Startup] 关闭遗留容器 |
容器治理 |
[{code}:S{idx}] / [{code}:SOLVER{sid}] |
按题+会话前缀的 worker/solver 输出 |
14. 部署与运行
14.1 环境要求
- Python ≥ 3.11,uv 包管理器;
claudeCLI 必须安装且在 PATH 中(引擎依赖);- 靶场 VPN 配置放入
vpn/(为空则跳过 VPN 直接答题); - 可选:Ghidra + JDK(PyGhidra 逆向)。
14.2 安装与启动
1 | # 安装 uv 与依赖 |
离线部署说明:
uv sync只装核心依赖,解题中 Agent 还会按需临时加装 Python 包(web3/slither/angr等)。离线镜像直接整份分发已就绪的.venv,而非在目标环境重新 sync。
15. 性能调优建议
| 目标 | 手段 |
|---|---|
| 提高单位时间解题数 | 调大 --sessions(受名额与 LLM 配额约束);保证 CRUISER_MAX_ACTIVE 与平台名额一致,避免名额空转 |
| 提高难题成功率 | 提高三级阈值;--worker-models 混入更强模型(如 1 个 deepseek-v4-pro 带 2 个 flash);确认 watcher 用 pro 级模型 |
| 降低 token 成本 | 主力用 flash 级模型;黑板/任务板注入已有 3000 字符截断;--quiet 减少日志 I/O |
| 减少重复劳动 | 保持黑板注入开启;dirsearch 去重勿绕过;合理温度分片(默认 0.0~0.9)保证视角差异 |
| 缩短容器空转 | warmup 探测保持默认 60s;确保僵尸回收正常(日志中关注 [Reaper]) |
16. 风险与限制
- 强依赖
claudeCLI:引擎构建在其 stream-json 协议与钩子机制上,CLI 版本升级需回归验证。 - 平台名额硬约束:
CRUISER_MAX_ACTIVE必须与平台实际配额一致,否则出现启动拒绝或名额浪费。 - 提示扣分:三级起拉取提示会按比例扣减得分,属设计取舍(宁可扣分也要解出),不适合「禁提示」规则的赛事。
- 黑盒定位:当前流程全程黑盒(无源码审计通道);对需源码辅助的题目依赖 Agent 自行从靶场读源码(文件包含/命令执行后优先读源码已写入提示词)。
- watcher 成本:每 6 步一次 pro 级模型调用,token 开销随会话数线性增长。
- 文件总线规模:单题黑板依赖 watcher 策展控制体量;极端长会话下黑板仍可能膨胀,注入端以尾部 3000 字符截断兜底。
17. 演进方向
| 方向 | 说明 |
|---|---|
| 解题画像学习 | 统计各题型的层级分布与耗时,动态调整阈值与模型搭配 |
| 黑板结构化升级 | 从自由文本演进为「端点/凭证/漏洞/结论」分类条目,支持按类检索注入 |
| solver 策略强化 | 根据任务板认领完成率动态扩缩 solver 数;引入方向优先级 |
| 多题知识迁移 | 跨题目沉淀可复用利用模式(当前知识库为静态离线 PoC) |
| 恢复点能力 | 会话中断后基于黑板 + 活动摘要续跑,而非从零开始 |
| 评测报表 | 汇总每题解题路径、步数、token 消耗,输出可视化跑分报告 |
18. 附录
18.1 关键源文件索引
| 文件 | 职责 |
|---|---|
main.py |
CLI 入口、VPN、容器治理、分层调度主循环、worker/solver 生命周期 |
cruiser/claude_agent.py |
claude CLI 驱动、stream-json 解析、watcher 策展、flag 权威校验 |
cruiser/llm.py |
LLM 提供方注册表、模型路由、温度分片 |
cruiser/taskboard.py |
任务板发布/认领/回报/下架(文件锁 + 原子重写 + 相似度判重) |
cruiser/prompt.py |
系统提示词与任务模板(探索 / solver 两套) |
cruiser/tools.py |
SDK 客户端、submit_flag、dirsearch、XSS fuzz 等工具实现 |
blackboard_hook.py |
SessionStart / PostToolUse 上下文硬注入钩子 |
kill_orphans.py |
悬空进程清理兜底 |
doc/SDK_API.md |
tsec-benchmark SDK 接入文档 |
18.2 运行时文件布局(reports/)
| 文件 | 内容 | 写者 | 读者 |
|---|---|---|---|
info_<code>.txt |
共享黑板 | 各会话 / watcher / 任务回报 | 钩子注入、watcher |
tasks_<code>.txt |
待认领探索方向 | watcher | worker / solver |
tasks_<code>.txt.claimed |
认领日志(45min TTL) | claim_task | publish 判重、watcher |
hint_<code>.txt |
题目提示 | 主进程(三级拉取) | 钩子注入、watcher |
desc_<code>.txt |
题目描述 | 主进程 | 钩子注入、watcher |
本文档与代码同步维护;机制性变更请同步修订对应章节。
