GACTF Writeup

この大会は2020/8/29 19:00(JST)~2020/8/31 19:00(JST)に開催されました。
今回もチームで参戦。結果は359点で519チーム中156位でした。
自分で解けた問題をWriteupとして書いておきます。

SignIN (Misc)

切り貼りすると、QRコードになる。
f:id:satou-y:20200914222641j:plain
このQRコードを読み込む。

welc0me_t0_GACTF_have_Fun
GACTF{welc0me_t0_GACTF_have_Fun}

ezAES (Crypto)

keyは2バイトだけが不明。

SECRET: keyで決まる10バイト
message: 86バイト

暗号化
0 1 2 3 4 5 6 7 8 9 a b c d e f
a8**************************b1a9
23**************************0111
47**************************6e09
4e**************************cdb1
c7**********a32c412a3e7474e584cd
72481dab9dd83141706925d92bdd39e4

[平文1ブロック目] ^ IV                  --(暗号化)--> [暗号文1ブロック目]
[平文2ブロック目] ^ [暗号文1ブロック目] --(暗号化)--> [暗号文2ブロック目]
[平文3ブロック目] ^ [暗号文2ブロック目] --(暗号化)--> [暗号文3ブロック目]
[平文4ブロック目] ^ [暗号文3ブロック目] --(暗号化)--> [暗号文4ブロック目]
[平文5ブロック目] ^ [暗号文4ブロック目] --(暗号化)--> [暗号文5ブロック目]
[平文6ブロック目] ^ [暗号文5ブロック目] --(暗号化)--> [暗号文6ブロック目]

最後の16バイトの暗号化が分かっているので、ブルートフォースでそれを復号する。
チェック内容は以下の条件を満たすかどうかになる。

・平文6ブロック目の1バイト目と暗号文5ブロック目の1バイト目のXORが復号データの1バイト目
・平文6ブロック目の末尾10バイトと暗号文5ブロック目の末尾10バイトのXORが復号データの末尾10バイト

keyがわかったら、後ろのブロックから復号していくと、平文1ブロック目とIVのXORがわかる。平文1ブロック目とのXORによりIVがわかるので、それがフラグになる。

from Crypto.Cipher import AES
import itertools
import string
import hashlib

def pad(s):
    p = 16 - len(s) % 16
    return s + chr(p) * p

def str_xor(s1, s2):
    return ''.join(chr(ord(a) ^ ord(b)) for a, b in zip(s1, s2))

def get_msg(key):
    msg = 'AES CBC Mode is commonly used in data encryption. What do you know about it?'
    msg += hashlib.md5(key).digest()[:10]
    return msg

c5 = '72481dab9dd83141706925d92bdd39e4'.decode('hex')
c4_1 = 'c7'.decode('hex')
c4_2 = 'a32c412a3e7474e584cd'.decode('hex')

for c in itertools.product(string.letters + string.digits, repeat=2):
    key = 'T0EyZaLRzQmNe2' + ''.join(c)
    pad_msg4 = pad(get_msg(key))[-16:]
    aes = AES.new(key, AES.MODE_ECB)
    dec = aes.decrypt(c5)
    if str_xor(c4_1, pad_msg4[0]) == dec[0] \
        and str_xor(c4_2, pad_msg4[-10:]) == dec[-10:]:
        break

print '[+] key =', key

pad_msg = pad(get_msg(key))

pt_blocks = [pad_msg[i:i+16] for i in range(0, len(pad_msg), 16)]

ct_block = c5
for i in range(5):
    aes = AES.new(key, AES.MODE_ECB)
    dec = aes.decrypt(ct_block)
    ct_block = str_xor(dec, pt_blocks[-i-1])
    print '[+] ct_block =', ct_block.encode('hex')

aes = AES.new(key, AES.MODE_ECB)
dec = aes.decrypt(ct_block)
IV = str_xor(dec, pt_blocks[0])

flag = 'gactf{%s}' % IV
print flag

実行結果は以下の通り。

[+] key = T0EyZaLRzQmNe2pd
[+] ct_block = c70b38bbd268a32c412a3e7474e584cd
[+] ct_block = 4eea629633f4d9589791ac584817cdb1
[+] ct_block = 4765763869a74c4d22538ad4489c6e09
[+] ct_block = 233f21c19790307c1f0b551b29640111
[+] ct_block = a884ed307a7af7b003e81c46b928b1a9
gactf{9j_for_aes_cbc!!}
gactf{9j_for_aes_cbc!!}