Hackover CTF 2016 Writeup

この大会は2016/10/8 3:00(JST)~2016/10/9 21:00(JST)に開催されました。
今回もチームで参戦。結果は44点で776チーム中53位でした。
自分で解けた問題をWriteupとして書いておきます。

rollthedice (crypto)

Go言語のスクリプトが添付されている。概要は以下の通り。
・16バイトのキーで16バイトのメッセージがAES暗号化されて提示される。
・提示されたメッセージの平文の最初の16ビットは1~6の数を表している。
・こちらも同様に暗号化メッセージとキーを提示する。
・こちらの提示したものが表す数と上記の数の合計が7になるように提示する必要がある。
上記の条件を満たすようにメッセージを固定し、キーを変えて、条件をみたすようにブルートフォースで答えていく。スクリプトは以下の通り。

#!/usr/bin/env python
import socket
import re
import struct
import string
import itertools
from Crypto.Cipher import AES

def recvuntil(s, tails):
    data = ""
    while True:
        for tail in tails:
            if tail in data:
                return data
        data += s.recv(1)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('challenges.hackover.h4q.it', 1415))

data = recvuntil(s, '\n')
data += recvuntil(s, '\n')
data += recvuntil(s, '\n')
data += recvuntil(s, '\n')
data += recvuntil(s, '\n')
data += recvuntil(s, '\n')
data += recvuntil(s, '\n')
data += recvuntil(s, '\n')
data += recvuntil(s, '\n')
print data

for i in range(32):
    print 'Round %d' % (i + 1)
    data = recvuntil(s, '\n')
    print data
    pattern = 'My dice roll: (.+)\n'
    m = re.search(pattern, data)
    my_dice_roll_enc_b64 = m.group(1)

    data = recvuntil(s, ':')
    data += recvuntil(s, ' ')
    your_dice_roll_enc = 'AAAAAAAAAAAAAAAA'
    your_dice_roll_enc_b64 = your_dice_roll_enc.encode('base64')
    data += your_dice_roll_enc_b64
    print data
    s.sendall(your_dice_roll_enc_b64)

    data = recvuntil(s, '\n')
    print data
    pattern = 'My key: (.+)\n'
    m = re.search(pattern, data)
    my_key_b64 = m.group(1)

    data = recvuntil(s, ':')
    data += recvuntil(s, ' ')
    my_key = my_key_b64.decode('base64')
    aes1 = AES.new(my_key)
    my_dice_roll_enc = my_dice_roll_enc_b64.decode('base64')
    my_dice_roll = int(aes1.decrypt(my_dice_roll_enc).encode('hex')[0:4])
    expected = 7 - my_dice_roll

    for c in itertools.combinations_with_replacement(string.printable, 4):
        your_key_tail = ''.join(c)
        your_key = 'AAAAAAAAAAAA' + your_key_tail
        aes2 = AES.new(your_key)
        h = aes2.decrypt(your_dice_roll_enc).encode('hex')
        if h[0:4] == '000' + str(expected):
            break

    your_key_b64 = your_key.encode('base64')
    data += your_key_b64
    print data
    s.sendall(your_key_b64)

data = recvuntil(s, '\n')
print data

実行すると、32ラウンドの後、フラグが表示された。

             :
Round 32
My dice roll: asCvL0SUQrfvrQQ0VK18pA==

Your dice roll: QUFBQUFBQUFBQUFBQUFBQQ==

My key: gNflaEQwFBcSGPJgeerGrw==

Your key: QUFBQUFBQUFBQUFBMGJrLg==

You win! How was that possible? However, here is your flag: hackover16{HowAboutAuthenticatedEncrYption?}
hackover16{HowAboutAuthenticatedEncrYption?}