hllttz/ctf-solving-agent
GitHub: hllttz/ctf-solving-agent
Stars: 0 | Forks: 0
# ctf-agent
`ctf-agent` 是一个用 Go 编写的本地 CTF 解题代理。它会为每个 solver 创建隔离的 Docker sandbox,把题目附件挂载进去,然后让一个或多个模型并行尝试解题。多个 solver 之间可以通过消息总线共享发现,operator 也可以在运行中发送提示、查看状态、终止或手动启动本地题目。
当前版本专注于本地题目目录和手工输入题目。solver 找到 flag 后会通过 `report_flag` 记录结果。
## 功能概览
- 多模型并发:同一道题可以同时由多个模型求解,先找到 flag 的结果胜出。
- Docker sandbox:题目附件只读挂载到 `/challenge/distfiles`,工作目录挂载到 `/workspace`。
- 本地题目工作流:支持已有题目目录,也支持用靶机地址和附件快速创建题目。
- 跨 solver 协作:solver 可以 `post_finding`、`notify_coordinator`,其他 solver 会周期性收到共享发现。
- operator 控制:运行中可通过本地 HTTP 接口查看状态、广播提示、定向 bump、kill、读取 trace、启动本地题目。
- 成本与 trace:记录模型 token usage、估算成本,并把工具调用、模型响应和 usage 写入 `logs/*.jsonl`。
## 环境要求
- Go 1.24+
- Docker
- 已构建的 sandbox 镜像
- 至少一个模型 provider 的 API Key
构建 sandbox:
docker build -f sandbox/Dockerfile.sandbox -t ctf-sandbox .
## 题目目录格式
已有题目推荐放在 `./challenges//` 下:
challenges/
baby-web/
metadata.yml
distfiles/
source.zip
workspace/ # 不存在时会自动创建
`metadata.yml` 示例:
name: baby-web
category: web
description: Find the flag in the web service.
connection_info: http://example.com:8080
files:
- source.zip
常用字段:
name: chall-name
category: pwn # web / pwn / rev / crypto / forensics / misc
description: ...
value: 500
connection_info: nc host 31337
tags:
- heap
hints:
- content: check the login flow
也兼容 `host`、`port`、`service_type` 字段。若存在连接信息,prompt 会要求 solver 第一步优先探测远端服务。
## 使用方法
### 1. 手工创建并求解题目
只有附件和靶机地址时,直接使用 `run`:
go run ./cmd/ctf-agent run --target "nc host 31337" --file ./chall.zip --category pwn --name baby-pwn
Web 题目:
go run ./cmd/ctf-agent run --target "http://host:8080" --file ./source.zip --category web --name baby-web
`run` 会在 `CHALLENGES_DIR`,默认 `./challenges`,下创建题目目录,复制附件到 `distfiles/`,写入 `metadata.yml`,然后启动求解。
`run` 不会进入交互式输入;靶机地址用 `--target` 传入,附件用 `--file` 传入。
### 2. 求解单个已有题目
go run ./cmd/ctf-agent single ./challenges/baby-web
### 3. 求解目录下所有题目
go run ./cmd/ctf-agent solve ./challenges
`solve` 会扫描所有包含 `metadata.yml` 的子目录,并按 `MAX_CONCURRENT_CHALLENGES` 控制并发题目数。每道题内部仍会按 `MODEL_SPECS` 启动多个 solver。
启动时会打印本次使用的题目路径、模型列表、sandbox 镜像和 operator 地址。若 `MODEL_SPECS` 里包含未配置 API Key 的 provider,程序会在创建 sandbox 前直接报错,例如提示缺少 `OPENAI_API_KEY` 或 `DEEPSEEK_API_KEY`。
## 模型配置
通过环境变量配置模型和密钥:
export MODEL_SPECS=openai/gpt-5.4,anthropic/claude-opus-4-6
export OPENAI_API_KEY=...
export ANTHROPIC_API_KEY=...
export GEMINI_API_KEY=...
export DEEPSEEK_API_KEY=...
只使用 DeepSeek:
export MODEL_SPECS=deepseek/deepseek-v4-flash
export DEEPSEEK_API_KEY=...
默认模型:
claude-sdk/claude-opus-4-6
claude-sdk/claude-sonnet-4-6
openai/gpt-5.4
支持的 provider 前缀:
- `openai/...`
- `anthropic/...`
- `claude-sdk/...`
- `gemini/...`
- `google/...`
- `deepseek/...`
- `codex/...`,走 OpenAI 兼容路径
如果使用 OpenAI 兼容代理,可以设置:
export OPENAI_BASE_URL=https://proxy.example.com/v1/chat/completions
DeepSeek 默认使用 `https://api.deepseek.com/chat/completions`。如果需要代理或私有网关:
export DEEPSEEK_BASE_URL=https://proxy.example.com
## 其他配置
export SANDBOX_IMAGE=ctf-sandbox
export CONTAINER_MEMORY_LIMIT=16g
export MAX_CONCURRENT_CHALLENGES=10
export CHALLENGES_DIR=./challenges
export SKILLS_DIR=./skills
export MSG_ADDR=127.0.0.1:0
说明:
- `SANDBOX_IMAGE`:Docker sandbox 镜像名。
- `CONTAINER_MEMORY_LIMIT`:每个 solver 容器的内存限制。
- `MAX_CONCURRENT_CHALLENGES`:同时求解的题目数量上限。
- `MODEL_SPECS`:逗号分隔的 solver 模型列表。
- `SKILLS_DIR`:额外 prompt 技能目录。每道题只会注入 `common.md` 和匹配题目分类的 `{category}.md`。
- `MSG_ADDR`:operator HTTP 服务监听地址,默认随机端口。
## Operator 接口
运行 `solve` 时会启动本地 operator HTTP 服务,日志里会显示地址,例如:
operator message server listening on http://127.0.0.1:9400/msg
常用接口:
# 查看当前状态、结果、成本、usage
curl http://127.0.0.1:9400/status
# 给所有运行中的 swarm 广播提示
curl -X POST http://127.0.0.1:9400/msg \
-H 'Content-Type: application/json' \
-d '{"message":"优先检查 /admin 和 JWT secret"}'
# 给指定题目广播提示
curl -X POST http://127.0.0.1:9400/broadcast \
-H 'Content-Type: application/json' \
-d '{"challenge":"baby-web","message":"重点看 cookie 签名"}'
# 定向 bump 某个模型
curl -X POST http://127.0.0.1:9400/bump \
-H 'Content-Type: application/json' \
-d '{"challenge":"baby-web","model":"openai/gpt-5.4","insights":"其他 solver 发现存在 SSTI"}'
# 终止某道题的 swarm
curl -X POST http://127.0.0.1:9400/kill \
-H 'Content-Type: application/json' \
-d '{"challenge":"baby-web"}'
# 启动一个本地已有题目
curl -X POST http://127.0.0.1:9400/spawn \
-H 'Content-Type: application/json' \
-d '{"challenge":"baby-web"}'
# 读取最近 trace
curl 'http://127.0.0.1:9400/trace?challenge=baby-web&model=gpt-5.4&last=40'
`/spawn` 只接受本地 `CHALLENGES_DIR//metadata.yml` 已存在的题目。
## Solver 工具
solver 可用工具包括:
- `bash`:在 sandbox 内执行命令。
- `read_file` / `write_file` / `list_files`:读取、写入、列目录。
- `view_image`:识别图片文件并给出分析建议。
- `web_fetch`:从宿主侧发 HTTP 请求,默认阻止内网/private IP。
- `webhook_create` / `webhook_get_requests`:创建和读取 webhook.site 回连请求。
- `post_finding` / `check_findings`:跨 solver 分享发现。
- `notify_coordinator`:向 coordinator/operator 通知重要发现。
- `report_flag`:记录最终 flag。
## 输出、日志与成本
运行结束后会输出:
- 每道题状态。
- 找到的 flag 和方法。
- step 数。
- trace 文件路径。
- 成本汇总。
trace 写入 `logs/trace---.jsonl`,包含:
- `start`
- `tool_call`
- `tool_result`
- `model_response`
- `usage`
- `bump`
- `finish`
- `error`
成本估算来自模型响应里的 token usage。若 provider 没返回 usage,该次调用不会计入成本。
## 开发与测试
普通测试:
go test ./...
如果默认 Go build cache 不可写,可以使用项目内 cache:
GOCACHE=$PWD/.cache/go-build \
GOMODCACHE=$PWD/.cache/go-mod \
go test ./...
标签:EVTX分析