SHA2017 CTF Teaser round Writeup

この大会は2017/6/10 21:00(JST)~2017/6/11 5:00(JST)に開催されました。
今回もチームで参戦。結果は650点で462チーム中7位でした。
自分で解けた問題をWriteupとして書いておきます。

Crypto Engine (Crypto 200)

いろいろ試して出力される色のRGBの組を確認する。まずは以下の点がわかる。

・3文字で一つのセルが生成される。
・3の倍数の文字でない場合は、3で割った余りの文字数分8ビットの16進数が表記されている。

このことからフラグの文字数は38文字であることがわかる。XORで算出された結果を色で表していると推測しながら、38文字でいろいろ試す。

■abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLの場合
RGB: 83 82 82 83 54 52 53 59 95 94 94 87 50 48 49 39 67 66 66 83 54 52 53 43 79 78 116 105 12 10 49 47 75 66 120 101 | 0x00 0x0e
文字列とRGBのXOR:
[50, 48, 49, 55, 83, 82, 82, 83, 54, 52, 53, 59, 95, 94, 94, 87, 50, 48, 49, 39, 67, 66, 66, 83, 54, 52, 53, 43, 79, 78, 116, 105, 12, 10, 49, 47, 75, 66]

■ZUHadnaopwefvnsudhaaiTjaksUkladauULandの場合
RGB: 104 101 121 86 12 11 24 57 124 124 125 95 10 18 14 42 110 122 111 75 7 46 5 42 108 93 80 65 0 60 52 32 117 105 120 65 | 0x1b 0x0d
文字列とRGBのXOR:
[50, 48, 49, 55, 104, 101, 121, 86, 12, 11, 24, 57, 124, 124, 125, 95, 10, 18, 14, 42, 110, 122, 111, 75, 7, 46, 5, 42, 108, 93, 80, 65, 0, 60, 52, 32, 117, 105]

■YZabcdefghijklMNOPqrstuVWxyzhaAjadsKKKの場合
RGB: 107 106 80 85 8 14 53 51 111 102 92 89 4 10 17 23 75 90 96 101 56 46 21 51 111 86 108 73 7 55 45 35 102 83 94 104 | 0x2d 0x18
文字列とRGBのXOR:
[50, 48, 49, 55, 107, 106, 80, 85, 8, 14, 53, 51, 111, 102, 92, 89, 4, 10, 17, 23, 75, 90, 96, 101, 56, 46, 21, 51, 111, 86, 108, 73, 7, 55, 45, 35, 102, 83]

■ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklの場合
RGB: 115 114 114 115 54 52 53 59 127 126 126 119 50 48 49 39 99 98 98 115 54 52 53 43 111 110 84 73 12 10 49 47 107 98 88 69 | 0x00 0x0e
文字列とRGBのXOR:
[50, 48, 49, 55, 115, 114, 114, 115, 54, 52, 53, 59, 127, 126, 126, 119, 50, 48, 49, 39, 99, 98, 98, 115, 54, 52, 53, 43, 111, 110, 84, 73, 12, 10, 49, 47, 107, 98]

以上を見ていて以下のことに気が付いた。

・XORキーの最初の4バイトは固定:50, 48, 49, 55
・XORキーの5バイト以降はRGBの値を順に並べている。

このことから復号コードを書く。

from PIL import Image

img = Image.open('flag.png').convert('RGB')
w, h = img.size

key = [50, 48, 49, 55]
enc = []
for x in range(1, w, 40):
    r, g, b = img.getpixel((x, 1))
    key.append(r)
    key.append(g)
    key.append(b)
    enc.append(r)
    enc.append(g)
    enc.append(b)
del key[-2:]
enc.append(0x2e)
enc.append(0x29)

flag = ''
for i in range(len(enc)):
    flag += chr(key[i] ^ enc[i])

print flag

この結果フラグがゲットできた。

flag{deaf983eb34e485ce9d2aff0ae44f852}