2026.8.10(8)【Misc】消失的Yui

📌 题目信息

项目内容
题目名称消失的Yui
题目来源青少年CTF S1·2026 公益赛(投稿题)
题目类型Misc
子分类零宽字符 / Base100 / RC4 / 地理坐标
考点零宽字符隐写、emoji(Base100)编码、压缩包、二维码、RC4解密、坐标定位
难度⭐⭐⭐⭐
最终 Flagflag{hefei}

题面:你是A市的警官,负责找到离奇失踪的作家Yui,你找到了一些线索,觉得事情大有蹊跷……

🛠️ 使用工具

  • 零宽字符解码:提取文本中隐藏信息(格式提示)
  • Base100 解码(emoji → 字符串):得压缩包密码
  • zbarimg / 扫码工具:读取二维码
  • Python3:RC4 解密、(可选)零宽字符解析

📝 解题思路

一道剧情化套娃题,线索一层套一层:

最后的作品.txt
  ├─ 零宽字符 → 格式提示 flag{当前所在城市英文名(小写)}
  └─ emoji串(Base100) → 压缩包密码 TrY_to_F1Nd_m3
        └─ 解压 yui的房间.zip
             ├─ under_the_sea.jpg(二维码) → RC4密文
             └─ 时间的谜语.txt → 拼出RC4密钥 1145141919810
                  └─ RC4解密 → 经纬度 → 定位城市(合肥) → flag

第 1 步:从初始文本提取线索

什么是零宽字符

零宽字符(Zero-width characters)是一类"看不见、但真实存在"的 Unicode 字符——它们占位置,但显示时宽度为 0,所以肉眼看不到痕迹,但程序能读出来。

常用几种:

名称UnicodePython 转义作用
ZWSP(零宽空格)U+200B\u200b常见隐写载体
ZWNJ(零宽不连字)U+200C\u200c常见隐写载体
ZWJ(零宽连字)U+200D\u200d常见隐写载体(还影响 emoji 组合)
BOM(字节序标记)U+FEFF\ufeff有时也被利用
ZWJ-no-breakU+2060\u2060少见

为什么能隐写:把一段"隐藏信息"用 2~3 种零宽字符编码成二进制(比如 \u200c=0、\u200d=1),穿插在正常文字中间。人眼看不出来,但解码程序能提取出来。这就是零宽字符隐写(Zero-width steganography)

⚠️ 举例:你好 vs 你\u200c\u200d\u200c你好 显示完全一样,但后者藏了 3 位二进制。

最后的作品.txt 是一大段小说文本,但里面藏着:

  • 零宽字符(如 \u200c ZWNJ、\u200d ZWJ、\ufeff),肉眼看不见(vscode可以看见)。
  • 解码后给出格式提示
    #这是关于flag的提示,后面要用
    flag{当前所在城市英文名(小写)}
    
  • 文本中还有很多 emoji,用 Python 提取 emoji:
    import re
    s = open('最后的作品.txt', encoding='utf-8').read()
    emojis = re.findall(r'[\U0001F300-\U0001FAFF]', s)
    print(''.join(emojis))   # 👫👟👜👧...
    

第 2 步:Base100 解码 emoji → 得到压缩包密码

emoji 串是 Base100 编码(用 emoji 表示信息)。用 Base100 工具/库解码:

👫👟👜👧👘👪👪📦💳💑👋👩👐👖👫👦👖🐽🐨👅👛👖👤🐪
↓ Base100 解码
TrY_to_F1Nd_m3

得到 yui的房间.zip 的解压密码。
解压yui的房间.zip,得到如下内容:


第 3 步:二维码 → Base64编码文本

under_the_sea.jpg里是二维码,扫码得到 Base64 格式的文本

z2qbTYV1U4vpBNoL7jEGcAFyrLpTnlNQdi4OuFxsFl8=

Base64 解码 → 得到一堆二进制乱码(不是可读文本)
看到乱码 → 说明它不是"明文文本的 Base64",而是加密/压缩后数据的 Base64"

最后结果多次尝试,得到本题出题时的加密过程:

  明文
   │  RC4加密
   ▼
二进制密文(乱码)
   │  Base64编码
   ▼
Base64密文: z2qbTYV1U4vpBNoL7jEGcAFyrLpTnlNQdi4OuFxsFl8=
   │  存进二维码
   ▼
扫码得到的那串 Base64

为什么这道题优先锁定 RC4(核心判断依据):

  • 线索 1:只给了一串密钥,没有 IV ,绝大多数工作模式都必须搭配 IV(初始向量)才能正常解密;而 RC4 是经典的流加密算法,只需要一个密钥即可完成加解密,完全匹配题目给出的条件。
  • 线索 2: AES 等分组加密会有固定块大小的填充(比如 16 字节对齐),密文长度一定是块大小的整数倍,和本题特征不符。
  • 线索 3:CTF 入门赛的高频考点。青少年 CTF、入门级赛事的加密考点里,RC4 是流加密的头号考点,出题频率远高于 Salsa20、ChaCha20 等其他流加密算法。

第 4 步:从「时间的谜语」拼出 RC4 密钥

时间的谜语.txt 分四段,每段藏一个数字线索:

段落线索数字
钟楼指针凝固在十一时四十五分1145
档案柜编号14191419
1981年学术期刊1981
仪器刻度盘零点熵增阈值0

按顺序拼接密钥:

1145 + 1419 + 1981 + 0 = 1145141919810

⚠️ 易错点:注意"十一时四十五分"要写成 1145(不是 11:45 或带冒号);"仪器零点"是数字 0,要拼在末尾作为第 4 段。四段顺序必须一致,少一段/顺序错都会导致 RC4 解不出来。


第 5 步:RC4 解密 → 坐标 → 定位城市

用密钥 1145141919810 对密文做 RC4 解密

import base64

def rc4(key, data):
    S = list(range(256)); j = 0
    for i in range(256):
        j = (j + S[i] + key[i % len(key)]) % 256
        S[i], S[j] = S[j], S[i]
    i = j = 0; out = bytearray()
    for b in data:
        i = (i + 1) % 256; j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        out.append(b ^ S[(S[i] + S[j]) % 256])
    return bytes(out)

key = b"1145141919810"
cipher = base64.b64decode("z2qbTYV1U4vpBNoL7jEGcAFyrLpTnlNQdi4OuFxsFl8=")
print(rc4(key, cipher).decode())

输出:

31°49′14″N 117°13′38″E

这个坐标(约 31.82°N, 117.23°E)指向安徽省合肥市

⚠️ 易错点:RC4 密钥是字节串b"..."),Base64 密文要先 b64decode 成二进制再喂给 RC4。坐标用度分秒(DMS)表示,31°49′14″N = 31+49/60+14/3600 度;换算后对应合肥。


第 6 步:按格式提示组装 flag

第 1 步的零宽字符提取已提示flag格式:flag{当前所在城市英文名(小写)}
坐标位于合肥,英文名小写为 hefei


✅ 最终 Flag

flag{hefei}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值