HackThisSite - Steganography Mission 9
Challenge
Download the song Here kiss me alone
Solution
Analysis
1 | curl -sL -b "$HTS_COOKIE" -o Stego9.zip \ |
1 | Type = zip |
1 | Channels : 2 |
ZIP 里只有一个 40 秒、11025 Hz、16 bit 立体声的 WAV。单看左右声道各自都是一首连续的 电子舞曲,波形和频谱都很正常,秘密只在混音层面才会显形。
Step 1: WAV chunks
先按 WAV 的块结构逐块核对尾部附加数据,以及头部声明长度与实际文件长度的一致性:
1 | import struct |
1 | riff b'RIFF' file_size 1784818 |
data
块正好覆盖到文件结尾(58 + 1784760 = 1784818),没有任何尾部附加数据;
头部声明的长度也和真实文件一致。信息只能在 PCM 采样里。
Step 2: Channel inversion
分别看左右声道的能量和相关性:
1 | import wave |
1 | corr(L,R) = -0.999697 |
这一步就是全部关键。两个声道的相关系数是 -0.9997:右声道是左声道的反相副本。 所以:
- 现场听感正常,是因为播放器把两声道混合后音乐照旧;
L - R的幅度几乎是被乘了 2 倍的歌曲本身(std 37281 ≈ 2×18641);L + R却塌缩成 std 只有 459 的极小残差。
音乐在求和时被抵消,留下的 L + R
才是承载信息的信号。把它单独导出成单声道:
1 | import wave |
1 | residual std=458.9 absmax=1044 |
这个残差和歌曲本身几乎不相关(corr(L+R, L) = 0.0115),是一个独立的信号。
Step 3: Carrier
对残差做精细 FFT,看能量集中在哪:
1 | import wave |
1 | 998.6 Hz mag 963327.3 |
残差里几乎只有一个 约 1000 Hz 的纯载波(相邻几条谱线都挤在 1 kHz 附近, 是同一根载波在 FFT 分辨率上的展宽)。再用时间轴看它,按 100 ms 一格量载波的能量, 会发现它一段一段地通断:
1 | import wave |
1 | 517 249 1034 781 4 1019 1027 12 747 1017 271 495 1035 482 0 1 997 1006 23 708 994 283 394 856 513 222 1033 676 1 947 |
每 100 ms 的能量在接近 1000 和接近 0 两档之间来回跳,这正是通断键控(OOK), 把通断的时间长度读出来就是莫尔斯电码。
Step 4: Morse
对上一步的包络取阈值、做游程编码,按运行长度区分点 / 划和字符内间隔 / 字符间间隔 / 词间间隔,然后查表:
1 | import wave |
1 | on ms: [51, 201, 202, 202, 201, 202, 202, 202, 201, 202, 201, 201, 52, 50, 52, 52, 51, 52, 51, 51, 202, 52, 51, 52] |
时长分成非常干净的四档:
- 通 ≈ 51 ms(点)与 ≈ 201 ms(划),约 1:4;
- 断 ≈ 124 ms(字符内部间隔)、≈ 249 ms(字符之间)、≈ 499 ms(词之间),约 1:2:4。
按这个比例把游程翻译成 ./-,用 124/249/499
三档间隔切分字符和词:
1 | import wave |