ISCC2020 Misc - 耳听为实
送分部分
题目地址: https://hikawa.ml/CTF/iscc-misc5/ear.rar
解压得到 ABC.mp3
是Maksim Mrvica - New Silk Road
联想到 MP3Stego
, 使用密码解压出隐藏数据
1 2 3
| flag is here! https://pan.baidu.com/s/1L3cq1CRVhvv6mq8qogq-sA dHc0aQ==
|
dHc0aQ==
base64解码得 tw4i
,看出是百度网盘的密码
下载后又是一个mp3
file一下,你就知道,这是个zip
binwalk解压得 ctf-produce.py
和 flag-RD.wav
ctf-produce.py 分析
flag-RD.wav
听起来像是杂讯,我们看看py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
| import wave import numpy as np import os
f = wave.open(os.path.abspath('./flag.wav'), 'rb')
params = f.getparams()
nchannels, sampwidth, framerate, nframes=params[:4]
str = f.readframes(nframes)
wave_data = np.fromstring(str, dtype=np.short)
time = np.arange(0, nframes) * (1.0 / framerate)
wlen = 100 inc = 50 signal_length = len(wave_data)
if signal_length <= wlen: nf = 1 else: nf = int(np.ceil((1.0*signal_length-wlen+inc)/inc))
pad_length = int((nf-1)*inc+wlen)
zeros = np.zeros((pad_length-signal_length), dtype=int)
pad_signal = np.concatenate((wave_data,zeros))
indices = np.tile(np.arange(0,wlen),(nf,1))+np.tile(np.arange(0,nf*inc,inc), (wlen,1)).T indices = np.array(indices, dtype=np.int32)
indices = np.random.permutation(indices)
frames = pad_signal[indices]
frames = frames.flatten()
w = wave.open(os.path.abspath('./flag-RD.wav'), "wb")
w.setnchannels(nchannels) w.setsampwidth(sampwidth) w.setframerate(framerate*2) w.writeframes(frames.tostring()) w.close() f.close()
|
总结一下
1 2 3 4 5 6 7 8 9 10
| 我们现在有一堆长度为50整倍数的数据,假设他是长度为150 [1,2,8,4,...77,12,54]无规律,是什么不重要 然后每行100,偏移50生成坐标矩阵 [0,1,2...,98,99] [50,51,52...148,149] 其中第n行的范围为[(n-1)*50, (n-1)*50+100-1],整数 然后打乱行 [50,51,52...148,149] [0,1,2...,98,99] 然后把对应坐标的数据填进去降维就是加密后的数据
|
所以我们只需要把数据读成 numpy.ndarray
在像拼拼图一样把数据按原来的顺序拼好就行啦
解密脚本
其实可以优化一下,这个是暴力
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| import wave import numpy as np import os
f = wave.open(os.path.abspath('./flag-RD.wav'), 'rb') params = f.getparams() nchannels, sampwidth, framerate, nframes=params[:4] str = f.readframes(nframes) res_data = np.frombuffer(str, dtype=np.short) res = []
for i in range(len(res_data)): if i % 2 == 0: res.append(res_data[i])
wave_data = np.array(res) time = np.arange(0, nframes) * (1.0 / framerate) wlen = 100 inc = 50 signal_length = len(wave_data) if signal_length <= wlen: nf = 1 else: nf = int(np.ceil((1.0*signal_length-wlen+inc)/inc)) pad_length = int((nf-1)*inc+wlen) zeros = np.zeros((pad_length-signal_length), dtype=int) pad_signal = np.concatenate((wave_data,zeros)) frames = pad_signal.reshape(len(pad_signal) // 100, 100) def force_cmp(a,b): if list (a)[:50] == list(b)[-50:]: return -1 elif list(b)[:50] == list(a)[-50:]: return 1 else: return 0
seed = list(frames[0]) while True: print(frames.shape[0]) for i in range(frames.shape[0]): if force_cmp(np.array(seed), frames[i]) == -1: tmp = list(frames[i])[:50] seed = tmp+seed frames = np.delete(frames,i,0) break elif force_cmp(np.array(seed), frames[i]) == 1: tmp = list(frames[i])[-50:] seed = seed+tmp frames = np.delete(frames,i,0) break if frames.shape[0] == 1: break
w = wave.open(os.path.abspath('./flag-res.wav'), "wb") w.setnchannels(nchannels) w.setsampwidth(sampwidth) w.setframerate(int(framerate/2))
res_str = np.array(seed) w.writeframes(res_str.tostring())
w.close() f.close()
|
然后用木耳听,细听
可以听到 The flag is 'password'