defojeco/ctfd-dynamic-values
GitHub: defojeco/ctfd-dynamic-values
CTFd插件,根据参赛者身份确定性地为每个用户或团队生成稳定的动态变量,用于在题目描述中嵌入个性化参数。
Stars: 0 | Forks: 0
# ctfd-dynamic-values — CTFd 的按参与者动态变量
[🇷🇺 俄语版本](README.ru.md)
在挑战中定义命名变量,这些变量是使用 token **掩码**,根据当前参与者的身份(用户/团队)加上可选的 salt,**确定性地生成**的。
在挑战描述中以 `{{name}}` 的形式引用它们——每个参与者都会看到他们自己的值,并且在刷新时保持不变(该值是输入的纯函数;不存储任何随机内容)。
典型用途:每个用户唯一的目标 IP 或端口、每个团队的子网、嵌入在任务文本中的按用户分配的 token。
## 安装说明
将此目录作为 `ctfd-dynamic-values` 放在 `CTFd/plugins/` 中:
```
CTFd/plugins/ctfd-dynamic-values/
├── __init__.py
├── generator.py
├── README.md
└── assets/
├── variables.js
└── variables.css
```
在 Docker stack 中,使用该名称挂载它:
```
- ./plugins/ctfd-dynamic-values:/opt/CTFd/CTFd/plugins/ctfd-dynamic-values:ro
```
重启 CTFd。启动时,插件会:
- 创建其数据表 (`dynamic_values`),
- 注册管理脚本,在挑战编辑器中添加 **Variables** 选项卡(位于 Files / Flags / Topics 旁边),
- 修补挑战的 `read()` 方法,以便为每个参与者替换描述中的 `{{name}}`,
- 发布 `app.dynamic_values_substitute` 用于可选的 flag 集成。
## 使用方法
1. 在管理后台打开一个挑战,转到 **Variables** 选项卡。
2. 添加变量:一个 **name** (`target_ip`),一个 **mask**,一个 **scope**,以及一个可选的 **salt**。使用 **Preview** 查看示例值。
3. 将 `{{target_ip}}` 放在挑战 **description** 中的任意位置。
4. 现在每个参与者都会看到自己生成的值,该值在刷新后保持稳定。
### Scope
| Scope | 值由…共享 |
|-----------|---------------------|
| `user` | 每个独立用户(默认) |
| `team` | 同一团队的所有人(如果没有团队则回退到按用户分配) |
| `global` | 所有人(整个挑战只有一个值) |
### Salt
混入 seed 的可选字符串。更改它可以轮换变量的所有生成值,而无需更改名称或掩码。如果不需要,请留空。
## Mask token
token 之外的所有内容都将按原样输出。token 从左到右消耗确定性熵。
| Token | 含义 |
|------------------|---------|
| `{A-B}` | 闭区间 `[A, B]` 内的整数(十进制) |
| `{N}` | `N` 个十进制数字 |
| `{xN}` / `{XN}` | `N` 个十六进制字符(小写/大写) |
| `{aN}` / `{AN}` | `N` 个字母(小写/大写) |
| `{wN}` | `N` 个字母和数字字符 `[a-zA-Z0-9]` |
| `\{` `\}` | 原样输出大括号 |
### 示例
| Mask | 示例输出 |
|-----------------------------------|-----------------|
| `10.{0-255}.{0-255}.{1-254}` | `10.137.42.200` |
| `{1024-65535}` | `49213` |
| `host-{x8}` | `host-3fa9c0b1` |
| `USER-{A6}` | `USER-KQWZPL` |
| `token_{w16}` | `token_yK1s0KqHHWq3aB9c` |
| `static-value-123` (无 token) | `static-value-123` (总是如此) |
## 确定性
seed 为 `sha256("|||")`,并扩展为用于掩码的无限字节流。范围使用无偏拒绝采样。
相同的输入 → 相同的输出,始终如此。这就是为什么值在页面刷新后依然存在,以及为什么两个不同的用户(几乎总是)获得不同的值,而范围限定为 `team` 的变量对于团队的所有成员都是相同的。
## 与 ctfd-dynamic-flag 集成
如果安装了 **ctfd-dynamic-flag**,它的 `dynamic_formula` flag 可以通过相同的 `{{name}}` 语法在 `source`/`secret` 中引用这些变量——这样 flag 就可以派生自任务文本中显示的相同的按用户分配的值。该集成通过 `app.dynamic_values_substitute` 松散耦合;两个插件互不导入,并且各自都能独立工作。
## REST API(仅限管理员)
| 方法 | 路径 | 用途 |
|--------|------|---------|
| GET | `/api/v1/plugins/dynamic_values?challenge_id=` | 列出变量 |
| POST | `/api/v1/plugins/dynamic_values` | 创建 |
| PATCH | `/api/v1/plugins/dynamic_values/` | 更新 |
| DELETE | `/api/v1/plugins/dynamic_values/` | 删除 |
| GET | `/api/v1/plugins/dynamic_values/preview?mask=…&salt=…&scope=…&name=…` | 预览掩码 |
所有 endpoint 都需要管理员会话 (`@admins_only`)。
## 安全说明
- 没有代码执行:掩码由固定的分词器解析,从不使用 `eval`/`exec`。
- 生成的值本身并不是秘密;如果您从变量派生出 flag,其保密性来自于 flag 的 salt/secret,而不是变量本身。
- 写入 endpoint 仅限管理员使用;预览使用请求管理员自己的身份作为示例。
## 兼容性
CTFd 3.x 和 4.x。
标签:CTFd插件, CTF平台, Python, Syscall, Web开发, 动态变量, 参数生成, 数据可视化, 无后门, 请求拦截, 逆向工具