Imtnk/ctf-toolkit
GitHub: Imtnk/ctf-toolkit
一个面向 CTF 比赛的 AI Agent 工具链,结合本地/远程大语言模型与安全分析工具,通过 ReAct 循环自动化完成题目分类、文件分析和漏洞识别等任务。
Stars: 0 | Forks: 0
# CTF 工具链 — Mac 模型服务器
这台 Mac (M3 Pro, 18 GB) 运行 **Ollama** 并通过局域网向运行实际 CTF 工具的 Kali WSL2 环境提供模型服务。
## 模型
| 模型 | 角色 | 大小 |
|---|---|---|
| `deepseek-r1:14b` | **主力** — 链式推理,CTF 甄别 | ~9 GB |
| `qwen2.5-coder:14b` | 专注代码的备选方案 | ~9 GB |
| `dolphin-llama3:8b` | 无审查备选(在遇到拒绝时自动触发) | ~5 GB |
| `nomic-embed-text` | Embeddings(原有) | 274 MB |
考虑到操作系统的内存预留空间,RAM 中只能容纳一个 14B 模型。使用 `switch-model.sh` 进行切换。
## 快速开始
```
brew services list | grep ollama # Ollama runs as a launchd service (auto-starts at login)
curl -s http://localhost:11434 # → "Ollama is running"
ipconfig getifaddr en0 # LAN IP for Kali (currently 192.168.1.11; DHCP — may drift)
```
## `ai.py` — 单次执行与 agent 模式
### `ai` — 菜单与快捷方式
`ai-ui.py` 是一个轻量级启动器,别名为 **`ai`**(位于 `~/.bashrc` 和 `~/.zshrc` 中)。直接执行
`ai` 会打开一个交互菜单(询问 / 运行 agent / 恢复,并带有本地与远程大脑切换、自动批准以及 dry-run 开关);任何参数都将直接传递给 `ai.py`:
```
ai # interactive menu (shows the current brain)
ai "find the vulnerability" # one-shot passthrough
ai agent "triage ./chal" # agent passthrough (all ai.py flags work)
```
### 单次执行(向后兼容)
```
echo "solve this RSA: n=... e=... c=..." | python3 ai.py
cat challenge.py | python3 ai.py "find the vulnerability"
python3 ai.py "what does XOR with a repeating key look like in ciphertext?"
```
向 Ollama 发送单个 prompt 并打印回复。不使用工具,不进行循环。
### Agent 模式 — 包含工具的 ReAct 循环
```
python3 ai.py agent "what type is ./chal and what are its strings?"
python3 ai.py agent --approve auto "triage ./chal — architecture, protections, interesting strings"
python3 ai.py agent --dry-run "what would you do with ./chal?"
python3 ai.py agent -m dolphin "exploit the vuln in ./vuln.py"
cat chal.py | python3 ai.py agent "find and explain the vulnerability"
# 恢复崩溃或中断的运行
python3 ai.py agent --resume
python3 ai.py agent --resume .agent/run-20260721-143022.jsonl
```
| 标志 | 默认值 | 含义 |
|---|---|---|
| `-m / --model` | 大脑默认值 | 使用指定的 **本地** Ollama 模型 id 覆盖 |
| `--local` | 关 | 强制使用本地 Ollama 大脑,而不是远程 gateway |
| `--approve auto` | 手动 | 跳过非白名单命令的提示 |
| `--dry-run` | 关 | 显示计划执行的命令;不实际执行任何内容 |
| `--max-steps` | 15 | 触发软预算提示前的步数 |
| `--resume [FILE]` | — | 恢复最新(或指定)的 `.agent/*.jsonl` 记录 |
## 大脑:远程 gateway 对比本地 Ollama
Agent 的**大脑**(推理)与其**双手**(`agent/tools.py`,用于运行实际子进程)是解耦的。默认情况下,大脑是运行在**兼容 OpenAI 的 gateway** 上的大型托管模型;本地计算机仍然负责执行每一个工具。本地的 `dolphin-llama3:8b` 依然作为拒绝时的备选方案。
| 环境变量 | 默认值 | 含义 |
|---|---|---|
| `CTF_REMOTE_API_KEY` | *(未设置)* | **密钥。** gateway 的 Bearer 密钥。从 `~/.config/ctf-toolchain/secrets.env`(chmod 600,位于此仓库之外)读取。切勿提交。 |
| `CTF_REMOTE_MODEL` | `qwen3.6-35b-a3b` | 远程模型 id |
| `CTF_REMOTE_BASE_URL` | `https://gateway.9arm.co/v1` | 兼容 OpenAI 的 base URL (`POST {base}/chat/completions`) |
| `CTF_BRAIN` | `remote` | 设置为 `local` 可全局强制使用 Ollama 大脑 |
| `CTF_AI_HOST` | `localhost` | 用于本地大脑 / 备选方案的 Ollama 主机 |
**选择规则:** 当存在密钥,且未使用 `CTF_BRAIN=local`、`--local` 或 `-m ` 时,将使用远程大脑。如果没有密钥,则会降级为本地 `deepseek-r1:14b`(会打印一次警告);如果 Ollama 也无法访问,`ctf-eval` 将进一步降级为其离线启发式算法。
一次性密钥设置(请自行粘贴真实密钥——它永远不需要经过其他任何人的手):
```
printf 'export CTF_REMOTE_API_KEY=%q\n' 'sk-REAL' >> ~/.config/ctf-toolchain/secrets.env
# secrets.env 被 chmod 600 并通过 ~/.bashrc 和 ~/.zshrc 引入
```
## Agent 循环
每一轮:**模型 → JSON `{thought, tool, args}` → 批准 → 执行 → 观察 → 重复**
### 工具
| 工具 | 批准级别 | 用途 |
|---|---|---|
| `run_shell(cmd)` | 白名单 / 询问 / 拒绝 | Shell 命令;逐行流式传输输出 |
| `python_exec(code)` | 询问(扫描黑名单) | Python 代码片段;pwntools/pycryptodome/z3 |
| `read_file(path)` | 自动(只读) | 文本文件,8 KB 上限 |
| `write_file(path, text)` | 总是 diff+确认 | 在任何写入之前显示 Diff |
| `list_dir(path)` | 自动 | 包含大小的目录列表 |
| `file_info(path)` | 自动 | `file` 命令 + 大小 + SHA-256 |
| `hexdump(path, n)` | 自动 | 前 n 字节,hex+ASCII |
| `strings(path, min_len)` | 自动 | 可打印字符串(系统 `strings` + Python 备选) |
| `http_request(method, url, …)` | 询问 | 通过 urllib 发起的 Web 挑战请求 |
| `finish(answer)` | — | 结束循环;首先触发验证步骤 |
### 批准级别
1. **自动**(白名单) — `file`, `strings`, `ls`, `cat`, `grep`, `hexdump`, `nmap`, `objdump`, `readelf`, `binwalk`(不带 `-e`), `base64`, `openssl` 检查操作, … — 静默运行
2. **询问** — 其他所有命令;提示显示 `[y] once / [a] always / [N] deny`;"a" 会将前缀规则附加到会话白名单中
3. **拒绝**(黑名单) — `rm -rf`, `sudo`, `curl|sh`, `dd of=/dev/`, fork 炸弹, `shred` — 即使在 `--approve auto` 下也会被强制阻止
### 循环防护
- **重复检测** — 重复的工具+参数哈希 → 注入“你刚才已经运行过此命令”并跳过
- **无进展启发式** — 3 次连续的空/重复观察 → 暂停提示
- **软预算** — 到达 `--max-steps` 时:继续 10 步 / 停止 / 注入提示 / 输入答案
- **运行中干预** — 随时输入并按回车键;将作为 `[user hint]` 注入,无需重启
- **完成前验证** — 提出的答案将经过单独的分类调用
- **拒绝备选** — 通过干净上下文的分类器调用检测拒绝(不是对工具输出进行子字符串匹配);自动切换到 `dolphin-llama3:8b`
### 上下文管理
- 固定的事实(任务、flag 格式、确认的发现)在截断后依然保留
- 消息超过 40 条时会被修剪;最后 12 条将与固定块一起保留
- 类似 flag 的字符串 (`WORD{...}`) 会自动从观察结果中提取并存入固定发现中
### 记录与恢复
每一步都会追加到 `.agent/run-YYYYMMDD-HHMMSS.jsonl`。`--resume` 会重新加载消息历史并继续。恢复时会全新构建系统 prompt(目录更改将生效)。
## 辅助脚本
```
./switch-model.sh deepseek # load deepseek-r1:14b (primary)
./switch-model.sh coder # load qwen2.5-coder:14b
./switch-model.sh dolphin # load dolphin-llama3:8b (uncensored / RAM-saver)
./switch-model.sh status # ollama ps + ollama list
./start-ollama.sh # start service, confirm localhost + LAN reachable
./stop-ollama.sh # stop service to free RAM (e.g. before Ghidra)
./test-server.sh # health check: reachable, models present, generation works
./test-server.sh 192.168.1.11 # same check from Kali over LAN
```
## 从 Kali 环境
将 Kali 端的辅助工具指向局域网内的 Mac。`ai.py` 和 agent 会读取
**`CTF_AI_HOST`** 环境变量(默认为 `localhost`),因此无需修改代码:
```
export CTF_AI_HOST=192.168.1.11 # Mac's LAN IP (DHCP — may drift; see below)
python3 ai.py agent "triage ./chal"
```
有关连接设置和测试,请参阅 `[[local-ai-ctf-setup]]` 第 07–08 节。
## 架构
```
ctf-toolchain/
ai.py # CLI: one-shot (unchanged) + agent subcommand
agent/
config.py # host / model / limits
llm.py # Ollama /api/chat wrapper
protocol.py # JSON extractor (handles tags, ```json fences, nested braces)
tools.py # tool registry (10 tools, streaming run_shell + python_exec)
approval.py # three-tier gate + session-learned allowlist + check_write diff
loop.py # ReAct loop (all guards, steering, truncation, transcript writes)
transcript.py # .agent/*.jsonl write + load_resume
refusal.py # clean-context refusal classifier + dolphin fallback
context.py # pinned-facts + maybe_truncate
switch-model.sh
start-ollama.sh / stop-ollama.sh
test-server.sh
AGENT-PLAN.md # original implementation plan
```
依赖项:**仅标准库**(`urllib`, `json`, `subprocess`, `threading`, `select`, `difflib`)。
CTF 的强大能力源于通过 shell 调用已安装的工具集(pwntools, pycryptodome, z3, binwalk, …)。
标签:AI智能体, AI风险缓解, DLL 劫持, LLM评估, Ollama, 大语言模型, 应用安全, 本地部署, 逆向工具