CTF 竞赛业已变成 AI 狂欢,许多知名战队变成了 AI 驾驶员团队。当代模型(GPT-5.4 和 Opus 4.6)超越了绝大部分选手,而且我们完全看不到 AI 未来发展的瓶颈。在不远的将来,CTF 会被 AI 几乎完美地解决,如同 OI 和 ICPC 被 AI 解决。不过,在 AGI 时代到来之前,我们人类选手还有点事可以帮 AI 做:选模型、选 agent,以及写几句 user prompt。本文要解决的核心问题是:如何选择模型和 agent,让它的 CTF 能力最强?
此事的复杂程度经常被人低估,许多选手会凭经验选择 Claude Opus 4.6 + Claude Code。然而,就在前几周,某场线上初赛,由于题目简单,解出全部题目的队伍比出线名额还多。此时,用时较短的队伍会获胜。大尺寸 LLM 的推理速度慢于小尺寸 LLM,且 agent 行事风格不同——有些 agent 总是步步为营地收集信息,有些 agent 倾向于尽快把最可能成功的 PoC 打出去。所以我们不仅要衡量 agent 能不能做出题,还要衡量它的解题速度。
目前没有公认的 CTF agent 能力测量框架。事实上,连公认的 benchmark 题目库都没有。笔者也不打算做一个公认的框架;与之相反,本文要做一个开源项目,让每个人都能拥有「最贴合自己需求」的测量框架。
0x00 如何开源
今年 3 月,OpenAI 开源了一个有趣的项目:openai/Symphony,核心文件是 SPEC.md,长达 78 KB。要想使用它,需要先对自己的 coding agent 说:「根据 SPEC.md 实现 Symphony 项目」。接下来 agent 会产出具体实现,然后用户再使用之。
以前网络上常调侃 vibe coding 是「code is cheap, show me the prompt」,如今成真了。但想想也确实如此:若要用同一份代码解决各种用户的需求,则代码基必然冗杂;既然每个人的需求都不一致,那不妨给出一份《实现指南》,让 agent 根据用户具体情况来落地。这套开源模式也很适合本文的项目,因为每个人想测的题目集不同、模型不同、做题环境也不同。笔者将编写一份 SPEC.md 以描述笔者自己的需求,用户可以按照实际情况修改它,然后要求 agent 将其实现。
0x01 基本思路
我们要做的是:「对于每个 harness,测量它在每道题目上的表现」。测量指标包括:是否成功获得 flag、总耗时,以及用户想测量的其他指标(比如 token 用量、费用等)。
接下来需要给出「题目」和「harness」的定义。笔者将「题目」定义为一个文件夹,这个文件夹里面有 challenge.md,即为题面;附件也放在其中。「harness」定义为模型 + agent 的组合体,用 docker 封装。于是,做题过程就是:启动一个 docker,把题目文件夹挂载进去,要求 harness 做题,把答案写入 flag.txt ,解题过程写入 writeup.md 。
当然,用户可以将题目定义为其他含义——例如,定义为「BUUOJ 的一个题目 ID」。此时,做题过程就是 agent 获取靶机、攻击靶机、提交 flag。另外,harness 的定义也可以更改。举个例子,用户写了几套 sql 注入的 SKILL.md,想要测出哪一套 skill 最好,则可以将 harness 定义为「模型 + agent + skill」的组合体。
0x02 细节
笔者暂且只关心附件题,不关心靶机题,所以选了 10 道 misc 和密码学题目。至于 harness,笔者选择 opencode 和 claude code。本文要测的模型有 5 个,所以最终会执行 $5\times 2 \times 10 = 100$ 次解题过程。用户也可以选择多次运行测试,以获得更稳定的结果。
我们用 docker 封装 harness,具体交互方式是:把题目挂载到 /work,运行 /harness.sh,进程退出后,读出题目目录下的 flag.txt。为了提供足够的工具,采用 kali 镜像作为基础。
所以,我们需要让 AI 先去构建几个镜像:
- 构建 kali 镜像。根据 kali 官方文档,kalilinux/kali-rolling 这个 image 其实并没有自带工具,我们要执行
apt update && apt -y install kali-linux-headless安装一些基础工具。 - 构建 opencode 和 claude code 镜像。它们都基于 kali 镜像,自带 agent 和
harness.sh。
可想而知,AI 极有可能无法一次性完成配置。所以我们得给 AI 一个最简单的例题,以便验证 harness 是否配置成功。笔者选择了一个 base64 解码题目。
有了「启动即做题」的 docker 之后,我们要跑起来这 100 个解题实例。笔者要 AI 写了三个脚本:
- prepare.py,负责准备 100 个实例文件夹,每个文件夹里有 compose 文件和题目目录
- work.py,负责运行实例,允许中途停止后再次运行。所有还未产出 flag.txt 的实例将被运行。
- collect.py,负责收集结果。
为方便起见,我们直接采用文件系统来保存状态。每个实例有一个文件夹,结构如下:
run/qwen3-9b-opencode-example/
├── docker-compose.yml
├── end_time
├── meta.json
├── start_time
└── work
├── challenge.md
├── flag.txt
└── harness.log我们采用 meta.json 保存一些元信息,用 start_time 和 end_time 文件记录 docker 启动和结束的时间,供 collect.py 使用。
0x03 成品
成品见 7Hxz233/CTF-Agent-Measure 项目。读者可以把 SPEC.md 拷贝下来,然后要 agent 加以实现;或者,也可以直接采用笔者现成的参考实现。