Hack.lu CTF 2019 Writeup

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

COBOL OTP (crypto)

COBOLのコードを読み解くと、以下のようになる。

ws-flag: 英数字1バイト
ws-key: 英数字50バイト
ws-parse-data: 符号付き9桁数字
ws-xor-len: 数字1桁、初期値1
ws-ctr: 数字1桁

・key.txt読み込み→ws_key
・ws_ctrに1をセット
・以下50回繰り返し
 ・getcharコール
 ・1文字ずつ入力文字をws-parseにセット
 ・ws_parseをws-flagにセット
 ・ws_keyのws_ctr番目の文字とXOR→結果を表示
 ・ws_ctrを1プラス

簡単に言うと、keyとフラグをXORして暗号化しているのだが、よく見るとws-ctrは1桁のためkeyの先頭10バイトだけが繰り返し、XORに使われている。XORの鍵は10バイトになっていることと同様になる。そこで先頭がflag{になることから少しずつフラグを割り出す。

with open('out', 'rb') as f:
    enc = f.readlines()[1].rstrip()

pt_parts = []

head_flag = 'flag{'
tail_flag = '}'

key1 = []
for i in range(len(head_flag)):
    code = ord(enc[i]) ^ ord(head_flag[i])
    key1.append(code)

pt_part1 = []
for j in range(50//10):
    pt = ''
    for i in range(len(key1)):
        code = ord(enc[i+j*10]) ^ key1[i]
        pt += chr(code)
    pt_part1.append(pt)

print pt_part1
pt_parts.append(pt_part1)

## predict from here ##
pt2_flag = '_'
key2 = ord(enc[35]) ^ ord(pt2_flag)

pt_part2 = []
for j in range(50//10):
    pt = chr(ord(enc[5+j*10]) ^ key2)
    pt_part2.append(pt)

print pt_part2
pt_parts.append(pt_part2)

pt3_flag = 't'
key3 = ord(enc[36]) ^ ord(pt3_flag)

pt_part3 = []
for j in range(50//10):
    pt = chr(ord(enc[6+j*10]) ^ key3)
    pt_part3.append(pt)

print pt_part3
pt_parts.append(pt_part3)

pt4_flag = 'h'
key4 = ord(enc[37]) ^ ord(pt4_flag)

pt_part4 = []
for j in range(50//10):
    pt = chr(ord(enc[7+j*10]) ^ key4)
    pt_part4.append(pt)

print pt_part4
pt_parts.append(pt_part4)

pt5_flag = '3'
key5 = ord(enc[38]) ^ ord(pt5_flag)

pt_part5 = []
for j in range(50//10):
    pt = chr(ord(enc[8+j*10]) ^ key5)
    pt_part5.append(pt)

print pt_part5
pt_parts.append(pt_part5)

pt6_flag = '_'
key6 = ord(enc[39]) ^ ord(pt6_flag)

pt_part6 = []
for j in range(50//10 - 1):
    pt = chr(ord(enc[9+j*10]) ^ key6)
    pt_part6.append(pt)
pt_part6.append('')

print pt_part6
pt_parts.append(pt_part6)

flag = ''
for i in range(50//10):
    for j in range(6):
        flag += pt_parts[j][i]

print flag

実行結果は以下の通り。

['flag{', '_c4n_', 'O2_c3', '_s4v3', 'fUtUr']
['N', 'b', 'r', '_', 'E']
['0', 'u', 't', 't', '1']
['w', 'y', 's', 'h', '!']
['_', '_', '_', '3', '}']
['u', 'C', '&', '_', '']
flag{N0w_u_c4n_buy_CO2_c3rts_&_s4v3_th3_fUtUrE1!}
flag{N0w_u_c4n_buy_CO2_c3rts_&_s4v3_th3_fUtUrE1!}