Try   HackMD

[InterKosenCTF 2019] Hugtto!

tags: InterKosenCTF 2019, forensics

概要

emiru.pngに対してflagを隠す処理をして結果とスクリプトをtar.gzにまとめている。処理の内容は単純で、0〜2の乱数によってr, g, bの下位1ビットにビットを格納している。
乱数のシードを知る必要があるが、tar.gzが生成された時刻に近いのでそれを利用する。

解法

tarでタイムスタンプを見てみる。

$ tar -t -v --full-time -f hugtto.tar.gz
-rw-rw-r-- ptr/ptr     1346615 2019-08-01 14:07:10 ./steg_emiru.png
-rw-rw-r-- ptr/ptr        1009 2019-08-01 14:06:22 steg.py

タイムゾーンや画像処理の方向が縦であることなどに注意してデコーダを書く。

from PIL import Image
import random
import datetime

img = Image.open("steg_emiru.png")
width, height = img.size

bin_prefix = []
for c in "KosenCTF{":
    for i in range(8):
        bin_prefix.append((ord(c) >> i) & 1)

approx = int(datetime.datetime.strptime(
    '2019-08-01 14:00:00', '%Y-%m-%d %H:%M:%S'
).timestamp())

for seed in range(approx, approx + 0x1000):
    random.seed(seed)
    bin_flag = []
    for i in range(len(bin_prefix)):
        x, y = i // width, i % width
        rnd = random.randint(0, 2)
        r, g, b = img.getpixel((x, y))
        if rnd == 0: bin_flag.append(r & 1)
        if rnd == 1: bin_flag.append(g & 1)
        if rnd == 2: bin_flag.append(b & 1)
        if bin_flag[i] != bin_prefix[i]:
            break
    else:
        print("[+] Found seed: {}".format(seed))
        break
else:
    print("[-] Invalid approx")
    exit(1)

random.seed(seed)
flag = ""
char = []
for i in range(8 * 128):
    x, y = i // width, i % width
    rnd = random.randint(0, 2)
    r, g, b = img.getpixel((x, y))
    if rnd == 0: char.append(r & 1)
    if rnd == 1: char.append(g & 1)
    if rnd == 2: char.append(b & 1)
    if len(char) == 8:
        x = 0
        for j in range(8):
            x |= char[j] << j
        flag += chr(x)
        char = []

print(flag)

はい。

KosenCTF{Her_name_is_EMIRU_AISAKI_who_is_appeared_in_Hugtto!PreCure}