HackThisSite - Steganography Mission 6

Challenge

A PNG image is provided. The only hint is Thank you Leafman. 题目提供了一张 PNG 图片,唯一的提示是 Thank you Leafman(感谢 Leafman)。

数据文件在 https://www.hackthissite.org/missions/stego/lvl/stego6.png,是一个 100x100 的 RGBA PNG。

Solution

Step 1: Container

file 只认出这是 100x100 的 8-bit RGBA PNG,共 1965 字节:

1
2
3
4
5
6
$ file stego6.png
stego6.png: PNG image data, 100 x 100, 8-bit/color RGBA, non-interlaced
$ wc -c stego6.png
1965 stego6.png
$ sha256sum stego6.png
207ef63dfb3d052e347d0b91c9ad9523f8e8212505013030abdbdbd9ff8fa751 stego6.png

PNG 是块(chunk)结构,先用 pngcheck -v 走一遍每个块:

1
2
3
4
5
6
7
8
9
10
11
12
$ pngcheck -v stego6.png
File: stego6.png (1965 bytes)
chunk IHDR at offset 0x0000c, length 13
100 x 100 image, 32-bit RGB+alpha, non-interlaced
chunk bKGD at offset 0x00025, length 6
red = 0x00ff, green = 0x00ff, blue = 0x00ff
chunk tIME at offset 0x00037, length 7: 12 Nov 2007 13:51:36 UTC
chunk IDAT at offset 0x0004a, length 1779
zlib: deflated, 32K window, default compression
chunk IEND at offset 0x00749, length 0
additional data after IEND chunk
ERRORS DETECTED in stego6.png

结构很干净:IHDR、一个背景色块 bKGD、一个时间戳块 tIME、一个 IDAT、IEND。bKGDtIME 都是普通元数据,没有藏东西。唯一的异常是最后一行:IEND 之后还有数据

IEND 是 PNG 的结束标记,规范上文件到它就结束。这里 IEND 块结束于偏移 0x751,而文件长 0x7AD,即后面多出 92 字节。pngcheck 把声明结束点之后还有字节直接报告成 ERRORS DETECTED。

Step 2: Pixel analysis

PNG 隐写的另一条常见路径是把数据写入 IDAT 解码后的像素位平面(LSB)。用 zsteg -a 扫全部通道、全部位平面:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ zsteg -a stego6.png | tr '\r' '\n' | sed '/^[[:space:]]*$/d' | head -n 12
extradata:0 .. text: "Tm90IGxpa2UgaXQncyBoYXJkIHRvICdkZWNyeXB0JyB0aGlzIGh1aD8gVGhlIHBhc3N3b3JkIGlzIGhnYnZadzA3Lg=="
chunk:0:IHDR .. file: Adobe Photoshop Color swatch, version 0, 100 colors; 1st RGB space (0), w 0x64, x 0x806, y 0, z 0; 2nd RGB space (0), w 0, x 0, y 0, z 0
b1,r,lsb,xy ..
b1,r,msb,xy ..
b1,g,lsb,xy ..
b1,g,msb,xy ..
b1,b,lsb,xy ..
b1,b,msb,xy ..
b1,a,lsb,xy ..
b1,a,msb,xy ..
b1,rgb,lsb,xy ..
b1,rgb,msb,xy ..

zsteg -a 的原始输出用 \r 分隔通道,这里用 tr 归一化成每行一个通道再看。)

所有 bN,channel,lsb/msb 位平面要么为空,要么只是 text: ["U" repeated 21 times] 这类单字符重复的噪声(那是图像本身大色块的规律,不是文本),没有一处读出可读字符串。第 2 行 chunk:0:IHDR 是 zsteg 把 IHDR 头字节误认成 Photoshop 色板,与本题无关。zsteg 唯一有效的一行是 extradata:0IEND 之后的 92 字节额外数据,内容是 Base64 文本。

Step 3: Payload

定位 IEND 块结束的位置,取出后面的字节:

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
#!/usr/bin/env python3
"""HackThisSite Steganography 6 - extract the appended payload from stego6.png.

The PNG container is normal (IHDR / bKGD / tIME / IDAT / IEND). After the IEND
chunk there are 92 extra bytes that are not part of the image stream: an ASCII
Base64 string. Decoding it yields a sentence that carries the password.
"""
import base64
import sys


def extract(path):
data = open(path, "rb").read()
i = data.find(b"IEND") # IEND is unique in a valid PNG
end = i + 8 # chunk length(4) + type(4) = end of IEND
trailer = data[end:].strip() # everything after the PNG stream
message = base64.b64decode(trailer).decode("ascii")
return end, trailer.decode("ascii"), message


def main():
path = sys.argv[1] if len(sys.argv) > 1 else "stego6.png"
end, b64, message = extract(path)
print("IEND ends at offset:", hex(end))
print("trailing bytes :", len(b64))
print("Base64 :", b64)
print("decoded message :", message)


if __name__ == "__main__":
main()
hgbvZw07