跳转至

CPCTF - mirage Writeup

题目信息

  • 比赛: CPCTF
  • 题目: mirage
  • 类别: Web
  • 难度: 简单
  • 附件/URL: 在线靶机
  • 附件链接: 无附件
  • Flag格式: CPCTF{...}
  • 状态: 已解

Flag

CPCTF{CH4R4C73R5_4L50_D159U153}

解题过程

1. 初始侦察/文件识别

  • 题面是:“复制并粘贴正确的flag!”
  • 提示也非常直接:
  • 如果你复制“看起来正确”的 flag,会得到虚假 flag
  • 可以逐个复制其他字符串
  • 也可以尝试全部复制、搜索或使用开发者工具
  • 打开页面后,能看到很多“长得像 flag”的字符串,但题目名本身叫 mirage,已经暗示这是视觉伪装题,眼睛看到的不一定是真的。

2. 关键突破点一:先别信显示效果,要看源码和原始文本

  • 这题最容易的误区是只盯着页面上看起来最像 flag 的那一行。
  • 但提示已经说明:看起来正确的内容会对应虚假 flag
  • 所以第一步就不该继续点选某一行,而应该直接换思路:
  • 全选页面内容后粘贴到本地文本编辑器
  • 搜索 CPCTF{
  • 或者直接打开开发者工具 / 查看页面源码
  • 一旦进入源码视角,就能发现真正的问题根本不在后端,而在前端渲染层。

3. 关键突破点二:页面用自定义字体伪装字符外观

  • 页面源码里直接内联了一个自定义字体:
@font-face {
  font-family: "Mirage";
  src: url("data:font/woff2;base64,...");
}
  • 同时页面正文和每个 flag 元素都使用这个字体:
body, .flag {
  font-family: "Mirage", monospace;
}
  • 这说明页面上的可见字符,很可能不是“真实文本长什么样就显示成什么样”,而是通过 glyph 映射把原始字符伪装成另一套外观。
  • 也就是说:
  • 你眼睛看到的是字体渲染后的假象
  • DOM / 源码里的文本才是真正可复制、可搜索的内容

4. 获取 Flag

  • 继续看源码可以发现,页面里的多条字符串其实是由一段前端 JS 数组直接注入 DOM:
[
  "TGT7D{I_L0VE_M1KU_H4T5UN3}",
  ...
  "CPCTF{CH4R4C73R5_4L50_D159U153}",
  ...
].forEach((flag, i) => {
  const div = document.createElement("div");
  div.className = "flag";
  div.textContent = `${flag}`;
  container.appendChild(div);
});
  • 这里关键点有两个:
  • 使用的是 textContent,说明 DOM 里的原始字符串没有被额外编码
  • 真正的 CPCTF{...} 已经明文写在源码数组里
  • 所以根本不需要逐条肉眼比对,只要在源码或全文复制结果里搜索 CPCTF{,就能直接定位真实 flag:
CPCTF{CH4R4C73R5_4L50_D159U153}

攻击链/解题流程总结

打开页面 -> 意识到视觉结果不可信 -> 查看源码 / 开发者工具 / 全文复制 -> 搜索 CPCTF{ -> 发现前端数组中的真实 flag -> 提交答案

漏洞分析 / 机制分析

根因

  • 真实 flag 被直接下发到了前端页面源码中。
  • 页面只是依靠自定义字体改变 glyph 外观,让原始字符串“看起来像别的内容”。
  • 这种伪装只作用于显示层,无法真正隐藏 DOM 中的底层文本。

影响

  • 任何会查看源码、搜索文本、复制全文或使用开发者工具的用户,都能绕过视觉伪装直接找到真实 flag。
  • 在真实业务中,如果把敏感信息直接发给前端,再靠 CSS / 字体 / 混淆做“隐藏”,同样不能提供真正安全性。

修复建议(适用于漏洞类题目)

  • 敏感数据不要直接出现在前端源码、DOM 或静态资源里。
  • 不要把自定义字体、CSS 隐藏、前端混淆当作安全边界。
  • 如果数据需要保护,应由服务端在满足权限条件后再返回。

知识点

  • 自定义字体与 glyph 映射伪装
  • DOM 原始文本与视觉渲染结果可能不一致
  • 查看源码 / 开发者工具 / 全文搜索在前端题中的价值

使用的工具

  • 浏览器开发者工具 — 查看 Elements / Sources / 全局搜索
  • 查看页面源码 / 抓取 HTML — 直接读取原始前端代码
  • Python 3 — 自动抓取页面并提取 CPCTF{...}

脚本归档

  • Python:CPCTF_mirage.py
  • 说明:脚本会直接抓取页面 HTML,并在源码中搜索唯一真实的 CPCTF{...}

命令行提取关键数据(无 GUI)

python CTF_Writeups/scripts_python/CPCTF_mirage.py

推荐工具与优化解题流程

这题的重点不是“更仔细地看页面”,而是尽快跳出视觉层,直接查看原始文本和源码。

工具对比总结

工具 适用阶段 本题耗时 优点 缺点
全文复制 + 本地搜索 初筛 秒级 不依赖 DevTools,最快看到真实文本 页面内容多时不如源码定位直接
浏览器开发者工具 正解 秒级 可直接查看 DOM、源码和内联字体 需要会用搜索面板
Python 抓取脚本 自动化复现 秒级 稳定、可归档、适合仓库保存 需要写少量代码

推荐流程

推荐流程:先观察页面与提示 -> 立即切换到源码 / DevTools / 全文复制搜索 -> 搜索 CPCTF{ -> 直接取出前端数组中的真实 flag。

工具 A(推荐首选)

  • 安装:浏览器自带开发者工具
  • 详细步骤
  • 打开页面后按 F12
  • 查看 SourcesElements
  • 全局搜索 CPCTF{
  • 直接读取源码中真实 flag
  • 优势:最贴近题目提示,也最容易看清自定义字体伪装机制

工具 B(可选)

  • 安装:Python 3
  • 详细步骤
  • 抓取页面 HTML
  • 用正则提取 CPCTF{...}
  • 去重并输出唯一结果
  • 优势:适合自动化归档,也能证明题目不依赖页面视觉层

评论