Chumikov/CTFd-Skill
GitHub: Chumikov/CTFd-Skill
为 opencode 智能体打造的 CTFd 平台交互技能,提供挑战管理、flag 提交、持久化工作区等完整的玩家端 API 功能。
Stars: 0 | Forks: 0
# CTFd Skill
一个用于 [opencode](https://opencode.ai) 的技能 (skill),允许智能体通过统一的 REST 接口 (`/api/v1`) 与任何基于 **[CTFd](https://ctfd.io)** 引擎的 CTF 平台 API 进行交互。它可以帮助参与 CTF:任务列表、阅读说明、下载文件、提交 flag、解锁提示、查看排名和公告。
该技能面向**玩家** (player):涵盖普通账户可执行的操作,不包含管理员端点。
## 功能
- 列出并详细查看挑战(分类、分数、解答次数、“我是否已解答”)
- **提交 flag**,处理所有响应变体
(`correct` / `incorrect` / `already_solved` / `partial` / `ratelimited` / …)
- 遇到 `429` 时自动 backoff(CTFd 的防暴力破解机制)——客户端会自动从响应中读取等待的秒数并执行一次重试
- 通过已签名的 URL 下载附件
- 为每个任务提供**持久化工作区** (`~/Downloads/ctf////`) —— 文件、脚本和日志在重启后依然保留(而不是 `/tmp`)
- **解题进度日志** `NOTES.md` —— 自动追加带有日期的记录(假设/尝试/结果)
- **提示智能体优先使用 `hexstrike_*` MCP 工具**处理 offsec 任务(在上下文压缩后依然保留)
- 解锁提示和官方解答(考虑扣减分数)
- 排名、前 N 名、个人资料、团队资料
- 轮询组织者公告 (`since_id`)
- 管理个人的 API token(创建 / 列出 / 撤销)
- 通过 **API token** 进行授权(推荐)或使用账号/密码登录
- 适用于**任何** CTFd 实例 —— 不绑定特定的平台
## 环境要求
- [opencode](https://opencode.ai) ≥ 2.x
- Python 3.8+
- [`requests`](https://pypi.org/project/requests/) — `pip install requests`
## 安装说明
在 opencode 中,该技能的名称为 `ctfd-api`。本地目标目录**必须**命名为 `ctfd-api`(与 `SKILL.md` 中的 `name` 字段保持一致)。
### 方法 1 — 全局安装(推荐)
该技能将对当前用户的所有项目可用。
```
git clone https://github.com/Chumikov/CTFd-Skill ~/.config/opencode/skills/ctfd-api
```
### 方法 2 — 在特定项目中安装
将该技能放置在与其相关的 CTF 仓库旁边。
```
git clone https://github.com/Chumikov/CTFd-Skill .opencode/skills/ctfd-api
```
### 方法 3 — 通过 `opencode.jsonc`
如果该技能位于非标准目录下,请显式指定路径:
```
{
"$schema": "https://opencode.ai/config.json",
"skills": {
"paths": ["/абсолютный/путь/к/ctfd-api"]
}
}
```
### 方法 4 — 手动安装(不使用 git)
下载 [仓库压缩包](https://github.com/Chumikov/CTFd-Skill/archive/refs/heads/main.zip),
并将其解压到 `~/.config/opencode/skills/ctfd-api/`。
### 验证
安装完成后,运行 opencode —— `ctfd-api` 技能将出现在可用列表中。智能体会根据请求自动加载它(例如,当您输入“在任务 42 中提交 flag”时)。
## 配置
该技能需要两个值:实例的 host 和 API token。建议将它们放入环境变量中:
```
export CTFD_HOST="https://ctf.example.com"
export CTFD_TOKEN="ctfd_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```
token 在 Web 界面中创建:**Settings → Access Tokens → Generate**
(该值仅显示一次)。或者,也可以通过客户端自动生成(见下文)。
## 使用方法
### 通过 opencode 智能体
只需使用自然语言要求即可,例如:
- “显示 ctf.bug-makers.ru 上的任务列表”
- “打开任务 42 并下载它的文件”
- “在任务 42 中提交 flag `BugCTF{demo}`”
智能体会自动加载该技能并调用相应的方法。
### 直接从 Python 中使用
```
import sys
sys.path.insert(0, "scripts")
from ctfd_client import CTfdClient
c = CTfdClient.from_env() # читает CTFD_HOST / CTFD_TOKEN
print(c.list_challenges()) # список задач
detail = c.get_challenge(42) # условие, файлы, хинты
ws = c.init_challenge_workspace(detail) # персистентный воркспейс (НЕ /tmp)
for f in detail["files"]:
c.download_file(f) # → ws/attachments/ (dest_dir=None по умолчанию)
c.log_attempt(42, "Начало решения", "hypothesis") # запись в ws/NOTES.md
# ... 解决方案 (对于 offsec — 优先使用 hexstrike_* 工具,参见 SKILL.md §7a) ...
verdict = c.attempt(42, "BugCTF{example}") # {"status": "correct", ...}
c.log_attempt(42, "BugCTF{example}", "solved")
```
密码授权(如果没有 token):
```
c = CTfdClient.from_userpass("https://ctf.example.com", "username", "password")
```
### 通过 CLI
```
python scripts/ctfd_client.py challenges --host "$CTFD_HOST" --token "$CTFD_TOKEN"
python scripts/ctfd_client.py challenge 42 --host "$CTFD_HOST" --token "$CTFD_TOKEN"
python scripts/ctfd_client.py submit 42 'BugCTF{...}' --host "$CTFD_HOST" --token "$CTFD_TOKEN"
python scripts/ctfd_client.py me --host "$CTFD_HOST" --token "$CTFD_TOKEN"
python scripts/ctfd_client.py scoreboard --host "$CTFD_HOST" --token "$CTFD_TOKEN"
python scripts/ctfd_client.py top 10 --host "$CTFD_HOST" --token "$CTFD_TOKEN"
python scripts/ctfd_client.py hint 7 --host "$CTFD_HOST" --token "$CTFD_TOKEN"
python scripts/ctfd_client.py unlock-hint 7 --host "$CTFD_HOST" --token "$CTFD_TOKEN"
python scripts/ctfd_client.py notifications --since-id 5 --host "$CTFD_HOST" --token "$CTFD_TOKEN"
python scripts/ctfd_client.py gen-token --description "automation" --expiration 2026-12-31
python scripts/ctfd_client.py tokens
python scripts/ctfd_client.py revoke-token 3
```
完整的端到端演示场景(默认仅读取):
```
python examples/solve_flow.py
python examples/solve_flow.py --show-id 42
python examples/solve_flow.py --submit-id 42 --flag 'BugCTF{...}'
```
## 持久化工作区
为了让任务文件、解题脚本和解答日志**不会在重启后丢失**
(曾经有整个 CTF 周末的成果存放在 `/tmp` 中,结果被重启清空了),该技能会在 `~/Downloads/ctf/` 下为每个任务创建持久化结构:
```
~/Downloads/ctf////
├── challenge.yaml # метаданные CTFd (id, name, host, solved)
├── description.md # условие задачи
├── attachments/ # скачанные файлы (автоматически через download_file)
├── scripts/ # самописные solve-скрипты/эксплойты — запускать отсюда
└── NOTES.md # журнал хода решения (append через log_attempt)
```
- `` 从实例的 host 中提取(`nhnc.ic3dt3a.org` → `nhnc-2026`);
可通过环境变量 `CTFD_EVENT` 覆盖。
- `init_challenge_workspace(detail)` 会创建脚手架 + `description.md` + `NOTES.md` 标题。
- `download_file(f)` 如果不带 `dest_dir` 参数,文件会被放入 `attachments/`。
- `log_attempt(challenge_id, entry, status)` 会向 `NOTES.md` 追加带有日期的记录
(`status`:`hypothesis` / `tried` / `solved` / `failed`)。
临时的草稿文件(一次性的 `curl` 测试、解压的二进制文件等)依然会存放在 `/tmp` 中。自定义脚本则存放在工作区的 `scripts/` 目录下。
## 安全性
- **不要滥用 `submit`**。 CTFd 具有防暴力破解机制(每个账户+任务组合每分钟约允许 10 次错误提交,超过后触发 `429 ratelimited`)以及针对单个挑战的 `max_attempts` 和 `lockout` 模式 —— 胡乱盲猜可能会**永久**锁定您的任务。客户端能正确处理 `429`,但多余的错误尝试仍然会被记录在历史中。
- token 意味着对您账户的完全访问权限。请勿将其提交到代码仓库或泄露到聊天室中。
- `unlock-hint` 会从您个人或团队的账户中扣除真实的分数。
## 项目结构
```
CTFd-Skill/
├── SKILL.md # тело навыка для opencode
├── scripts/
│ └── ctfd_client.py # Python-клиент + CLI
├── examples/
│ └── solve_flow.py # демо: список → скачать → флаг
├── README.md # этот файл
├── LICENSE # MIT
└── .gitignore
```
## 兼容性
支持 CTFd 3.x,REST API v1。客户端逻辑是根据 CTFd 的源码 (`master`) 推导出来的,不调用任何第三方的非官方端点。
## 许可证
[MIT](LICENSE)。
标签:API客户端, CTF辅助, Python, 无后门, 网络调试, 自动化, 逆向工具