WhiteHat Grand Prix 06 – Quals Writeup

この大会は2020/1/4 11:00(JST)~2020/1/5 11:00(JST)に開催されました。
今回もチームで参戦。結果は500点で150チーム中50位でした。
自分で解けた問題をWriteupとして書いておきます。

Blockchain (Misc)

3つのjsonファイルと2つの公開鍵、パスワード付きzipファイルが添付されている。2者間で公開鍵で暗号化してメッセージを送っていて、それがjsonに書かれている。試してみたところ、2つの公開鍵のnは1でない素数を共通に持っているので、素因数分解できる。それを元にメッセージを復号する。

from Crypto.PublicKey import RSA
from Crypto.Util.number import *
import json

id_list = ['34a7370734caff5d129ad355f78f3ccf', '8a95963d7bedd2b81ad09cd1838c7a4d']

ns = []
es = []
for i in range(2):
    filename = 'Blockchain/%s.pem' % id_list[i]
    with open(filename, 'r') as f:
        pub_data = f.read()
    pubkey = RSA.importKey(pub_data)
    ns.append(pubkey.n)
    es.append(pubkey.e)

p = GCD(ns[0], ns[1])

ds = []
for i in range(2):
    q = ns[i] / p
    phi = (p - 1) * (q - 1)
    d = inverse(es[i], phi)
    ds.append(d)

for i in range(1, 4):
    filename = 'Blockchain/block%d.json' % i
    with open(filename) as f:
        block = json.load(f)

    for j in range(2):
        c = int(block['data_block'][j][id_list[j]]['messger'])
        m = pow(c, ds[j], ns[j])
        msg = long_to_bytes(m)
        print msg

メッセージの復号結果は以下の通り。

Do you understand the blockchain?
Password using open flag.zip
flag in flag.txt
Password = Password1+Password2
Password1:'irVOwoJR7d'
Password2:'D@V!4P##Ij'

flag.zipをパスワード'irVOwoJR7dD@V!4P##Ij'で解凍する。flag.txtにはbase64文字列が書かれているので、デコードしてファイルに保存する。

with open('Blockchain/flag/flag.txt', 'r') as f:
    data = f.read()

with open('flag.png', 'wb') as f:
    f.write(data.decode('base64'))

f:id:satou-y:20200116220611p:plain
QRコードの画像ファイルだったので、読み取る。

Whitehat{the_ flag_blockchain_ iot}
$ echo -n "the_ flag_blockchain_ iot" | sha1sum
af398a30871f3f533986bf4e58cc8899e00c1139  -
WhiteHat{af398a30871f3f533986bf4e58cc8899e00c1139}

Crypto 01 (Crypto)

$ nc 15.164.159.194 8006
Your cipher key: 32322f34342f67672f4444 36362f2d2d2f1b1b2f7474 34342f3e3e2f12122f6464 30302f23232f6b6b2f4646 34342f40402f1a1a2f6f6f 30302f3d3d2f6b6b2f5151 58582f74742f43432f7c7c2f3535 30302f20202f6d6d2f5757 78782f31312f4f4f 35352f37372f61612f4f4f 6b6b2f33332f4b4b 39392f36362f79792f4f4f 35352f3e3e2f17172f7474 70702f33332fb6b6 36362fc0c02f75752f5555 33332f2c2c2febeb2f7575 ffff2f67672f41412f7e7e2f3838 31312f7c7c2fe2e22f7676 a8a82f6c6c2f54542f28282f3636 adad2f62622f59592f2c2c2f3535 37372fd0d02f7a7a2f4f4f 37372f3f3f2fe7e72f7676 37372f3d3d2fe2e22f7272 eaea2f77772f48482f3c3c2f3939 31312f3f3f2ff3f32f7676 32322fc8c82f62622f4343 34342f2b2b2fe4e42f7676 a2a22f6d6d2f47472f60602f3737 a1a12f62622f4b4b2f3d3d2f3838 30302f3f3f2ff5f52f6c6c 35352fc9c92f6d6d2f5252 34342f3c3c2ff9f92f6e6e 37372f24242ff2f22f6d6d 33332f29292fe4e42f6363 71712f38382fa5a5 bdbd2f64642f50502f2e2e2f3232 6c6c2f39392faeae f8f82f79792f47472f5f5f2f3939 34342fcbcb2f63632f5757 38382fc0c02f65652f5151 bebe2f6e6e2f59592f60602f3939 b0b02f6e6e2f42422f7e7e2f3939 38382fcfcf2f6f6f2f5353 38382fd1d12f72722f4b4b 32322f2e2e2fe9e92f7979 fefe2f6c6c2f41412f2a2a2f3030 38382f3d3d2fc3c32f7575 9d9d2f73732f56562f24242f3939 39392fe8e82f70702f5959 33332ffefe2f61612f4c4c 38382f3c3c2fdddd2f7979 63632f33332f9090 35352f3c3c2fd7d72f6464 72722f32322f9898 36362ff0f02f64642f4141 30302fe3e32f75752f4141 39392ffefe2f6b6b2f4a4a 33332fffff2f77772f4c4c 31312febeb2f6f6f2f4747 62622f33332f9d9d 32322ffdfd2f63632f4c4c 37372fe6e62f67672f4242 39392f3f3f2fd4d42f7474 65652f37372f8181
WELCOME TO CHAOS TOOL: 
Description: This is a tool which helps you hide the content of the message
Notes:
- Message cannot contain whitespace characters
- Message can use all characters including punctuation marks and number
- Decrypt the above key to get the flag, len(key) = 64
- All punctuation marks use in plain key: ~`!@#$%^&*()_-+=<,>.?|
- Key is not a meaningful sentence
- Find the rule in this tool
**FEATURES**
<1> Encrypt message 
<2> Get the flag 
Your choice: 1
Enter your message: 1234
66662f32322f4242 75752f32322f4646 71712f32322f4646 61612f32322f4242
**FEATURES**
<1> Encrypt message 
<2> Get the flag 
Your choice: 2
Please enter the key to get flag: abcd
WRONG KEY

メッセージには英数字+記号(~`!@#$%^&*()_-+=<,>.?|)が使われる。

$ nc 15.164.159.194 8006
Your cipher key: a0a02f66662f59592f25252f3030 33332f28282ff3f32f7171 38382fe5e52f6f6f2f4242 63632f30302f9797 dcdc2f73732f4e4e2f2d2d2f3333 9c9c2f6f6f2f58582f5f5f2f3838 35352ff1f12f63632f5757 32322f40402fd2d22f6c6c 36362fecec2f69692f4f4f 31312f3e3e2fcccc2f7676 33332fecec2f7a7a2f5757 35352f7e7e2fcaca2f6666 36362f3e3e2fc4c42f6f6f 6b6b2f36362f9c9c 31312feeee2f72722f4242 76762f36362f9898 d2d22f7a7a2f43432f40402f3434 30302feeee2f75752f4f4f 35352feaea2f62622f4848 36362f3d3d2fcbcb2f7474 34342f2c2c2fcaca2f6f6f 32322f3d3d2fc4c42f6f6f 9e9e2f72722f59592f2a2a2f3535 39392ffdfd2f6e6e2f4a4a 38382ff9f92f76762f5252 e8e82f67672f59592f5f5f2f3030 31312ff2f22f6d6d2f5959 74742f32322f8080 35352f28282fd9d92f6565 e4e42f6f6f2f42422f5e5e2f3131 32322ffafa2f63632f4e4e 98982f66662f48482f3f3f2f3636 38382ff7f72f73732f4444 95952f61612f4d4d2f2c2c2f3131 32322f28282fa5a52f7a7a ffff2f75752f51512f2b2b2f3636 31312f96962f70702f5151 33332f2d2d2fbaba2f6c6c 32322f3c3c2fa9a92f6f6f e6e62f64642f55552f2c2c2f3535 34342f92922f70702f5252 34342f3e3e2fafaf2f7979 31312f9f9f2f72722f4343 31312f88882f77772f5454 f7f72f61612f53532f23232f3737 34342f7c7c2fbaba2f7575 30302f25252fb6b62f6464 35352f80802f6c6c2f4f4f 35352f9b9b2f79792f4646 e5e52f6b6b2f52522f7e7e2f3636 32322f21212fb5b52f7272 36362f23232fa7a72f7373 ffff2f69692f54542f2c2c2f3434 32322f86862f73732f5757 6a6a2f30302fe4e4 abab2f6d6d2f5a5a2f3c3c2f3535 30302f29292fb7b72f7575 39392f85852f61612f4c4c 32322f97972f67672f4848 62622f35352feded 76762f33332feded f3f32f64642f4d4d2f2b2b2f3232 36362f95952f6d6d2f4a4a e1e12f6c6c2f42422f2c2c2f3232
WELCOME TO CHAOS TOOL: 
Description: This is a tool which helps you hide the content of the message
Notes:
- Message cannot contain whitespace characters
- Message can use all characters including punctuation marks and number
- Decrypt the above key to get the flag, len(key) = 64
- All punctuation marks use in plain key: ~`!@#$%^&*()_-+=<,>.?|
- Key is not a meaningful sentence
- Find the rule in this tool
**FEATURES**
<1> Encrypt message 
<2> Get the flag 
Your choice: 1
Enter your message: 1
69692f37372fafaf
**FEATURES**
<1> Encrypt message 
<2> Get the flag 
Your choice: 1
Enter your message: 1
65652f32322fafaf
**FEATURES**
<1> Encrypt message 
<2> Get the flag 
Your choice: 1
Enter your message: 1
73732f34342fafaf
**FEATURES**
<1> Encrypt message 
<2> Get the flag 
Your choice: 1
Enter your message: 1
68682f31312fafaf
**FEATURES**
<1> Encrypt message 
<2> Get the flag 
Your choice: 1
Enter your message: 12
6d6d2f38382fafaf 70702f30302fadad

同じ文字でも暗号は異なる。hexデコードしてみる。

■平文: 1
>>> '69692f37372fafaf'.decode('hex')
'ii/77/\xaf\xaf'
>>> '65652f32322fafaf'.decode('hex')
'ee/22/\xaf\xaf'

どこかでこういう暗号を見たことがある。ISITDTU CTF 2019 Quals の Chaos 1000と類似の問題だが、特徴が少々複雑。特徴を見出すために何回か試してみる。

■aからzまで順に試す。
00/&&/ll/rr 30302f26262f6c6c2f7272
33/((/oo/bb 33332f28282f6f6f2f6262
11/((/nn/aa 31312f28282f6e6e2f6161
22/>>/ii/vv 32322f3e3e2f69692f7676
99/>>/hh/vv 39392f3e3e2f68682f7676
22/**/kk/kk 32322f2a2a2f6b6b2f6b6b
55/``/jj/ww 35352f60602f6a6a2f7777
77/==/ee/pp 37372f3d3d2f65652f7070
88/&&/dd/vv 38382f26262f64642f7676
99/&&/gg/yy 39392f26262f67672f7979
00/((/ff/xx 30302f28282f66662f7878
11/--/aa/rr 31312f2d2d2f61612f7272
00/--/``/ii 30302f2d2d2f60602f6969
99/%%/cc/mm 39392f25252f63632f6d6d
77/%%/bb/kk 37372f25252f62622f6b6b
33/--/}}/tt 33332f2d2d2f7d7d2f7474
00/,,/||/hh 30302f2c2c2f7c7c2f6868
44/!!//kk 34342f21212f7f7f2f6b6b
88/$$/~~/kk 38382f24242f7e7e2f6b6b
22/^^/yy/zz 32322f5e5e2f79792f7a7a
44/<</xx/ii 34342f3c3c2f78782f6969
11/^^/{{/cc 31312f5e5e2f7b7b2f6363
66/||/zz/tt 36362f7c7c2f7a7a2f7474
33/$$/uu/oo 33332f24242f75752f6f6f
66/##/tt/oo 36362f23232f74742f6f6f
44/../ww/jj 34342f2e2e2f77772f6a6a

この暗号の特徴は以下のようになっていることがわかった。

"/"区切りで3つの場合は数字で、平文は"/"区切りの3番目の文字が決まり、XORの値が固定になっている。
"/"区切りで4つの場合で、4つ目が英小文字の場合は英小文字で、平文は"/"区切りの3番目の文字が決まり、XORの値が固定になっている。
"/"区切りで4つの場合で、4つ目が英大文字の場合は英大文字で、平文は"/"区切りの2番目の文字が決まり、XORの値が固定になっている。
"/"区切りで5つの場合は記号で、平文は"/"区切りの1番目の文字が決まり、XORの値が固定になっている。

各バイトのXORの値を求めれば、復号できる。

import socket
import string

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

def get_elems(k):
    elems = []
    for i in range(0, len(k), 3):
        elems.append(k[i:i+2])
    return elems

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('15.164.159.194', 8006))

data = recvuntil(s, 'choice: ')
key = data.split('\n')[0].split(': ')[1].split(' ')
print data + '1'
s.sendall('1\n')

chars = 'a' * 64
data = recvuntil(s, ': ')
print data + chars
s.sendall(chars + '\n')

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

try_key = data.split(' ')
xor_key = []
for tk in try_key:
    c = ord(get_elems(tk.decode('hex'))[2][0])
    xor_key.append(c ^ ord('a'))

print '[+] XOR Key:', xor_key

pt = ''
for i in range(len(key)):
    elems = get_elems(key[i].decode('hex'))
    if len(elems) == 3:
        code = ord(elems[2][0]) ^ xor_key[i]
    elif len(elems) == 4:
        if elems[3][0] in string.lowercase:
            code = ord(elems[2][0]) ^ xor_key[i]
        else:
            code = ord(elems[1][0]) ^ xor_key[i]
    else:
        code = ord(elems[0][0]) ^ xor_key[i]
    pt += chr(code)

data = recvuntil(s, 'choice: ')
print data + '2'
s.sendall('2\n')

data = recvuntil(s, ': ')
print data + pt
s.sendall(pt+ '\n')

data = s.recv(8192)
print data

実行結果は以下の通り。

Your cipher key: 39392f5e5e2f88882f7373 c2c22f65652f44442f2c2c2f3636 84842f72722f51512f2a2a2f3030 30302fb4b42f79792f5050 37372f25252f8a8a2f7878 30302faeae2f63632f5252 6a6a2f31312fdcdc 31312f2d2d2f8f8f2f6b6b 67672f33332fd9d9 32322f29292f8e8e2f6d6d 32322fa9a92f75752f5959 c3c32f65652f4f4f2f2d2d2f3939 92922f78782f5a5a2f3f3f2f3333 68682f31312fdede d3d32f6d6d2f4f4f2f24242f3939 cece2f73732f50502f24242f3232 69692f36362fc7c7 30302f2d2d2f99992f7373 34342f28282f93932f7474 35352f7e7e2f9c9c2f6969 72722f35352fc7c7 34342f2e2e2f96962f7878 33332f5e5e2f8c8c2f6b6b 30302f23232f95952f6a6a 63632f38382fcdcd 35352fb0b02f74742f4b4b dada2f6d6d2f44442f29292f3535 d8d82f7a7a2f57572f29292f3333 37372fb3b32f79792f5050 40402f69692f48482f60602f3131 20202f6e6e2f4d4d2f3c3c2f3838 34342f2c2c2f7a7a2f6262 79792f31312f3333 30302f5c5c2f66662f5353 39392f21212f77772f6f6f 34342f7c7c2f6d6d2f6969 7a7a2f37372f3636 21212f70702f43432f5e5e2f3232 33332f3f3f2f6e6e2f6868 35352f66662f58582f21212f3636 6b6b2f65652f48482f7e7e2f3737 2d2d2f67672f58582f7e7e2f3737 36362f25252f7d7d2f7777 33332f44442f68682f4d4d 79792f31312f3f3f 3a3a2f6d6d2f57572f3f3f2f3030 33332f50502f75752f5151 32322f29292f71712f7979 30302f29292f77772f6565 35352f66662f48482f7c7c2f3535 39392f56562f66662f4242 37372f79792f4b4b2f26262f3535 34342f24242f6f6f2f6161 37372f41412f70702f4545 38382f6f6f2f57572f7c7c2f3939 33332f7c7c2f60602f7676 30302f5e5e2f73732f4e4e 33332f53532f61612f4747 38382f4c4c2f65652f4f4f 38382f44442f61612f5a5a 33332f4f4f2f6f6f2f4343 0b0b2f66662f48482f3e3e2f3232 35352f7c7c2f45452f6969 7a7a2f37372f1b1b
WELCOME TO CHAOS TOOL:
Description: This is a tool which helps you hide the content of the message
Notes:
- Message cannot contain whitespace characters
- Message can use all characters including punctuation marks and number
- Decrypt the above key to get the flag, len(key) = 64
- All punctuation marks use in plain key: ~`!@#$%^&*()_-+=<,>.?|
- Key is not a meaningful sentence
- Find the rule in this tool
**FEATURES**
<1> Encrypt message
<2> Get the flag
Your choice: 1
Enter your message: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
36362f2c2c2f83832f6262 37372f5f5f2f82822f6464 39392f24242f85852f7575 34342f2c2c2f84842f7979 34342f2c2c2f87872f6868 34342f2a2a2f86862f6d6d 30302f5e5e2f89892f6262 34342f2d2d2f88882f6666 32322f2d2d2f8b8b2f6767 30302f60602f8a8a2f7575 33332f23232f8d8d2f7a7a 38382f3e3e2f8c8c2f6b6b 30302f2d2d2f8f8f2f7777 31312f40402f8e8e2f6d6d 35352f3d3d2f91912f7a7a 37372f7c7c2f90902f7777 39392f7c7c2f93932f6f6f 39392f40402f92922f7272 39392f40402f95952f6868 37372f28282f94942f7070 37372f7e7e2f97972f7676 39392f2b2b2f96962f7a7a 32322f3c3c2f99992f6969 31312f7e7e2f98982f7171 33332f2b2b2f9b9b2f7a7a 36362f5e5e2f9a9a2f6f6f 34342f25252f9d9d2f6464 38382f3e3e2f9c9c2f7979 33332f26262f9f9f2f6e6e 34342f7e7e2f61612f6262 38382f3d3d2f60602f6d6d 36362f2d2d2f63632f7979 33332f21212f62622f6b6b 39392f26262f65652f6464 37372f23232f64642f7070 33332f2d2d2f67672f7777 38382f3c3c2f66662f6c6c 32322f21212f69692f6767 30302f3c3c2f68682f7272 32322f23232f6b6b2f6565 36362f3f3f2f6a6a2f7474 34342f2c2c2f6d6d2f6a6a 31312f2a2a2f6c6c2f6e6e 34342f3c3c2f6f6f2f6b6b 32322f2d2d2f6e6e2f6464 33332f24242f71712f7a7a 33332f21212f70702f6d6d 35352f2a2a2f73732f6a6a 38382f29292f72722f6a6a 38382f25252f75752f6464 37372f3d3d2f74742f6f6f 32322f60602f77772f7272 32322f5e5e2f76762f6363 39392f2b2b2f79792f6969 38382f2a2a2f78782f6e6e 36362f21212f7b7b2f7070 36362f5e5e2f7a7a2f6e6e 31312f5f5f2f7d7d2f6868 32322f7e7e2f7c7c2f7a7a 38382f2c2c2f7f7f2f7777 32322f3c3c2f7e7e2f6a6a 32322f29292f41412f6a6a 33332f2a2a2f40402f7878 37372f2a2a2f43432f7272
[+] XOR Key: [226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34]
**FEATURES**
<1> Encrypt message
<2> Get the flag
Your choice: 2
Please enter the key to get flag: j!`QlI4f3eE.|1#?5jgi1atl7K&%M@!x0Xrk1)g?`!pJ0*Acd!C!xY!zEOQZP+d9
Good job! Here is your flag: Hav3_y0u_had_4_h3adach3_4ga1n??_Forgive_me!^^
>>> import hashlib
>>> hashlib.sha1('Hav3_y0u_had_4_h3adach3_4ga1n??_Forgive_me!^^').hexdigest()
'960caf240a19b8531b4f50807ec0a67c765b8f18'
WhiteHat{960caf240a19b8531b4f50807ec0a67c765b8f18}

Misc 03 (Misc)

PNGの後ろによくわからないデータが付いている。ヘッダ部分を1バイトの鍵でXORのブルートフォースをしてみると、PNGのヘッダになるものがあった。その鍵で復号して画像にする。

def decrypt(s, key):
    dec = ''
    for i in range(len(s)):
        dec += chr(ord(s[i]) ^ key)
    return dec

with open('pied_piper_2', 'rb') as f:
    enc = f.read()

PNG_HEAD = '\x89PNG'

for key in range(256):
    dec = decrypt(enc[:4], key)
    if dec == PNG_HEAD:
        print key
        break

dec = ''
for e in enc:
    code = ord(e) ^ key
    dec += chr(code)

with open('flag.png', 'wb') as f:
    f.write(dec)

f:id:satou-y:20200116221433p:plain
Pigpen cipherの暗号画像になったので、復号する。

ITSNOTMAGI
CITSTALENT
ANDSWEATHE
RESYOURFLA
GPETERGREG
ORY

フラグは"PETERGREGORY"。

$ echo -n PETERGREGORY | sha1sum
135d4281008b8ccddef42be4a7762e68b8a8f579  -
WhiteHat{135d4281008b8ccddef42be4a7762e68b8a8f579}