01(矩阵二维码+兽音编码)

题目信息

题目目录下有两个关键文件:

  • hint.txt

  • flag.zip

flag.zip 中包含加密文件 flag.txt,需要先找到压缩包密码。

1. 分析 hint.txt

打开 hint.txt 后可以看到 25 行由 01 组成的内容:

1111111011111001001111111
1000001000000001101000001
1011101000100010101011101
...
1111111000010001000011011

每行长度都是 25,因此可以判断它是一个 25 x 25 的黑白矩阵。25 x 25 对应 QR Code Version 2。

1 作为黑色,0 作为白色渲染后,可以得到一个二维码。

解码二维码,内容为:

p@ssw0rd!

所以压缩包密码是:

p@ssw0rd!

2. 解压 flag.zip

使用上一步得到的密码解压 flag.zip,得到 flag.txt

解压出的内容不是明文 flag,而是一串由 ~ 组成的文本:

~呜喵喵喵喵呜啊喵啊呜呜喵呜呜~喵喵~啊喵啊呜喵喵...

3. 识别兽音编码

这类文本是常见的“兽音译者”编码。

其特征是:

  • 字符集通常只有 4 个字符

  • 本题使用的是 ~

  • 文本以 ~呜喵 开头

  • 文本以 结尾

兽音译者的解码逻辑大致如下:

  1. 去掉头部 ~呜喵

  2. 去掉末尾

  3. 每两个兽音字符表示一个 4-bit 数据

  4. 按动态偏移还原 nibble

  5. 每 4 个 nibble 还原一个 Unicode 字符

本题使用的字符顺序为:

喵 呜 啊 ~

解码脚本如下:

import zipfile
​
with zipfile.ZipFile("flag.zip") as zf:
    s = zf.read("flag.txt", pwd=b"p@ssw0rd!").decode("utf-8")
​
dict_chars = "喵呜啊~"
prefix = "~呜喵"
suffix = "啊"
​
body = s[len(prefix):-len(suffix)]
idx = {ch: i for i, ch in enumerate(dict_chars)}
​
nibbles = []
offset = 0
​
for i in range(0, len(body), 2):
    pair = body[i:i + 2]
    val = (idx[pair[0]] << 2) | idx[pair[1]]
    n = (val - offset) & 0xF
    nibbles.append(n)
    offset += 1
​
plain = ""
​
for i in range(0, len(nibbles), 4):
    code = (
        (nibbles[i] << 12)
        | (nibbles[i + 1] << 8)
        | (nibbles[i + 2] << 4)
        | nibbles[i + 3]
    )
    plain += chr(code)
​
print(plain)

运行后得到:

flag{8a8c0a039c3bd6fb50e84b047e42e8e6}

Flag

flag{8a8c0a039c3bd6fb50e84b047e42e8e6}

颜色换成非白色显现第一部分flag

全选文本点击字体,选择文字->取消隐藏出现第二部分flag

改文件后缀为zip

解压之后在word文件夹下发现存在txt,打开第三部分flag

Flag:flag{I_be1ieve_y0u_Can_flnd_+h3m}