Hack.lu CTF 2017 Writeup

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

b64 (Crypto 100)

暗号化処理の概要は以下の通り。

secret:ランダムな8バイトデータ。
secretと入力文字列のXORを取り、その結果に64をプラスし、256で割った余りをASCIIコードとして文字にする。
その結果からBase64で使われる文字以外を削除する。
文字列長を4で割って、1余る場合はその1文字を削除する。
余りが2または3の場合は、=でパディングし、4の倍数の文字列長にする。
Base64デコードしたものが提示される。

Base64文字以外がないものを探すことができれば、XORでsecretを算出することができる。それをコードにしたものは以下の通り。

import socket

PAD = 64

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

def decrypt(s1, s2):
    dec = ''
    for i in range(len(s1)):
        code = ord(s1[i]) ^ ((ord(s2[i]) - PAD) % 256)
        dec += chr(code)
    return dec

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('flatearth.fluxfingers.net', 1718))

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

in_str = ''
for i in range(4):
    found = False
    for code1 in range(0, 256, 16):
        for code2 in range(0, 256, 16):
            data = recvuntil(s, '>')
            data += recvuntil(s, ' ')
            print data + '1'
            s.sendall('1')
            data = recvuntil(s, '>')
            data += recvuntil(s, ' ')

            try_str = in_str + chr(code1) + chr(code2)
            print data + try_str
            s.sendall(try_str)
            data = recvuntil(s, '\n')
            print data
            dec = data[30:-1]
            if len(dec) > 0:
                b64 = dec.encode('base64').strip()
                b64_no_pad = b64.replace('=', '')
                if len(b64_no_pad) == ((i+1) * 2):
                    in_str += chr(code1) + chr(code2)
                    found = True
                    break
        if found:
            break

data = recvuntil(s, '>')
data += recvuntil(s, ' ')
print data + '2'
s.sendall('2')
data = recvuntil(s, '>')
data += recvuntil(s, ' ')

secret = decrypt(in_str, b64).encode('hex')
print data + secret
s.sendall(secret)
data = recvuntil(s, '\n')
print data
data = recvuntil(s, '\n')
print data
flag{7h3_b35t_w4y_of_h1ding_s3cr3t5_the_w0r1d_h4s_ev3r_seen_period!}