HackThisSite - Programming Mission 7
Challenge
Level 7
This level is about image processing, inspired by pay-tv cracking. Code a program which is able to automatically unscramble the lines of a given image. Type in all characters from the image. Begin with the upper line, and add the lower line without a blank in between.
限时 180 秒:GET /missions/prog/7/
生成随机实例(图在 /missions/prog/7/BMP),
POST /missions/prog/7/index.php 字段
solution。
图像结构
实例图是 200×100 的 PNG(Content-Type: image/png,注意
/missions/prog/7/BMP 会 301 到带尾斜杠的地址, 用
curl -L 或直接请求 /BMP/,否则可能拿到 0 字节
body)。
对像素做颜色统计就能一眼看出结构:
1 | shape (100, 200, 3) |
- 只有两个颜色的像素数在 800 以上(1031 / 871),它们就是两行文字的字形颜色;
- 其余颜色每个只有 4–6 个像素,是逐像素噪声(不是行级噪声);
- 两种字形色各自的 27–28 行散布在整幅图的高度上(span 3–98 / 7–91),说明加扰是行置换: 原始图的两行文字,它们的像素行被打乱后均匀撒在整张图里。
这就给出还原思路:先判断每一行原本在图像里的纵坐标,再把每个颜色的行按这个坐标排序,就能把两行文字拼回来。
行序判定:B 通道中值
背景是一条垂直渐变,B
通道随行号单调变化;而行置换并不改变每一行的像素内容,
于是每一行自身的 B
通道统计量就保留了它原来的纵坐标信息。实测
(min+max)/2(midrange)足够稳定:
1 | import numpy as np |
对每个字形色取出它的行、按 rank 排序后渲染(白底黑字、5
倍放大),就得到两段干净的字形条带:
1 | colour A (129, 127, 77): 27 rows -> ranks [8, 10, 12, ..., 46, 48, 49] |
注意这里的 rank 是从下往上计数的(rank
0 = 底部):色带 B 的 rank 均值更大,
说明它原本位于上面那一行;所以拼接顺序必须是 B 的文字 +
A 的文字。
读出字符
条带放大 5 倍后字形是纯黑白的点阵,逐像素打成 ASCII 就能直接读 (也可以直接交给视觉模型读同一张图,两者结果一致):
1 | line 1 (strip B): J 6 7 L 3 6 |
Submit
同一个实例的提交实测(每行是 solution=<串>
的返回判定):
1 | submit 'ME5FEYJ67L36' -> ok=False bad=True # 先上后下、但左右顺序错 |
被接受后 profile 的 Programming 列表出现 (7),积分
6919。
Key points
- 图像加扰(置乱行)不构成任何机密性:每一行的内容完好无损,背景渐变反而成了免费的坐标编码器。 任何能读像素统计的对手都能在毫秒级还原;真实世界的付费电视加扰最终也是被同类思路破解的。
- 真正需要内容保护时应该在压缩/加密层处理,而不是在像素排列上做手脚。
- 工程层面值得记的一点:限时关卡必须把读数→提交做成单进程,
本例
fetch → 排序 → 渲染实测 1.93 秒,读字用视觉模型也在 180 秒预算内。