ctfpilot/challenge-schema
GitHub: ctfpilot/challenge-schema
CTF Pilot 的竞赛题目 Schema 规范,以结构化的 YAML/JSON 格式统一描述 CTF 挑战赛题目信息并支持自动化部署。
Stars: 1 | Forks: 1
# CTF Pilot 挑战赛 Schema
此 schema 定义了描述 CTF 挑战赛的结构。它确保了挑战赛描述的统一格式,并包含了实现自动化所需的所有必要信息。
此 schema 同时支持 YAML 和 JSON 版本。本 README 记录了每个受支持的字段,并列出了所有允许的值,以便维护者和挑战赛作者拥有统一的参考标准。
有关 schema 的使用示例,请参阅 [示例](./examples) 目录。
## 快速参考
schema 是一个对象。挑战赛至少应包含以下字段:
- `enabled` (布尔值) - 挑战赛是否启用。默认值:`true`。
- `name` (字符串) - 人类可读的挑战赛名称。
- `slug` (字符串) - 对机器友好的 slug。必须匹配正则表达式 `^[a-z0-9-]+$`。
- `author` (字符串) - 挑战赛的作者或所有者。
- `category` (字符串) - [查看允许的值](#allowed-enumerations-and-constraints)。
- `difficulty` (字符串) - [查看允许的值](#allowed-enumerations-and-constraints)。
- `tags` (字符串数组,可选) - 自由格式的标签。
- `type` (字符串) - `static` | `shared` | `instanced`。
- `instanced_type` (字符串,可选) - `web` | `tcp` | `none`(对 `instanced` 类型的挑战赛很有用)。
- `flag` (字符串 | 数组 | 对象数组) - 一个或多个 flag(参见 Flags 部分)。
- `points` (整数,可选) - 初始分值 (1..10000)。默认 1000。
- `min_points` (整数,可选) - 最低分值 (1..1000)。默认 100。
请在[字段参考](#field-reference-structure-and-examples)中查看所有值类型。
## 允许的枚举与约束
以下是 schema 和工具使用的显式允许值。
- `category`(以下之一):
- `web`
- `forensics`
- `rev`
- `crypto`
- `pwn`
- `boot2root`
- `osint`
- `misc`
- `blockchain`
- `mobile`
- `test`
- `difficulty`(以下之一):
- `beginner`
- `easy`
- `easy-medium`
- `medium`
- `medium-hard`
- `hard`
- `very-hard`
- `insane`
- `type`(以下之一):
- `static` - 挑战赛是静态工件(文件、解谜等)。
- `shared` - 外部网络服务;可能需要 `connection` 字符串。实例由所有团队共享。
- `instanced` - 为每个团队/服务启动一个实例(参见 `instanced_type`)。
- `instanced_type`(以下之一):
- `web` - HTTP/web 实例。
- `tcp` - 基于 TCP/端口的普通实例。
- `none` - 非实例化 / 没有特殊的实例行为。
- `tags`:每个标签都是一个字符串,且应匹配正则表达式:`^[a-zA-Z0-9-_:;? ]+$`(允许字母、数字、连字符、下划线、冒号、分号、问号和空格)。
- `slug`:必须匹配 `^[a-z0-9-]+$`,最小长度为 1,通常最大长度为 50(权威限制请参见 schema 文件)。
- `points`:介于 1 和 10000 之间(包含)的整数。默认 1000。
- `min_points`:介于 1 和 1000 之间(包含)的整数。默认 100。
## 字段参考(结构与示例)
- `version` (字符串,可选) - schema 版本(例如 `1.0.0` 或 `1`)。完全可选;如果省略,则假定使用最新的 schema 版本。
- `enabled` (布尔值) - 挑战赛是否处于活动状态。
- `name` (字符串) - 例如 "Demo Challenge"。
- `slug` (字符串) - 例如 `demo-challenge`。
- `author` (字符串) - 例如 `The Mikkel`。
- `category` (字符串) - 参见上文枚举。
- `difficulty` (字符串) - 参见上文枚举。
- `tags` (字符串数组,可选) - 例如 `["demo", "example"]`。
- `type` (字符串) - `static`、`shared` 或 `instanced`。
- `instanced_type` (字符串,可选) - `web`、`tcp` 或 `none`。
- `instanced_name` (字符串,可选) - 实例化挑战赛的 slug。如果省略,通常使用挑战赛的 `slug`。
- `instanced_subdomains` (字符串数组,可选) - 用于实例化 web 挑战赛的子域名列表。
每个条目可以选择以 `web:` 或 `tcp:` 为前缀(例如 `web:api`、`tcp:service`,或者直接写 `admin`)。前缀指示与子域名关联的协议。所有条目必须匹配模式 `^((web|tcp):)?[a-z0-9-]+$`。
- `connection` (字符串,可选) - 用于 `shared` 挑战赛的连接 URI 或 host:port 字符串(最大长度 255)。
- `flag` (字符串 | 数组 | 对象数组) - 参见 [Flags 部分](#flags)。
- `points` (整数,可选) - 解出后奖励的初始积分。
- `min_points` (整数,可选) - 动态计分的下限。
- `decay` (整数,可选) - 动态计分的衰减。默认值:`75`。
- `description_location` (字符串,可选) - 包含挑战赛描述的文件路径(例如 `description.md`)。
- `prerequisites` (字符串数组,可选) - 必须先完成的其他挑战赛 slug。
- `dockerfile_locations` (对象数组,可选) - 构建指令列表;每个对象包含:
- `context` (字符串) - 构建上下文目录
- `location` (字符串) - Dockerfile 的路径
- `identifier` (字符串 | null,可选) - 标识镜像的可选标签
- `handout_dir` (字符串,可选) - 包含分发文件的目录。
## Flags
`flag` 支持多种形式,以适应静态和高级工作流。
- 单个字符串 flag:
- 字符串 flag 数组:
- 对象数组(支持区分大小写和元数据):
每个 flag 元素可以是 `dynamic`、`null` 或普通的 flag 字符串。如果省略 `case_sensitive`,flag 检查将默认区分大小写。
### Flag 格式
默认的 flag 格式为 `flag{...}`。不过,schema 允许使用 2-10 个字符作为 flag 分隔符。例如 `FLAG[...]`、`CTF{...}`、`SECRET(...)` 等。
分隔符必须是单词字符(`a-z`、`A-Z`、`0-9`、`_`)。
如果你想为你的 CTF 设定固定的 flag 格式,可以 fork 该 schema 并修改 `schema.json` 文件中 `flag` 字段的正则表达式模式。找到 `flag` 属性并调整 `pattern` 属性以匹配你所需的格式。
flag 的最大长度为 1000 个字符(包含分隔符)。
## Dockerfile 位置
`dockerfile_locations` 是一个对象数组。示例:
这会告知自动化流程:在 `demo/` 上下文中,使用 `demo/Dockerfile`,并在提供 `identifier` 的情况下使用它来标记生成的镜像。
`identifier` 字段接受字符串或 `null`(即在 schema 中为 `"type": ["string", "null"]`)。使用 `null`、空字符串或字面值 `None` 来表示镜像标签“无后缀”。以下是不使用标识符/后缀的示例:
## 最小示例
## 完整示例(高级)
## 链接到 schema
在你的 YAML 文件中添加以下首行,以启用编辑器验证和自动补全:
```
# yaml-language-server: $schema=https://raw.githubusercontent.com/ctfpilot/challenge-schema/refs/heads/main/schema.json
```
在你的 JSON 文件中添加以下内容,以启用编辑器验证和自动补全:
```
{
"$schema": "https://raw.githubusercontent.com/ctfpilot/challenge-schema/refs/heads/main/schema.json"
}
```
*你可以将 URL 替换为指向本地 `schema.json` 的路径,或 GitHub 仓库中特定版本/发布版的路径,例如:`https://raw.githubusercontent.com/ctfpilot/challenge-schema/refs/tags/vX.X.X/schema.json`。*
## 注意事项与最佳实践
- 标识符和 `instanced_subdomains` 优先使用 `slug` 风格的名称(小写、连字符分隔)。
- 将 `points` 和 `min_points` 保持在规定的范围内,以避免自动化中出现验证失败。
- 当挑战赛 runtime 需要自定义镜像时,请使用 `dockerfile_locations`;如果存在多个镜像,请包含 `identifier`。
- 如果对某个字段的格式有疑问,请打开挑战赛文件夹中的规范文件 `schema.json` 进行查看。
## 许可证
此 schema 及代码仓库基于 **EUPL-1.2 License** 授权。
你可以在 **[LICENSE](LICENSE)** 文件中找到完整的许可证内容。
我们鼓励将所有的修改和贡献回馈给社区,例如通过向此仓库提交 pull request。
我们也鼓励所有的衍生作品在 **EUPL-1.2 License** 下公开可用。
任何时候都必须遵守许可条款。
有关如何做出贡献的信息,请参阅上方的[贡献](#contributing)部分。
CTF Pilot 由 **[The0Mikkel](https://github.com/The0mikkel)** 拥有并维护。
所需声明:版权所有 Mikkel Albrechtsen ()
## 行为准则
我们期望所有贡献者都能遵守我们的[行为准则](/CODE_OF_CONDUCT.md),以确保为所有人营造一个热情和包容的环境。
YAML
flag: flag{flag}JSON
"flag": "flag{flag}"YAML
flag: - flag{flag1} - flag{flag2}JSON
"flag": [ "flag{flag1}", "flag{flag2}" ]YAML
flag: - flag: flag{flag1} case_sensitive: true - flag: flag{flag2} case_sensitive: falseJSON
"flag": [ { "flag": "flag{flag1}", "case_sensitive": true }, { "flag": "flag{flag2}", "case_sensitive": false } ]YAML
``` dockerfile_locations: - context: demo/ location: demo/Dockerfile identifier: web ```JSON
``` "dockerfile_locations": [ { "context": "demo/", "location": "demo/Dockerfile", "identifier": "web" } ] ```YAML
``` dockerfile_locations: - context: demo/ location: demo/Dockerfile identifier: null ```JSON
``` "dockerfile_locations": [ { "context": "demo/", "location": "demo/Dockerfile", "identifier": null } ] ```YAML
``` enabled: true name: "Demo Challenge" slug: "demo-challenge" author: "The Mikkel" category: "misc" difficulty: "easy" type: "static" instanced_type: "none" flag: "flag{d3m0_fl4g}" points: 1000 min_points: 100 description_location: "description.md" ```JSON
``` { "$schema": "https://raw.githubusercontent.com/ctfpilot/challenge-schema/refs/heads/main/schema.json", "enabled": true, "name": "Demo Challenge", "slug": "demo-challenge", "author": "The Mikkel", "category": "misc", "difficulty": "easy", "type": "static", "instanced_type": "none", "flag": "flag{d3m0_fl4g}", "points": 1000, "min_points": 100, "description_location": "description.md" } ```YAML
``` enabled: true name: "Example Challenge" slug: "example-challenge" author: John Smith category: web difficulty: easy tags: - web - easy type: static instanced_type: none instanced_name: example-challenge instanced_subdomains: - example - test flag: - flag: flag{flag1} case_sensitive: true - flag: flag{flag2} case_sensitive: false points: 1000 min_points: 100 description_location: description.md prerequisites: - prerequisite-challenge dockerfile_locations: - location: src/web/Dockerfile context: src/web/ identifier: web - location: src/bot/Dockerfile context: src/bot/ identifier: bot handout_dir: handout connection: http://example.com ```JSON
``` { "$schema": "https://raw.githubusercontent.com/ctfpilot/challenge-schema/refs/heads/main/schema.json", "enabled": true, "name": "Example Challenge", "slug": "example-challenge", "author": "John Smith", "category": "web", "difficulty": "easy", "tags": [ "web", "easy" ], "type": "static", "instanced_type": "none", "instanced_name": "example-challenge", "instanced_subdomains": [ "example", "test" ], "flag": [ { "flag": "flag{flag1}", "case_sensitive": true }, { "flag": "flag{flag2}", "case_sensitive": false } ], "points": 1000, "min_points": 100, "description_location": "description.md", "prerequisites": [ "prerequisite-challenge" ], "dockerfile_locations": [ { "location": "src/web/Dockerfile", "context": "src/web/", "identifier": "web" }, { "location": "src/bot/Dockerfile", "context": "src/bot/", "identifier": "bot" } ], "handout_dir": "handout", "connection": "http://example.com" } ```标签:Homebrew安装, JSON Schema, SOC Prime, 安全, 开发工具, 数据规范, 请求拦截, 超时处理