📌 题目信息
| 项目 | 内容 |
|---|---|
| 题目名称 | 找到呆唯 |
| 题目来源 | 青少年CTF S1·2026 公益赛(投稿题) |
| 题目类型 | Misc |
| 子分类 | 压缩包爆破 / JPEG隐写 / Base64解码 |
| 考点 | 字典爆破、JPEG COM 注释段隐写、多重 Base64、二维码 |
| 难度 | ⭐⭐⭐ |
| 最终 Flag | flag{iam_here!!!} |

题面:呆唯走丢了,找到她,她会告诉你 flag 的。
🛠️ 使用工具
- unzip / fcrackzip:压缩包密码爆破
- Python3:Base64 解码、JPEG 段解析、提取隐藏数据
- zbarimg:二维码扫描识别
- binwalk / file:文件类型判断
📝 解题思路
题目给两个附件:
提示.zip(加密,需爆破密码)which_kind_of_Base64.txt(Base64 文本,/9j/开头 → 实为 JPEG)
流程分三步:
- 爆破压缩包:结合提示"喜欢符号和数字",符号+数字组合爆破,得到密码
1/45*,解出工具提示; - 解码 Base64 → JPEG → 提取隐写:Base64 解码出 JPEG,其 COM 注释段(
FF FE) 里藏了另一段 Base64,解码后提取出隐藏的 PNG(二维码); - 扫码:识别二维码得到 flag。
第 1 步:爆破压缩包密码,并解码“可能用到的工具.txt”
提示.zip 加密,zip 内有个目录叫「我喜欢符号和数字哦」,提示密码只含符号和数字。用字典/掩码爆破(符号集如 !@#$%^&*()_+-=/? × 数字 0-9),命中密码:

1/45*
用密码解压,得到 提示/可能用到的工具.txt:

解码 txt,得到隐写工具链接(关键提示):
可能用到的工具.txt 里是「就 这 ¿」和「不 会 吧 ?」两种词组的重复(字间有空格)。这是两态(二进制)编码,所以可以转换成0/1编码,转换后尝试 8 位一组转换成ASCII,但本题比较特殊,不是 8 位一组——经尝试,正确分组是 9 位一组:
import re
s = open('可能用到的工具.txt', encoding='utf-8').read()
# 提取两种词组的顺序(去掉空格)
tokens = re.findall(r'就这|不会吧', s.replace(' ', ''))
# 就这→0, 不会吧→1
binseq = ''.join('0' if t == '就这' else '1' for t in tokens)
print(len(binseq)) # 468, 468//9 = 52, 整除
# 9位一组转字符
out = ''.join(chr(int(binseq[i:i+9], 2)) for i in range(0, len(binseq), 9))
print(out)

解码结果:
https://tools.cmdragon.cn/zh/apps/steganography-tool
这个链接是 CMDragon 的「文件隐写工具」——把文件隐藏到 JPG 图像的在线工具。这就是解题工具提示。
⚠️ 易错点:这组两态文本不是标准 8 位 ASCII 二进制,用 8 位分组会得到乱码;正确是 9 位一组(468 = 9×52)。所以看到"两种词重复"先别急着按常规二进制解,先算总位数能否整除、多试几种位宽(7/8/9)。
⚠️ 工具说明:这个在线工具在 JPG 的注释/字段里写入隐藏文件并用自定义格式标记(本题里是
STEGO37880:头 + base64)。
第 2 步:Base64 解码 which_kind_of_Base64.txt 得到 JPEG 图
由于题目提示了JPG 图像隐写工具网站,而且which_kind_of_Base64.txt 开头是 /9j/——标准 Base64 的 JPEG 头(/9j/ 解码 = \xff\xd8\xff)。因此用标准 Base64 解码:
import base64
raw = open('which_kind_of_Base64.txt','rb').read().strip()
data = base64.b64decode(raw) # 标准 Base64
open('img.jpg','wb').write(data) # 得到 JPEG
# 文件头 ffd8fffe ... 说明是 JPEG

第 3 步:解析 JPEG 的 COM 注释段(FF FE)
exiftool 是干什么的:
exiftool 是一个功能强大的命令行工具,主要用来读取 / 写入 / 编辑各种文件的元数据(metadata)。核心能力:
- 读元数据:图片(EXIF、GPS、拍摄参数)、视频、PDF、Office 文件等的内置信息
- 写/改元数据:改拍摄时间、作者、GPS 坐标等
- 解析文件内部结构:包括 JPEG 的各个段(APP0/APP1/EXIF/COM 等)
- CTF 里最有用的:快速暴露藏在元数据/注释段里的字符串(比如这里的
STEGO37880base64)
它支持几百种文件格式,是取证/CTF 的常规武器之一。
exiftool img.jpg

关键发现:COM 段内容以 STEGO37880: 开头(这就是那个JPG 图像隐写工具网站的关键特征!!),后面紧跟一大段 Base64(UAAAAH...)。
⚠️ JPEG 结构速记:
FF D8文件头FF E0APP0(JFIF)FF E2APP2(ICC)FF FECOM 注释段 ← 常用来藏数据FF DB量化表、FF C4Huffman 表、FF DASOS(之后是图像数据)
第 4 步:提取 STEGO37880 后的隐藏 PNG
STEGO37880 是隐写工具的标识/头。把它后面的 Base64 解码,得到 P\x00\x00\x00 + JSON 元数据 + 隐藏的 PNG:
# -*- coding: utf-8 -*-
"""读取当前目录JPEG的COM(FF FE)注释段, 提取STEGO37880后的base64解码为PNG"""
import base64
# ---------- 第一步: 读取jpg并解析COM段 ----------
jpg_name = "img.jpg" # 改成你的jpg文件名
with open(jpg_name, 'rb') as f:
data = f.read()
print(f"JPEG大小: {len(data)} 字节")
# 遍历JPEG段, 找 FF FE (COM) 段
com_content = None
i = 2
while i < len(data) - 1:
if data[i] != 0xFF:
i += 1
continue
marker = data[i+1]
if marker == 0xD8 or marker == 0xD9 or 0xD0 <= marker <= 0xD7:
i += 2
continue
seglen = (data[i+2] << 8) | data[i+3] # 段长度(大端,含自身2字节)
if marker == 0xFE: # COM 注释段
com_content = data[i+4 : i+2+seglen]
print(f"找到 COM 段 @偏移{i}, 长度={seglen}")
break
i += 2 + seglen
if marker == 0xDA:
break
if com_content is None:
print("没有找到 COM(FF FE) 段")
exit()
print("COM内容开头:", com_content[:50])
# ---------- 第二步: 提取 STEGO37880: 后的 base64 ----------
idx = com_content.find(b'STEGO37880')
if idx == -1:
print("没找到 STEGO37880 标记")
exit()
b64 = com_content[idx+len(b'STEGO37880'):]
b64 = b64.decode(errors='replace').strip()
if b64.startswith(':'):
b64 = b64[1:] # 去掉冒号
print("base64字符串长度:", len(b64))
# ---------- 第三步: base64解码, 提取PNG ----------
pad = (4 - len(b64) % 4) % 4
d = base64.b64decode(b64 + '='*pad) # 补padding
print("解码长度:", len(d))
png_sig = d.find(b'\x89PNG\r\n\x1a\n') # 找PNG签名
if png_sig == -1:
print("没找到PNG签名")
exit()
png = d[png_sig:]
# 裁剪到 IEND 结束(避免尾部CRC错)
iend = png.rfind(b'IEND')
if iend >= 0:
png = png[:iend+12]
open("qr.png", 'wb').write(png)
print(f"已保存二维码: qr.png (长度 {len(png)})")
# ---------- 第四步(可选): 直接用pyzbar扫 -----------------
try:
from PIL import Image
from pyzbar.pyzbar import decode
im = Image.open("qr.png")
res = decode(im)
for r in res:
print("QR内容:", r.data.decode())
except Exception as e:
print("扫码步骤(可选)跳过:", e)

说明:
- 解码开头:
b'P\x00\x00\x00{"name":"haha.png","type":"image/png","size":28326,...}'—— 是一段 JSON 头 + 尾随的 PNG 二进制。 - 提取出的 PNG 是 400×400 的二维码图。
第 5 步:扫码获取 Flag
用 zbarimg(或手机扫码)识别二维码图获取flag。
✅ 最终 Flag
flag{iam_here!!!}
【Misc】找到呆唯&spm=1001.2101.3001.5002&articleId=163948907&d=1&t=3&u=fe2fa42d6e5a49599fbbd8fb59f1828e)
402

被折叠的 条评论
为什么被折叠?



