about 4 years ago

海報探秘

先用 ImageMagick 來觀察一番。

$ identify post.png
post.png PNG 1003x654 1003x654+0+0 8-bit DirectClass 496KB 0.000u 0:00.000

毫無反應,就是張圖片?讓我們看更仔細一點。

$ identify -verbose post.png
identify: Extra compressed data. `post.png' @ warning/png.c/MagickPNGWarningHandler/1335.
identify: Extra compression data. `post.png' @ warning/png.c/MagickPNGWarningHandler/1335.
identify: Too many IDAT's found `post.png' @ error/png.c/MagickPNGErrorHandler/1309.
identify: corrupt image `post.png' @ error/png.c/ReadPNGImage/3294.

看起來後面有偷塞東西?認真讀個 PNG 的 spec,想辦法撈出多餘的資料。

#include <bits/stdc++.h>
#include <zlib.h>

typedef unsigned char Byte;

inline unsigned convert_uint(Byte *b) {
    unsigned ret = 0;
    for (int i = 0; i < 4; i++) ret = ret << 8 | b[i];
    return ret;
}

Byte chunk_len_buf[4];
Byte chunk_name[4];
Byte chunk_data[8 << 10];
Byte raw_data[8 << 20];

int main(int argc, char *argv[]) {
    FILE *fin = fopen(argv[1], "r");
    FILE *fout = fopen(argv[2], "w");
    fseek(fin, 8 + 4 + 4 + 13 + 4, SEEK_CUR); // skip header

    z_stream zs;
    memset(&zs, 0, sizeof(zs));
    inflateInit(&zs);
    zs.next_out = raw_data;
    zs.avail_out = sizeof(raw_data);

    while (fread(chunk_len_buf, 1, 4, fin) == 4) {
        unsigned chunk_len = convert_uint(chunk_len_buf);
        fread(chunk_name, 1, 4, fin);
        fread(chunk_data, 1, chunk_len, fin);
        fseek(fin, 4, SEEK_CUR); // skip crc
        if (memcmp(chunk_name, "IDAT", 4) == 0) {
            zs.next_in = chunk_data;
            zs.avail_in = chunk_len;
            inflate(&zs, Z_SYNC_FLUSH);
        }
    }

    inflateEnd(&zs);
    
    unsigned raw_png_len = 1003 * 654 * 4 + 654;
    unsigned out_len = sizeof(raw_data) - zs.avail_out - raw_png_len;
    fwrite(raw_data + raw_png_len, 1, out_len, fout);

    fclose(fin);
    fclose(fout);
    return 0;
}

編譯並跑跑。

$ g++ poster.cpp -o poster -lz
$ ./poster post.png data

拿到些什麼呢?

$ file data
data: Gameboy ROM: "PAINT", [ROM ONLY], ROM: 256Kbit

歐歐歐,用 OpenEmu 跑起來。

這啥?Google 一下可以發現 Konami Code

嘗試輸入 ↑ ↑ ↓ ↓ ← → ← → B A 後,它就開始畫 flag 了!

最後一步是想辦法辨別出 1lI 之間的差別,耶比 BCTF{1-l0v3-p14yIng-g4m3s}

← Boston Key Party CTF 2014 Decrypt Img BCTF 超級加解密 Writeup →