sondt99/ctf-bot
GitHub: sondt99/ctf-bot
一款面向 CTF 团队的 Discord 机器人,集成赛事管理、挑战追踪、实时记分牌轮询和消息统计,一站式解决比赛协作的组织难题。
Stars: 1 | Forks: 0
# Discord CTF Bot
一个用于组织 Capture The Flag 比赛的 Discord bot。它集成了 CTFtime 来获取赛事信息,为每个赛事创建专属分类和频道,通过线程跟踪各项挑战,并对 CTFd 和 rCTF 平台的实时记分牌进行轮询。
## 文档
- [架构](docs/architecture.md) — 组件概述与数据流
- [数据库](docs/database.md) — schema、表、迁移和 repository API
- [开发](docs/development.md) — 本地设置、测试与类型检查
- [部署](docs/deployment.md) — Docker、systemd 与环境变量参考
## 功能
- **CTFtime 集成** — 通过分页浏览并加入即将举行的 CTF 赛事
- **挑战管理** — 为每个挑战创建线程,批量导入 CTFd 挑战,跟踪已解决/开放状态
- **实时记分牌** — 定期轮询,并针对 CTFd 和 rCTF 的变化发送通知
- **消息统计** — 用户排行榜、活跃度分析以及历史数据回填
- **多赛事支持** — 同时运行多个 CTF,每个赛事都有各自的分类
- **基于角色的权限控制** — `@ctf` 角色的成员可以将挑战标记为已解决;管理员命令仅限管理员使用
- **审计日志** — 自动创建私有的 `BOT` 分类,包含命令日志和手动数据库备份
## 要求
- Python 3.11+
- 带有[所需 intents](#permissions) 的 Discord bot token
## 设置
```
# 1. 克隆并配置
cp .env.example .env
# 编辑 .env 并设置 DISCORD_TOKEN
# 2. 安装依赖
pip install -r requirements.txt
# 3. 运行 bot
python -m bot.main
```
## Docker 部署
```
# 1. 复制并编辑 env 文件
cp .env.example .env
# 编辑 .env:设置 DISCORD_TOKEN,可选 FERNET_KEY 等
# 2. 启动 bot
docker compose up -d
# 3. 查看日志
docker compose logs -f bot
# 4. 升级(在 git pull 之后)
docker compose build --pull && docker compose up -d
```
SQLite 数据库存储在一个命名的 Docker volume (`bot_data`) 中,因此它会在重启和容器升级后保留。
## 环境变量
| 变量 | 必需 | 默认值 | 描述 |
|---|---|---|---|
| `DISCORD_TOKEN` | 是 | — | Discord bot token |
| `DATABASE_PATH` | 否 | `ctf_bot.db` | SQLite 数据库文件的路径 |
| `SCOREBOARD_POLL_SECONDS` | 否 | `30` | 记分牌轮询间隔(秒) |
| `SCOREBOARD_TOP_N` | 否 | `10` | 记分牌更新中显示的队伍数量 |
| `SCOREBOARD_TEAM_NAME` | 否 | — | 你的队伍名称(用于记分牌跟踪) |
| `TIMEZONE` | 否 | `UTC+7` | 赛事显示的时区 — IANA 名称 (`Asia/Ho_Chi_Minh`) 或偏移量 (`UTC+7`) |
| `CTF_REMOVE_PASSWORD` | 否 | — | `/ctf remove` 所需的密码 |
| `DISCORD_GUILD_ID` | 否 | — | Guild ID,用于实现更快的斜杠命令同步 |
| `FERNET_KEY` | 否 | — | 用于对静态认证 token 进行加密的 Fernet key(使用 `python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"` 生成) |
## 命令
### CTF 赛事
| 命令 | 描述 | 权限 |
|---|---|---|
| `/ctf upcoming [limit]` | 浏览 CTFtime 上即将举行的 CTF | 所有人 |
| `/ctf running [limit]` | 列出 CTFtime 上当前活跃的 CTF | 所有人 |
| `/ctf archive [limit] [days]` | 列出最近结束的 CTF(默认:过去 30 天) | 所有人 |
| `/ctf join ` | 为赛事创建分类和频道(自动创建 `@ctf` 角色) | 管理员 |
| `/ctf list` | 列出已加入的 CTF 及其 event ID | 所有人 |
| `/ctf progress [event_id]` | 显示挑战进度及各分类详情 | 所有人 |
| `/ctf export [event_id] [format]` | 将挑战数据导出为 JSON 或 CSV | 所有人 |
| `/ctf hidden [event_id]` | 向非管理员隐藏 CTF 分类 | 管理员 |
| `/ctf remove [event_id] password` | 删除 CTF 分类及所有相关数据 | 管理员 |
### 挑战
| 命令 | 描述 | 权限 |
|---|---|---|
| `/challenge ` | 为挑战创建一个线程(必须在 topic 频道中执行) | 所有人 |
| `/challenge-fetch [auth_token]` | 获取 CTFd 挑战,将 CTFd 分类映射到 topic 频道,创建缺失的线程,并仅在描述/文件更改时刷新 CTFd embed | 管理员 |
| `/done [solver2] ...` | 将挑战标记为已解决并重命名线程 | 管理员 / `@ctf` 角色 |
| `/challenges [event_id]` | 列出所有挑战及其状态和线程链接 | 所有人 |
| `/remove-challenge` | 取消跟踪当前挑战(保留线程) | 管理员 |
### 记分牌
| 命令 | 描述 | 权限 |
|---|---|---|
| `/scoreboard [auth_token] [team] [event_id]` | 配置记分牌轮询(`CTFd` 或 `rCTF`) | 管理员 |
| `/scoreboard_list` | 显示活跃的记分牌配置 | 所有人 |
| `/scoreboard_remove ` | 移除记分牌配置 | 管理员 |
### 统计
| 命令 | 描述 | 权限 |
|---|---|---|
| `/stats leaderboard [limit] [channel]` | 按消息数排名的顶级用户 | 所有人 |
| `/stats user ` | 用户个人的消息统计、排名和活跃频道 | 所有人 |
| `/stats sync [limit] [channel]` | 将历史消息回填到统计中 | 管理员 |
## 工作流
```
1. /ctf join → Bot creates category with topic channels
2. /challenge-fetch [token]
→ Bot asks how to map CTFd categories, then imports into topic threads
3. Or go to a topic channel and run /challenge for manual threads
4. Work on the challenge in the thread
5. /done @solver → Mark solved, thread renamed to [DONE]
6. /challenges → Overview with clickable thread links
```
## 加入时创建的频道
每个 CTF 赛事都会获得一个以该赛事命名的 Discord 分类,其中包含:
```
account — read-only info channel
general — general discussion
rev — reverse engineering
pwn — binary exploitation
web — web challenges
crypto — cryptography
for — forensics
misc — miscellaneous
scoreboard — live scoreboard updates
```
## BOT 管理员分类
在启动时,bot 会创建一个仅管理员可见的私有 `BOT` 分类:
- **#log** — 命令使用日志
- **#backup** — 由 `/backup` 创建的数据库上传
## 权限
该 bot 需要以下 Discord 权限:
| 权限 | 原因 |
|---|---|
| Manage Channels | 创建分类、频道和线程 |
| Create Public Threads | 挑战线程 |
| Read Message History | `/stats sync` 数据回填 |
| Send Messages | 创建线程及回复 |
| Embed Links | 所有 bot 回复均使用 embed |
| Manage Roles | (可选)如果你希望 bot 管理 `@ctf` 角色 |
**所需 intents**(在 Discord Developer Portal 中启用):
- Server Members
- Message Content(如果将来使用前缀命令)
## 注意事项
- 必须在服务器中手动创建 `@ctf` 角色,`/done` 权限才能生效。
- `/challenge-fetch` 每次运行时都会询问分类映射,因此在赛事中途添加的新的 CTFd 分类可以在导入前进行路由。
- 现有的 CTFd 挑战线程仅在描述或文件链接发生更改时才会更新;仅分数/解答数量的变化将被忽略。标记为 `/done` 的线程不会被更新。
- `/challenge-fetch` 接受完整的 CTFd URL (`http://localhost:8000`) 或仅主机的 URL (`localhost:8000`)。
- 消息统计仅跟踪 bot 部署后发送的消息,除非你运行 `/stats sync`。
- rCTF 的记分牌轮询直接使用公共 API — 不需要浏览器依赖。
- 该 bot 使用 SQLite。在生产环境中使用时,请确保数据库文件位于持久化的 volume 中。
标签:Discord, Docker, Python, 团队协作, 安全防御评估, 无后门, 请求拦截, 逆向工具