PIZZA-CTF 赛后分析&复盘

PIZZA-CTF 赛后分析&复盘原帖子链接：https://www.nodeseek.com/post-625709-1 运用到的关卡（在对应level运用到的）不排序一、正式关卡（levels/） Level 1：SSTV 慢扫描电视 ★☆☆☆☆ 分发文件： level1_sstv.wav 出题原理：SSTV（Slow Scan Television）是业余无线电爱好者用来通过音频信道传输静态图像的技术。本关使用 Robot36 格式——一种将彩色图像编码为音频信号的协议。图像的每一行被转换为一系列频率在 1500–2300Hz 之间变化的音调，其中频率的高低对应像素的亮度。生成过程：创建一张 320×256 的图片，上面写有密钥文字将图片转为 YCrCb 色彩空间按 Robot36 规范逐行扫描：先发送 VIS 码标识格式，然后每行由同步脉冲（1200Hz）+ 亮度扫描（88ms）+ 色度扫描（44ms）组成使用连续相位正弦波生成，避免频率切换时的爆音解题思路：直接用手机 APP "Robot36" 对着扬声器播放即可解码出图片也可使用 PC 端的 RX-SSTV 或 MMSSTV 图片上直接显示密钥 Level 2：摩尔斯电码 ★★☆☆☆ 分发文件： level2_morse.wav 出题原理：最经典的电子通信编码。每个字母/数字对应一组"点"（短音）和"划"（长音）的组合，不同符号之间有固定的时间间隔规则：点（dit）：1 单位时长划（dah）：3 单位时长符号内间隔：1 单位字符间间隔：3 单位单词间间隔：7 单位生成过程：以 12 WPM（每分钟 12 个单词）的速度，将密钥每个字符查表转为点划序列，再用 800Hz 正弦波生成音调，加上平滑包络避免爆音。解题思路：耳听：短音为点（·），长音为划（—），对照摩尔斯码表逐字解码使用在线摩尔斯解码器直接上传音频 Audacity 打开也能从波形直观看出点划模式 Level 3：音频频谱隐写 ★★★☆☆ 分发文件： level3_spectrogram.wav 出题原理：将一张黑白文字图片"画"进音频的频谱图中。图片的每一列对应一个时间片段，每一行对应一个频率。像素越亮，该频率的振幅就越大。直接听只能听到噪音，但用频谱分析工具查看就能看到隐藏的文字。生成过程：创建一张 600×128 的黑白图片，白色文字写着密钥遍历图片每个像素，对于亮像素，在对应的时间位置叠加对应频率（800–8000Hz）的正弦波像素亮度控制振幅大小最终归一化并保存为 WAV 解题思路：用 Audacity 打开 → 点击音轨名称 → 选择"频谱图"视图 → 密钥直接显示在频谱中也可使用 Spek 或 Sonic Visualiser Level 4：LSB 图片隐写 ★★★☆☆ 分发文件： level4_image.png 出题原理：LSB（Least Significant Bit，最低有效位）隐写是最经典的图片隐写术。由于人眼无法分辨像素值相差 1 的颜色（例如 RGB(100,200,50) 与 RGB(101,200,51)），可以利用每个颜色通道的最低位来存储秘密信息。生成过程：创建一张 640×480 的渐变装饰图作为封面将密钥转为二进制串，末尾加 NULL 终止符（8 个 0）依次修改每个像素的 R、G、B 通道最低位为消息比特必须保存为 PNG（无损格式），JPEG 压缩会破坏最低位解题思路：使用 zsteg 工具一键提取：zsteg level4_image.png 或用 stegsolve 逐通道查看或写几行 Python：提取所有像素 RGB 最低位，每 8 位组合成一个 ASCII 字符 Level 5：DTMF 电话拨号音 ★★★☆☆ 分发文件： level5_dtmf.wav 出题原理：DTMF（Dual-Tone Multi-Frequency，双音多频）是电话拨号使用的信号编码。每按一个按键，电话会同时发出两个特定频率的音调——一个来自低频组（697/770/852/941 Hz），一个来自高频组（1209/1336/1477/1633 Hz）。两个频率的组合唯一确定一个按键。生成过程：将密钥的每个数字查 DTMF 频率表，生成 0.25 秒的双频叠加音，按键之间留 0.15 秒间隔，加包络平滑处理。解题思路：使用在线 DTMF decoder 上传音频或用 Audacity 频谱分析，手动识别每段音频的两个峰值频率，查表得到对应数字验证脚本使用 Goertzel 算法（比完整 FFT 更高效地检测特定频率） Level 6：多重编码 ★★★★☆ 分发文件： level6_cipher.png、level6_ciphertext.txt 出题原理：三层套娃编码，玩家需要像剥洋葱一样逐层解开：明文 → ROT13 → Base64 → Hex = 密文玩家看到的是一串十六进制字符串，需要反向操作：密文(Hex) → Hex解码 → Base64解码 → ROT13解码 = 明文生成过程：对密钥先做 ROT13（字母替换，A↔N、B↔O...）结果做 Base64 编码再将 Base64 字符串转为十六进制同时生成一张"终端风格"的密文图片和纯文本文件解题思路：观察密文全是十六进制字符 → 尝试 Hex 解码 → 得到看起来像 Base64 的字符串（有 = 填充）→ Base64 解码 → 结果仍然是乱码字母 → 尝试 ROT13 → 得到明文 CyberChef 一站式解决：拖入 From Hex + From Base64 + ROT13 三个操作 Level 7：二维码碎片 + 频谱隐写（终极关）★★★★★ 分发文件： level7_piece1~4.png、level7_mystery.wav、level7_puzzle_map.png 出题原理：综合前面所学的技能。一张完整的二维码被切成 5 块：4 块直接给玩家作为图片碎片，第 5 块（中心部分）被编码到音频的频谱中——需要用第 3 关学到的频谱分析技能提取。生成过程：用高容错（Error Correct H）生成 300×300 的二维码切成 5 块（四角 + 中心），四角碎片带少量重叠确保定位点完整将中心碎片作为灰度图编码进音频频谱（复用 Level 3 的逻辑）生成拼图指引图标注各碎片位置解题思路：用 Audacity 打开 mystery.wav，切换频谱视图，截图得到第 5 块碎片参考 puzzle_map.png 的布局，用图片编辑器将 5 块碎片拼成完整二维码扫描二维码得到最终密钥二维码使用了高容错级别，即使拼接不够精确也能容忍约 30% 的误差二、附加题（new/） Bonus 1：零宽字符隐写 ★★★★☆ 分发文件： bonus_message.txt（可选：bonus_message_clean.txt 作对比）出题原理：Unicode 中存在一类"零宽字符"——它们在屏幕上完全不可见，但确实存在于文本中。本题利用三种零宽字符构建一套二进制编码：字符 Unicode 含义零宽空格 U+200B 二进制 0 零宽非连接符 U+200C 二进制 1 零宽连接符 U+200D 字符分隔符每个 ASCII 字符被编码为 8 个零宽字符（8 位二进制），字符之间用 U+200D 分隔。这些不可见字符被均匀嵌入到一段正常的英文文本中。关键线索：文件"看起来"只有一段普通的英文短文（约 200 字节），但实际文件大小超过 1000 字节——多出来的全是零宽字符（每个零宽字符占 3 字节 UTF-8）。解题思路：对比文件大小与可见文本长度，发现异常用十六进制编辑器打开，发现大量 E2 80 8B / E2 80 8C / E2 80 8D 字节序列识别为零宽 Unicode 字符提取所有零宽字符，按 U+200D 分割，将 U+200B 视为 0、U+200C 视为 1，每 8 位转一个 ASCII 字符 Bonus 2：敲击密码 ★★★☆☆ 分发文件： bonus2_prison_log.txt 出题原理：Tap Code（敲击密码）是战俘和囚犯之间通过墙壁敲击进行秘密通信的经典方式。它基于 5×5 的 Polybius 方阵： 1 2 3 4 5 1 A B C/K D E 2 F G H I J 3 L M N O P 4 Q R S T U 5 V W X Y Z 每个字母用两组敲击表示：第一组 = 行号，第二组 = 列号。例如 "H" 在第 2 行第 3 列，编码为"敲 2 下，停顿，敲 3 下"。注意字母 K 与 C 共用位置（5×5 只能放 25 个字母）。伪装形式：谜题文件被包装成一份"监狱监控日志"，记录了 Cell B-7 和 B-8 之间的墙壁敲击模式，带有时间戳和环境噪音记录（管道声、脚步声等）增加真实感。解题思路：阅读日志，注意到结构化的敲击模式：●●● ●●●● 或 (... ....) 搜索 "Tap Code" 或 "Prison Knock Code" 构建 5×5 方阵，将每组敲击的第一个数字作为行、第二个作为列注意结果中的 C 可能实际是 K（需结合语义判断） Bonus 3：DNA 碱基编码 ★★★★☆ 分发文件： bonus3_lab_report.txt、bonus3_sequence.fasta 出题原理：DNA 有四种碱基（A、T、C、G），恰好可以用 2 位二进制表示：碱基二进制 A (Adenine) 00 T (Thymine) 01 C (Cytosine) 10 G (Guanine) 11 因此每 4 个碱基 = 8 位 = 1 个 ASCII 字符。例如字母 'H'（0x48 = 01001000）编码为 TACA。伪装形式：谜题被包装成一份 XenoTech BioLabs 的"机密基因序列分析报告"，包含三段 FASTA 格式的 DNA 片段：Fragment Alpha 和 Gamma 是随机生成的干扰序列，Fragment Beta 是编码了密钥的目标序列，并被标注为"异常/非生物来源"。关键线索：报告明确指出 Fragment Beta "不匹配任何已知生物" 分析备注提到"序列长度恰好能被 4 整除"和"4-base periodicity" Beta 的碱基分布偏离自然序列（自然 DNA 四种碱基大致均匀，而编码后 ASCII 可打印字符集中在 0x41-0x7A 区间，导致 T 偏多）解题思路：锁定 Fragment Beta 为目标意识到 4 种碱基 = 2 位二进制每 4 个碱基一组，转为 8 位二进制，再转 ASCII Bonus 4：盲文 Unicode 编码 ★★★★☆ 分发文件： bonus4_accessibility_report.txt、bonus4_braille_raw.txt 出题原理：Unicode 盲文模式块（U+2800 ~ U+28FF）恰好包含 256 个字符，与一个字节的取值范围完全对应。每个盲文字符的码点偏移量（相对于 U+2800）就是 8 个点位的位图。这意味着：任意一个字节都可以直接映射为一个盲文字符：编码: 盲文字符 = chr(0x2800 + ASCII_value) 解码: ASCII_value = ord(盲文字符) - 0x2800 例如 'B'（0x42 = 66）→ chr(0x2842) = ⡂ 伪装形式：谜题被包装成一份"无障碍合规测试报告"。文档中包含标准英文盲文的 Grade 1 测试（干扰项，解码后是正常英语）和一段"异常序列"（目标，解码后不是标准盲文）。关键线索：报告直接列出了异常序列每个字符的 Unicode 码点分析师备注："256 = 2^8 = one byte. Coincidence?" 异常序列用标准盲文解码后是乱码，而正常测试段可以正确解码解题思路：尝试用标准盲文解码异常序列 → 失败（不是真正的盲文）查看码点：全部在 U+2800~U+28FF 范围意识到 256 个字符 = 一个字节每个码点减去 0x2800 即得 ASCII 值三、知识体系总结整个谜题集覆盖了 CTF（Capture The Flag）竞赛中 Misc 方向的核心知识领域：信号处理类： Level 1 (SSTV)：无线电图像传输协议 Level 2 (Morse)：经典电报编码 Level 5 (DTMF)：电话信令系统隐写术（Steganography）： Level 3 (Spectrogram)：音频频谱隐写 Level 4 (LSB)：图片最低有效位隐写 Bonus 1 (Zero-Width)：Unicode 零宽字符隐写编码与密码学： Level 6 (Multi-Cipher)：多层编码（Hex/Base64/ROT13） Bonus 2 (Tap Code)：Polybius 方阵替换密码 Bonus 3 (DNA)：自定义二进制编码方案 Bonus 4 (Braille)：Unicode 码点映射综合应用： Level 7 (QR Fragments)：融合频谱隐写 + 图像拼接 + 二维码扫描难度梯度：关卡按从易到难排列。Level 1–2 是入门级，只需找到正确的工具；Level 3–5 需要理解编码原理；Level 6 需要逐层分析；Level 7 和附加题需要综合运用多种技能。后续还添加了sidequest线 那首乌托邦里面藏的是lsb隐写得到密文 图片的星点图是以红点X坐标排序 Y为ASCII码 解出后得到密钥 最后就是答案最后恭喜解开谜题的参赛者我们明年有缘再见 sealwhichilike.jpeg 再玩一次？https://101121.notion.site/trythispuzzlepizza 我们将在本服务器停止后公开谜题制作脚本&校验脚本