PerEvermo/TechHaven-CTF
GitHub: PerEvermo/TechHaven-CTF
一个基于 Blazor 构建的故意存在漏洞的电商网站 CTF 靶场,包含 20 个涵盖多种 Web 安全漏洞的夺旗挑战。
Stars: 0 | Forks: 0
GitHub: PerEvermo/TechHaven-CTF
一个基于 Blazor 构建的故意存在漏洞的电商网站 CTF 靶场,包含 20 个涵盖多种 Web 安全漏洞的夺旗挑战。
Stars: 0 | Forks: 0
) │ └── Layout/ │ └── MainLayout.razor # Navbar + footer ├── Services/ │ ├── DatabaseService.cs # All DB logic — vulnerable + patched queries │ ├── AuthStateService.cs # Per-circuit login state │ └── FlagService.cs # Flag registry and validation (20 flags) ├── wwwroot/ │ ├── robots.txt # Hints at hidden paths (Flag 4) │ ├── sitemap.xml # Lists /changelog (Flag 9) │ ├── security.txt # Flag 11 — security disclosure file │ ├── backup/ │ │ ├── index.txt # Fake directory listing — hints at config.txt │ │ └── config.txt # Flag 14 — exposed backup config + API key │ └── js/ctf.js # Cookie + localStorage JS helpers ├── Program.cs # HTTP header middleware (Flag 3) │ # /api/debug (Flag 13), /api/internal (Flag 15) └── README.md ``` ## CTF 挑战 — 概述 | # | Flag 值 | 类别 | 难度 | |---|-----------|----------|-----------| | 1 | `RECON_01` | 源代码 / 控制台 | ⭐ 简单 | | 2 | `SHADOW_02` | DOM 检查 | ⭐ 简单 | | 3 | `HEADER_03` | HTTP Headers | ⭐⭐ 中等 | | 4 | `WAREHOUSE_04` | 信息收集 / robots.txt | ⭐ 简单 | | 5 | `COOKIE_05` | Cookie 篡改 | ⭐⭐ 中等 | | 6 | `SQLINJECT_06` | SQL Injection (认证绕过) | ⭐⭐⭐ 困难 | | 7 | `UNION_07` | SQL Injection (UNION) | ⭐⭐⭐⭐ 专家 | | 8 | `COMMENT_08` | HTML 源代码注释 | ⭐ 简单 | | 9 | `SITEMAP_09` | Sitemap 信息收集 | ⭐ 简单 | | 10 | `LOCALSTORAGE_10` | 浏览器 localStorage | ⭐ 简单 | | 11 | `WELLKNOWN_11` | security.txt | ⭐ 简单 | | 12 | `IDOR_12` | 不安全的直接对象引用 (IDOR) | ⭐⭐ 中等 | | 13 | `APIDEBUG_13` | 暴露的 API Endpoint | ⭐⭐ 中等 | | 14 | `BACKUP_14` | 强制浏览 / 备份文件 | ⭐⭐ 中等 | | 15 | `APIKEY_15` | API Key 认证 | ⭐⭐⭐ 困难 | | 16 | `SQLCAT_16` | SQL Injection (类别筛选) | ⭐⭐⭐ 困难 | | 17 | `SQLDISCOUNT_17` | SQL Injection (折扣码) | ⭐⭐⭐ 困难 | | 18 | `SQLFORGOT_18` | SQL Injection (忘记密码) | ⭐⭐⭐ 困难 | | 19 | `SQLUSERS_19` | SQL Injection (成员搜索) | ⭐⭐⭐ 困难 | | 20 | `ENUMERATE_20` | 用户名枚举 + 弱凭证 | ⭐⭐⭐⭐ 专家 | ## 讲师指南 (完整解答) ### FLAG 1 — RECON_01 **页面:** `/` (首页) **类别:** 源代码 / 浏览器控制台 **难度:** ⭐ **方法 A — 查看页面源代码:** 右键点击页面 → *查看页面源代码* (`Ctrl+U`)。搜索 `Dev Notes`: ``` ``` 在浏览器控制台中解码: ``` atob("RkxBRzE6IFJFQ09OXzAx") // → "FLAG1: RECON_01" ``` **方法 B — 浏览器控制台:** 打开 DevTools → Console。页面加载时应用会打印: ``` [TechHaven Debug] RkxBRzE6IFJFQ09OXzAx Hint: this looks encoded. Try atob("RkxBRzE6IFJFQ09OXzAx") in the console. ``` **提交:** `RECON_01` ### FLAG 2 — SHADOW_02 **页面:** `/products` **类别:** DOM 检查 **难度:** ⭐ 打开 DevTools → Elements 选项卡,搜索 `__debug`。找到隐藏的 div: ```
``` ``` atob("RkxBRzI6IFNIQURPV18wMg==") // → "FLAG2: SHADOW_02" ``` **提交:** `SHADOW_02` ### FLAG 3 — HEADER_03 **页面:** `/about` **类别:** HTTP Response Headers **难度:** ⭐⭐ DevTools → **Network** 选项卡 → 刷新页面 → 点击 `about` 请求 → **Response Headers**: ``` X-Debug-Token: FLAG3: HEADER_03 ``` **提交:** `HEADER_03` ### FLAG 4 — WAREHOUSE_04 **页面:** `/hidden-warehouse` **类别:** 信息收集 / robots.txt **难度:** ⭐ 浏览至 `/robots.txt`: ``` Disallow: /hidden-warehouse ``` 导航至 `/hidden-warehouse` — flag 显示在页面上。 **提交:** `WAREHOUSE_04` ### FLAG 5 — COOKIE_05 **页面:** `/vip` **类别:** Cookie 篡改 **难度:** ⭐⭐ 首页设置 `customer_tier=standard`。VIP 页面在值为 `vip` 时授予访问权限。 DevTools → **Application** → **Cookies** → 将 `customer_tier` 值更改为 `vip` → 刷新。 **提交:** `COOKIE_05` ### FLAG 6 — SQLINJECT_06 **页面:** `/login` → `/admin` **类别:** SQL Injection — 认证绕过 **难度:** ⭐⭐⭐ 登录查询通过字符串拼接构建: ``` SELECT username, role FROM users WHERE username = '[INPUT]' AND password = '[INPUT]' ``` **绕过 payloads:** | 用户名 | 密码 | 效果 | |----------|----------|--------| | `admin' --` | *(任意)* | 注释掉密码检查 | | `' OR '1'='1' --` | *(任意)* | 永真条件 | 绕过后,`/admin` 的管理面板会显示 flag。 **提交:** `SQLINJECT_06` ### FLAG 7 — UNION_07 **页面:** `/products` (搜索栏) **类别:** SQL Injection — UNION **难度:** ⭐⭐⭐⭐ 页面源代码中提示了产品搜索查询的结构: ``` SELECT id, name, description, price, category FROM products WHERE name LIKE '%query%' ``` 粘贴到搜索框中: ``` ' UNION SELECT id, flag_value, hint, 0.0, flag_number FROM flags -- ``` 会出现一个结果卡片,显示从 `flags` 表中提取的 flag 值和提示文本。 **提交:** `UNION_07` ### FLAG 8 — COMMENT_08 **页面:** 任意页面 (共享布局) **类别:** HTML 源代码注释 **难度:** ⭐ 右键点击任意页面 → *查看页面源代码* (`Ctrl+U`)。滚动到最底部,在结束的 `` 标签之前找到注释: ``` ``` **教学要点:** HTML 源代码中的开发者注释对任何人都可见 — 切勿在 HTML 注释中留下凭证、flag 或内部笔记。 **提交:** `COMMENT_08` ### FLAG 9 — SITEMAP_09 **页面:** `/changelog` **类别:** Sitemap 信息收集 **难度:** ⭐ 浏览至 `/sitemap.xml`。它列出了所有公开 URL,包括导航栏中没有的 `/changelog`。 导航至 `/changelog` — flag 显示在页面上。 **教学要点:** `sitemap.xml` 是搜索引擎使用的标准文件。攻击者通常会检查它以发现未列出的页面。 **提交:** `SITEMAP_09` ### FLAG 10 — LOCALSTORAGE_10 **页面:** `/` (首页) — 访问首页后检查任何页面 **类别:** 浏览器 localStorage **难度:** ⭐ 当首页加载时,它会将一个 base64 编码的 token 写入 `localStorage`: DevTools → **Application** 选项卡 → **Local Storage** → 选择站点 → 找到键 `th_debug_token`。 该值是 base64 编码的。在控制台中解码: ``` atob(localStorage.getItem("th_debug_token")) // → "FLAG10: LOCALSTORAGE_10" ``` 提示也可见于 `ctf.js`: ``` // Dev note: session cache written to localStorage key "th_debug_token" on page load ``` **提交:** `LOCALSTORAGE_10` ### FLAG 11 — WELLKNOWN_11 **页面:** `/security.txt` **类别:** security.txt 泄露 **难度:** ⭐ 导航至 `/security.txt`。安全研究人员总是会检查这个标准文件以获取联系方式和披露信息。在底部附近: ``` # FLAG11: WELLKNOWN_11 # 如果你找到了这个文件 —— 很好的直觉。 ``` **教学要点:** `security.txt` (RFC 9116) 是组织发布的标准文件,用于告知研究人员如何报告漏洞。务必在目标上检查它。 **提交:** `WELLKNOWN_11` ### FLAG 12 — IDOR_12 **页面:** `/product/{id}` **类别:** 不安全的直接对象引用 (IDOR) **难度:** ⭐⭐ 产品页面列出了 10 个产品。每张卡片现在都有一个 **Details** 链接,指向 `/product/{id}`。通过猜测可见范围之外的 ID,学生发现了一个隐藏的草稿产品。 尝试: `/product/11` — 这会返回 "Prototype Unit X-11",一个在其描述中包含 flag 的 DRAFT 产品。该产品存在于数据库中,但在公开列表中被过滤掉了 — 然而详情 endpoint 本身没有授权检查。 **教学要点:** 始终在数据层实施访问控制,而不仅仅是在 UI 层。如果详情 endpoint 没有认证检查,从列表中隐藏记录并不能保护它。 **提交:** `IDOR_12` ### FLAG 13 — APIDEBUG_13 **页面:** `/api/debug` **类别:** 暴露的 Debug API Endpoint **难度:** ⭐⭐ 浏览或使用 `curl` 访问 `/api/debug`。该 endpoint 返回一个 JSON 对象: ``` { "version": "2.3.1-dev", "environment": "production", "database": "SQLite", "debug_mode": true, "internal_token": "FLAG13: APIDEBUG_13", ... } ``` **教学要点:** Debug endpoints 在生产环境中不应可访问。常见的尝试路径: `/api/debug`, `/api/status`, `/api/health`, `/_debug`, `/info`。 **提交:** `APIDEBUG_13` ### FLAG 14 — BACKUP_14 **页面:** `/backup/config.txt` **类别:** 强制浏览 / 暴露的备份 **难度:** ⭐⭐ **步骤 1 — 发现备份路径:** `/robots.txt` (来自 Flag 4) 将 `/backup` 列为禁止路径。浏览至 `/backup/index.txt` 找到一个伪造的目录列表: ``` Files: - config.txt [2026-01-15] internal configuration snapshot ... ``` **步骤 2 — 获取文件:** 浏览至 `/backup/config.txt`。该文件包含伪造的内部配置,包括 API key、SMTP 凭证和 flag: ``` # FLAG14: BACKUP_14 ``` **教学要点:** 备份文件、配置转储和提交到公共文件夹的旧文件是现实世界中常见的发现。务必检查 `/backup/`, `/old/`, `/.env`, `/config.bak` 等。 **提交:** `BACKUP_14` ### FLAG 15 — APIKEY_15 **页面:** `/api/internal` **类别:** API Key 认证 **难度:** ⭐⭐⭐ 这是一个两步链: **步骤 1** — 在 `/backup/config.txt` (Flag 14) 中找到 API key: ``` internal_api_key = th-internal-4829af ``` **步骤 2** — 使用该 key 认证 `/api/internal` endpoint: ``` curl -H "X-API-Key: th-internal-4829af" http://localhost:5210/api/internal ``` 响应: ``` { "status": "authenticated", "flag": "FLAG15: APIKEY_15", ... } ``` **教学要点:** 在暴露文件中发现的 API key 可以直接解锁受保护的 endpoints。多步骤漏洞利用链在真实渗透测试中很常见。 **提交:** `APIKEY_15` ### FLAG 16 — SQLCAT_16 **页面:** `/products?cat=` **类别:** SQL Injection — 类别筛选 **难度:** ⭐⭐⭐ 产品页面上的类别筛选按钮使用 URL 参数 (`?cat=`)。页面源代码中可见提示: ``` ``` 查询通过字符串拼接构建 — 通过 URL 注入: ``` /products?cat=Laptops' UNION SELECT 1,secret_key,secret_value,0.0,'SECRET' FROM secrets -- ``` 会出现一个结果卡片,显示 `secrets` 表的内容,包括 flag。 **提交:** `SQLCAT_16` ### FLAG 17 — SQLDISCOUNT_17 **页面:**checkout` **类别:** SQL Injection — 折扣码 **难度:** ⭐⭐⭐ 结账页面有一个折扣码输入框。页面源代码中的提示: ``` ``` `AND active = 1` 过滤器隐藏了停用的代码。注入以绕过它: ``` ' OR '1'='1' -- ``` 或更针对性的: ``` SAVE10' OR active=0 -- ``` `promo_codes` 的所有行都会返回,包括在其描述中包含 flag 的非活动行。 **提交:** `SQLDISCOUNT_17` ### FLAG 18 — SQLFORGOT_18 **页面:** `/forgot-password` **类别:** SQL Injection — 忘记密码表单 **难度:** ⭐⭐⭐ 忘记密码表单接受用户名。页面源代码注释显示了查询结构: ``` ``` 使用 UNION 注入提取第二个表。查询返回 2 列 (`username`, `password`),因此 UNION 也需要 2 列: ``` ' UNION SELECT email, token FROM newsletter_subscribers -- ``` 响应显示 `newsletter_subscribers` 的所有行,包括一个条目,其 token 列包含 flag。 **提交:** `SQLFORGOT_18` ### FLAG 19 — SQLUSERS_19 **页面:** `/community` **类别:** SQL Injection — 成员搜索 (LIKE) **难度:** ⭐⭐⭐ 社区成员搜索使用 `LIKE '%query%'` 模式。页面源代码中的提示: ``` ``` **最简单的方法** — 输入单个 `%` 作为搜索词: ``` % ``` 这匹配所有用户名,返回每个成员,包括隐藏的 `__404__` 账户,其徽章字段包含 flag。 **替代注入:** ``` ' OR '1'='1 ``` **提交:** `SQLUSERS_19` ### FLAG 20 — ENUMERATE_20 **页面:** `/login` → `/staff-portal` **类别:** 用户名枚举 + 弱凭证 **难度:** ⭐⭐⭐⭐ 登录页面现在根据用户名是否存在返回**不同的错误消息**: | 场景 | 错误消息 | |----------|---------------| | 用户名不存在 | *"No account found with that username."* | | 用户名存在,密码错误 | *"Incorrect password."* | **步骤 1 — 找到用户名:** 访问 `/community` — 成员卡片显示一个名为 `ghost` 的用户,带有 *"Former Staff"* 徽章。这就是要针对的用户名。 **步骤 2 — 通过登录错误进行枚举:** 尝试使用 `ghost` 和错误密码登录。登录页面根据用户名是否存在返回不同的错误: | 场景 | 错误消息 | |----------|---------------| | 用户名不存在 | *"No account found with that username."* | | 用户名存在,密码错误 | *"Incorrect password."* | `ghost` 返回 *"Incorrect password."* — 确认账户存在。 **步骤 3 — 破解弱密码:** `ghost` 账户使用密码 `ghost123` — 使用常见密码或短字典很容易猜到。 **步骤 4 — 登录:** 以 `ghost` / `ghost123` 登录。由于角色是 `staff`,应用重定向到 `/staff-portal` 而不是 `/admin`,那里显示 flag。 **教学要点:** "用户未找到"与"密码错误"的不同错误消息允许攻击者枚举有效账户名。结合弱密码,这是一个完整的账户接管链。 **提交:** `ENUMERATE_20` ## 讲师面板 `/instructor` 提供了一个受密码保护的页面 (UI 中未链接)。 它显示: - 实时统计: 活跃团队、已捕获的 flag、错误尝试 - 每个 flag 的进度条,显示有多少团队找到了该 flag - 一个带有确认的 **清除所有提交** 按钮 **默认密码:** `TechHaven2026!` 要更改它,编辑 `appsettings.json`: ``` "InstructorPassword": "YourNewPassword" ``` ## 在会话之间重置 **选项 A — 讲师面板 (推荐):** 浏览至 `/instructor`,登录,点击 *清除所有提交*。这只会清除记分板数据 — flag 和种子数据将被保留。 **选项 B — 删除数据库 (完全重置):** ``` # 停止应用,然后: del bin\Debug\net10.0\techhaven.db # Windows rm bin/Debug/net10.0/techhaven.db # Linux/macOS # 重启 — DB 会被自动重建并重新填充数据 ```