base玩明白了
hint:BBBBig5???
给了一个加密的zip和一个JPG文件,丢进随波逐流,发现JPG文件尾存在额外数据

若00是分隔符,那么多的数据则为:
c46540cc76b79b
由提示猜测到是big5编码
得到:
46ZA90za2w==
用这个密码可以打开压缩包,打开后得到一个QRCode

注意到前面的得到的46ZA90za2w==,这串数字出现0\9\a\z\A \Z。猜测是Base62编码(与Base64比无+/=
),多次尝试后,得到解码key是a-z0-9A-Z

星夜回声档案
首先题目附件是伪加密,打开后得到一个dat

根据这段数据,提示我们倒过来读文件尾的数据:

再Baase64得到:

这段JSON数据意味着:
hint:从 offset 128 取 169 字节,ROT13 解码。ppm:从 offset 1024 取 989094 字节,整体反转得到星图。wav:从 offset 990118 取 60044 字节,逐字节 xor 35 得到音频。
rot13:
The sky does not hide words in plain sight.
Only the brightest points remember the route.
The echo is honest because it repeats.
A false note is louder than a true one
这段提示告诉我们看最明亮的点和关注虚假的声音
ppm:

- 遍历每个像素的
r, g, b,只挑选亮点像素,也就是max(r, g, b) >= 240的“星星”。 - 对这些亮点的
r/g/b分量分别取最低位& 1,拼成二进制比特流。 - 每 8 位转成 1 字节,得到隐藏数据。
- 在隐藏数据中查找
part1=,一直读到空字节\x00为止。 - 再从消息里提取
rhythm=...,进行 Base64 解码。
import base64
import re
dat = open("cosmic_archive.dat", "rb").read()
ppm = dat[1024:1024 + 989094][::-1]
open("stars.ppm", "wb").write(ppm)
tokens = ppm.decode("ascii").split()
values = list(map(int, tokens[4:]))
bits = []
for i in range(0, len(values), 3):
r, g, b = values[i:i+3]
if max(r, g, b) >= 240:
bits += [str(r & 1), str(g & 1), str(b & 1)]
data = bytes(int("".join(bits)[i:i+8], 2) for i in range(0, len(bits)//8*8, 8))
start = data.index(b"part1=")
msg = data[start:data.index(b"\x00", start)]
print(msg.decode())
rhythm = re.search(rb"rhythm=([A-Za-z0-9+/=]+)", msg).group(1)
print(base64.b64decode(rhythm).decode())
得到部分flag
part1=flag{F4k3_Zip_St4rs_;rhythm=Yzg6MmE=
Yzg6MmE=经过Base64解密后得到:
c8:2a
首先,WAV 参数是:单声道、8-bit、8000 Hz、60000 个采样点。
上一步星图里得到 rhythm=c8:2a,Base64 解码是 c8:2a,其中 0xc8 = 200,所以把 PCM 数据按每 200 个采样分块。
音频 hint 里说 “echo repeats / false note is louder”,所以用第 0 块作为重复回声基准,逐块比较差异。
发现几乎所有有效差异都集中在块内位置 137,这是被替换的“false note”。
取第 0 块该位置的原始字节,加上后续差异块该位置的字节,直到遇到分隔用的未变化块。
得到字节序列:[107, 68, 78, 117, 105, 26, 89, 71, 27, 73, 117, 111, 73, 66, 26, 87]
用 0x2a 逐字节异或,得到音频里的剩余部分:
And_C0sm1c_Ech0}
得到flag:flag{F4k3_Zip_St4rs_And_C0sm1c_Ech0}
