svuillaume/forticnapp-ctfd

GitHub: svuillaume/forticnapp-ctfd

一个基于 CTFd 构建的云安全夺旗赛平台,能将 FortiCNAPP 的真实安全发现自动转化为竞赛题目,用于售前演示和客户研讨会。

Stars: 1 | Forks: 0

Fortinet # FortiCNAPP CTF **一个用于 FortiCNAPP 研讨会和客户演示的夺旗赛(CTF)平台** ![CTFd](https://img.shields.io/badge/CTFd-3.7.5-000000?style=flat&logoColor=white) ![Docker](https://img.shields.io/badge/Docker-Compose-2496ED?style=flat&logo=docker&logoColor=white) ![Python](https://img.shields.io/badge/Python-3.12-3572A5?style=flat&logo=python&logoColor=white) ![Challenges](https://img.shields.io/badge/challenges-21_static_%2B_live-DA291C?style=flat)
## 它是什么? FortiCNAPP CTF 将真实的云安全发现转化为有积分和计时的竞赛。 参与者需要在 FortiCNAPP 控制台中调查告警、对漏洞进行分类排查并找出合规违规情况, 然后在实时排行榜上提交答案。 **两种模式,同一技术栈:** | 模式 | 挑战题 | 需要 FortiCNAPP 租户 | 最适用于 | |---|---|---|---| | **CTF 实验室** | 21 道手工编写的题目 | ❌ 否 | 演示、离线、彩排 | | **实时 CTF** | 基于真实发现生成 | ✅ 是 | 使用真实租户的现场活动 | 首次启动时,**会自动加载 5 道随机的 CNAPP 热身题** —— 无需任何设置。 ## 架构 ``` Browser │ │ https://localhost (CTFd — port 443) │ https://localhost:5555 (Trigger API) │ ▼ ┌──────────────────────────────────────────────────────────┐ │ Caddy (HTTPS reverse proxy — self-signed cert) │ └────────────┬──────────────────────────────┬─────────────┘ │ │ :8000 ▼ :5555 ▼ ┌──────────────────┐ ┌──────────────────────────┐ │ CTFd 3.7.5 │ │ Trigger Service (Flask) │ │ challenges │◀──────│ /run/static │ │ scoring │ │ /run/dynamic │ │ leaderboard │ │ /reset │ └────────┬─────────┘ └──────────────────────────┘ │ │ ┌──────┴──────┐ ┌──────┴──────────────────────┐ │ MariaDB │ │ bridge-static │ │ Redis │ │ YAML challenges → CTFd │ └─────────────┘ │ │ │ bridge (dynamic) │ │ FortiCNAPP API → CTFd │ └─────────────────────────────┘ ``` ## 前置条件 - **Docker** 和 **Docker Compose v2** — `docker compose version` - **Python 3.10+** — 用于运行 `ctl.py` - 主机上需开放 **80、443、5555 端口** ## 快速开始 ``` python ctl.py ``` 首次运行时,设置向导会自动启动。它将引导您完成三个部分: | 部分 | 询问内容 | |---|---| | **CTFd** | 数据库密码、管理员用户名 / 邮箱 / 密码 | | **HTTPS** | 主机名或 IP —— 留空则使用 `localhost` | | **FortiCNAPP API** | Account、Key ID、Secret —— 仅在实时 CTF 模式下需要 | 然后按 **`1` (START)**。脚本将执行以下操作: 1. 启动 `db`、`cache`、`ctfd` 2. 自动完成 CTFd 首次运行向导(无需浏览器操作) 3. 生成管理员 API token 并保存到 `.env` 4. 启动 `trigger` 和 `caddy` 5. 应用 Fortinet 主题 6. 如果数据库为空,则加载 5 道随机的 CNAPP 热身题 打开 **`https://localhost`** —— 接受一次浏览器的安全警告(由于使用自签名证书)。 ## 主页 CTFd 主页包含两个模式卡片和一个重置控件: | 按钮 | 操作 | |---|---| | **加载 CTF 实验室挑战题** | 加载 21 道静态挑战题;解锁 CTF 实验室的 *Start Challenges* 按钮 | | **加载实时挑战题** | 从您的 FortiCNAPP 租户中拉取安全发现;解锁实时 CTF 的 *Start Challenges* 按钮 | | **重置**(任意卡片) | 清除所有挑战题并重新加载 5 道随机的 CNAPP 热身题 | ## 控制面板 (`ctl.py`) ``` ╔══════════════════════════════════════════╗ ║ FortiCNAPP CTF — Control Panel ║ ╚══════════════════════════════════════════╝ STATUS ● CTFd ● DB ● Cache ● Trigger ● Caddy s Setup / edit .env 1 START → https://localhost 2 STOP (containers stopped, data kept) 3 RESTART 4 DESTROY ⚠️ removes containers + volumes — all data lost 5 Logs (CTFd) 6 Logs (Trigger) q Quit ``` | 选项 | 功能 | |---|---| | `s` | 重新打开设置向导以编辑任何 `.env` 值 | | `1` | 启动完整技术栈 —— 首次运行时会自动配置 CTFd | | `2` | 停止所有容器(数据保留在 Docker volumes 中) | | `3` | 停止后重新启动 | | `4` | 停止 → 移除所有容器及 volumes → 清除管理员 token | | `5` / `6` | 跟踪查看 CTFd / Trigger 的日志 | ## Flag 格式 ### 热身题(默认 / 重置) 纯文本答案 —— 无需包含包装格式: ``` transport_layer_security cloud_security_posture_management misconfiguration ``` 挑战描述中始终会显示预期的格式,例如 `Example format: word_word_word`。 ### CTF 实验室和实时 CTF 挑战题 标准 CTF flag 格式: ``` FLAG{answer} ``` | 类别 | 答案是… | |---|---| | 告警分诊 | MITRE 技术 ID —— `FLAG{T1496}` | | 主机安全 | CVE ID 或主机名 —— `FLAG{CVE-2025-12345}` | | 容器安全 | 镜像名称、端口或缩写 | | 云合规 | CIS 控制编号 —— `FLAG{1.5}` | 所有 flag 均不区分大小写。 ## 模式详解 ### CTF 实验室(静态) 包含 21 道手工编写的挑战题,涵盖了真实的 FortiCNAPP 场景。无需凭证。可离线运行。 | 类别 | 数量 | 主题 | |---|---|---| | 🔴 告警分诊 | 5 | MITRE ATT&CK T1496 · T1078.004 · T1571 · 复合告警 | | 🟠 主机安全 | 5 | CVE ID · CVSS 评分 · 主机名查询 · 无代理扫描 | | 🔵 容器安全 | 5 | 影子 MCP · 挖矿木马 · Docker 取证 · 端口暴露 | | 🟡 云合规 | 6 | CIS AWS 1.5 · 1.14 · 2.1.5 · 3.1 · 5.2x · CSPM | 挑战题文件:`static_ctf/ctf/*/challenges.yml` —— 可自由编辑并重新加载。构建器是完全幂等的(首次运行时创建,再次运行时更新)。 ### 实时 CTF(动态) 从您的 FortiCNAPP 租户中拉取真实的安全发现,并自动生成挑战题。 **FortiCNAPP 控制台 → Settings → API Keys → Create New** 下载 JSON 文件 —— 其中包含 `keyId`、`secret` 和 `account`。在设置向导中输入它们,或直接添加到 `.env` 文件中: ``` FORTICNAPP_ACCOUNT=acme-prod FORTICNAPP_SUBACCOUNT= FORTICNAPP_API_KEY_ID=ACME_1234... FORTICNAPP_API_SECRET=_your_secret LOOKBACK_HOURS=72 MAX_CHALLENGES_PER_CATEGORY=5 ``` | 类别 | FortiCNAPP API endpoint | |---|---| | 告警分诊 | `/api/v2/Alerts`(带有 MITRE 标签的告警) | | 主机安全 | `/api/v2/Vulnerabilities/Hosts/search` | | 容器安全 | `/api/v2/Vulnerabilities/Containers/search` | | 云合规 | `/api/v2/Configs/ComplianceEvaluations/search` | ``` MOCK_MODE=true ``` **数据脱敏** —— 当设置 `SANITIZE=true`(默认值)时,桥接程序会清除所有可识别客户身份的数据:AWS 账户 ID、Azure 订阅 UUID、GCP 项目 ID、S3 存储桶名称、公网 IP、电子邮件地址和主机名。每次运行的映射关系是稳定的,因此挑战题的描述能保持内在一致。 ## HTTPS Caddy 使用 `tls internal` —— 其内置的本地 CA 会在启动时颁发自签名证书。无需域名或互联网连接。 **首次访问:** 浏览器会显示安全警告。点击 **Advanced → Accept**(Chrome/Edge)或 **Accept the Risk**(Firefox)。每个浏览器只需操作一次。 **自定义主机名或 IP**(适用于同一网络下的参与者): ``` # .env FQDN=192.168.1.100 ``` Caddy 将为该地址颁发证书。参与者只需接受一次警告。 ## 活动工作流 ### 活动前(约 5 分钟) ``` # 1. 启动一切 python ctl.py → 1 # 2. 加载你想要的挑战模式 # — 使用主页按钮,或通过 CLI: docker compose run --rm bridge-static # CTF Lab docker compose run --rm bridge # Live CTF # 3. 使挑战可见 # Admin Panel → Configs → Challenge Visibility → Public ``` ### 活动进行中 1. 参与者在 `https://your-host` **注册** 2. **阅读**挑战场景 3. **浏览** FortiCNAPP 控制台以寻找答案 4. **提交** flag —— 系统即时评分 5. 观看 **实时排行榜** 更新 **建议的 45 分钟流程:** | 时间 | 轮次 | 技能点 | |---|---|---| | 0–2 分钟 | 场景设置 | — | | 2–17 分钟 | 🔴 告警分诊 | MITRE 映射加速事件响应 (IR) | | 17–32 分钟 | 🟠🔵 主机 + 容器安全 | CWPP 相比独立扫描器的价值 | | 32–42 分钟 | 🟡 云合规 | CSPM + 审计案例 | | 42–45 分钟 | 复盘 + 排行榜 | 在控制台中现场演示一个发现结果 | ### 活动后 —— 完全重置 ``` python ctl.py → 4 → YES ``` 停止所有容器并清除所有 volumes(积分、用户、挑战题)。按 `1` 可从头开始重新构建。 ## 添加自定义挑战题 编辑或创建 `static_ctf/ctf//challenges.yml` 中的 YAML 文件,然后重新加载: ``` docker compose run --rm bridge-static ``` **最小化挑战题模板:** ``` challenges: - name: "My Challenge" author: "Your Name" category: "Alert Triage" description: | Find the alert triggered by technique **T1496** and submit the MITRE ID. value: 100 type: standard flags: - content: "FLAG{T1496}" type: static hints: - content: "Check the Alert Triage dashboard in FortiCNAPP." tags: - mitre state: visible ``` ## 项目布局 ``` forticnapp-ctf/ ├── ctl.py # ← single entry point ├── docker-compose.yml ├── .env.example # copy to .env — never commit .env │ ├── static_ctf/ # CTF Lab (static mode) │ ├── build.py # entrypoint: reads env → builds CTF │ ├── ctfbuilder.py # idempotent challenge push │ ├── ctfd.py # CTFd REST API wrapper │ ├── fortinet.css # Fortinet dark theme │ ├── home.html # home page (mode selector cards) │ └── ctf/ │ ├── config.yml │ ├── 1_Alert Triage/ │ ├── 2_Host Security/ │ ├── 3_Container Security/ │ └── 4_Cloud Compliance/ │ ├── forticnapp_ctf_api/ # Live CTF (dynamic mode) │ ├── bridge.py # pull → sanitize → push │ ├── forticnapp_client.py # FortiCNAPP v2 API client │ ├── ctfd_client.py # CTFd admin API client │ ├── challenges.py # finding → Challenge mapping │ └── sanitize.py # PII scrubber │ ├── trigger/ # Always-on trigger service │ └── app.py # Flask: /run/static /run/dynamic /reset │ # Auto-configures CTFd on first boot │ # Auto-resets after inactivity │ ├── caddy/ # HTTPS reverse proxy │ └── Caddyfile # tls internal — self-signed cert │ └── sample_data/ # Mock data for MOCK_MODE=true ├── alerts.json ├── container_vulns.json ├── host_vulns.json └── compliance.json ``` ## 常用命令 ``` # 启动一切 python ctl.py # 加载 / 重新加载挑战 docker compose run --rm bridge-static # CTF Lab docker compose run --rm bridge # Live CTF # 仅重新应用 Fortinet 主题(不更改挑战) docker compose run --rm bridge-static --theme-only # 查看日志 docker compose logs -f ctfd docker compose logs -f trigger # 检查 container 健康状态 docker compose ps # 代码更改后重建 image docker compose build && docker compose up -d # 检查不活动自动重置计时器 curl https://localhost:5555/status/inactivity ``` ## 故障排除 **浏览器显示安全警告** 属于预期情况 —— 自签名证书。每个浏览器点击一次 **Advanced → Accept** 即可。 **主页空白或显示默认的 CTFd 主题** 点击主页底部的 **Re-apply Fortinet Theme**,或者运行: ``` docker compose run --rm bridge-static --theme-only ``` **Start Challenges 按钮被锁定 (🔒)** 请先点击 **Load CTF Lab Challenges** 或 **Load Live Challenges**。成功加载后,该按钮将自动解锁。 **CTFd 不断重启** 检查 `.env` 中是否设置了 `SECRET_KEY`(由 `ctl.py` 自动生成)。 **管理员 token 被拒绝 (401)** 运行 `python ctl.py` → `s` → 从 **Admin Panel → Settings → Tokens** 粘贴一个新的 token。 **主页显示 "already running"(已在运行)** 系统正在构建中。请等待约 1 分钟,或检查 `docker compose logs trigger`。 **未生成任何挑战题 (实时 CTF)** 1. 检查 `.env` 文件:`FORTICNAPP_ACCOUNT`、`FORTICNAPP_API_KEY_ID`、`FORTICNAPP_API_SECRET` 2. 扩大时间窗口:`LOOKBACK_HOURS=720` 3. 离线测试:`MOCK_MODE=true` **容器安全返回结果为 0 (动态模式)** 必须在租户上启用无代理工作负载扫描。使用 `LOOKBACK_HOURS=720` 或 `MOCK_MODE=true`。 **参与者无法看到挑战题** Admin Panel → Configs → Challenge Visibility → 选择 **Public**。 **构建时出现 Docker 层缓存错误** ``` docker builder prune -f docker compose build --no-cache docker compose up -d ``` ## 许可证与致谢 CTFd 采用 [BSD-2-Clause 许可证](https://github.com/CTFd/CTFd/blob/master/LICENSE)。 FortiCNAPP 和 Lacework 是 Fortinet, Inc. 的商标。 本项目与 CTFd 没有官方附属关系。
标签:搜索引擎查询, 版权保护, 请求拦截, 逆向工具