この大会は2017/4/15 11:00(JST)~2017/4/17 11:00(JST)に開催されました。
今回もチームで参戦。結果は1444点で303チーム中35位でした。
自分で解けた問題をWriteupとして書いておきます。
Hulk (Crypto)
CBCモードのブロック暗号の問題。処理の概要は以下の通り。
request1: 入力 ・96バイト以下 ・16進数文字 plaintext1 = 入力16進数を文字に変換+フラグ ciphertext1 = plaintext1の暗号 plaintext1_str = 入力16進数+'|flag' ciphertext1_str = plaintext1の暗号の16進数表記 request2: 入力 ・96バイト以下 ・16進数文字 plaintext2 = 入力16進数を文字に変換 ciphertext2 = plaintext2の暗号(iv: ciphertext1の末尾16バイト) plaintext2_str = 入力16進数 ciphertext2_str = plaintext2の暗号の16進数表記
CBCモードなので、以下のようになる。
[平文1ブロック目] ^ IV --(暗号化)--> [暗号文1ブロック目] [平文2ブロック目] ^ [暗号文1ブロック目] --(暗号化)--> [暗号文2ブロック目] [平文3ブロック目] ^ [暗号文2ブロック目] --(暗号化)--> [暗号文3ブロック目]
3ブロック目に1バイトずつフラグの先頭が入るように暗号化する。
平文3ブロック目の最終バイトを総当たりで暗号化し、暗号文2ブロック目とIVとのXORを2回目の暗号化に使う。
この結果2回目の暗号文1ブロック目が1回目の暗号文3ブロック目と同じになるものをブルートフォースで探す。
#!/usr/bin/env python import socket import re pattern = 'ciphertext: (.+)' flag = '' l_flag = len(flag) while True: for code in range(36, 127): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('202.112.51.217', 9999)) print 'try %s' % chr(code) print flag plain1 = '58' * (47 - l_flag) data = s.recv(1024) data += plain1 s.sendall(plain1 + '\n') data = s.recv(1024) m = re.search(pattern, data) cipher1_str = m.group(1) iv = cipher1_str[2:].strip().decode('hex')[-16:] data = s.recv(1024) if l_flag < 16: try_str = ('58' * (15 - l_flag)).decode('hex') + flag + chr(code) else: try_str = flag[l_flag-15:l_flag] + chr(code) cipher1_2 = cipher1_str[2:].strip().decode('hex')[16:32] plain2 = '' for i in range(16): plain2 += chr(ord(try_str[i]) ^ ord(iv[i]) ^ ord(cipher1_2[i])) plain2 = plain2.encode('hex') data += plain2 s.sendall(plain2 + '\n') data = s.recv(1024) m = re.search(pattern, data) cipher2_str = m.group(1) if cipher1_str[66:98] == cipher2_str[2:34]: flag += chr(code) l_flag += 1 break if flag[-1:] == '}': break print flag
bctf{3c1fffb76f147d420f984ac651505905}