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 字节:
$ file stego6.pngstego6.png: PNG image data, 100 x 100, 8-bit/color RGBA, non-interlaced$ wc -c stego6.png1965 stego6.png$ sha256sum stego6.png207ef63dfb3d052e347d0b91c9ad9523f8e8212505013030abdbdbd9ff8fa751 stego6.pngPNG 是块(chunk)结构,先用 pngcheck -v 走一遍每个块:
$ pngcheck -v stego6.pngFile: 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 chunkERRORS DETECTED in stego6.png结构很干净:IHDR、一个背景色块 bKGD、一个时间戳块 tIME、一个 IDAT、IEND。bKGD 和 tIME 都是普通元数据,没有藏东西。唯一的异常是最后一行:IEND 之后还有数据。
IEND 是 PNG 的结束标记,规范上文件到它就结束。这里 IEND 块结束于偏移 0x751,而文件长 0x7AD,即后面多出 92 字节。pngcheck 把声明结束点之后还有字节直接报告成 ERRORS DETECTED。
Step 2: Pixel analysis
PNG 隐写的另一条常见路径是把数据写入 IDAT 解码后的像素位平面(LSB)。用 zsteg -a 扫全部通道、全部位平面:
$ zsteg -a stego6.png | tr '\r' '\n' | sed '/^[[:space:]]*$/d' | head -n 12extradata: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 0b1,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:0:IEND 之后的 92 字节额外数据,内容是 Base64 文本。
Step 3: Payload
定位 IEND 块结束的位置,取出后面的字节:
#!/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 IENDchunk there are 92 extra bytes that are not part of the image stream: an ASCIIBase64 string. Decoding it yields a sentence that carries the password."""import base64import 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