PlaidCTF 2018 Writeup

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

macsh (Crypto 125)

'<|>'区切りで1個目がmac, 2個目がcmdline

$ nc macsh.chal.pwning.xxx 64791
|$|> aaa<|>ls
macsh: bad tag
|$|> aaa<|>oo
macsh: oo: command not found
|$|> aaa<|>tag echo 123
feb086773d17f6438c7630d7da1dba79
|$|> bbb<|>tag echo 123
feb086773d17f6438c7630d7da1dba79
|$|> aaa<|>tag echo 456
d610717ba31f48a0cbde88926e95bd82
|$|>

k0, k1はランダムな16バイト文字列でmtagを先頭につけたときはmacを表示してくれる。
k0の鍵を割り出そうと考えたが、それは難しい。よく見ると129ブロック目は1ブロック目から鍵を再度使うようになっている。このことを使い、例えば以下のように考える。

ブロック データ1 データ2
1ブロック目 echo 0123456789; echo 0123456789;
2ブロック目 echo 0123456789; echo 0123456789;
128ブロック目 echo 0123456789; echo 0123456789;
129ブロック目 echo ls .
130ブロック目 コマンド長情報 コマンド長情報
131ブロック目 padding(\x10*16) padding(\x10*16)

こう考えると、データ1とデータ2の129ブロック以外の各ブロックの暗号化のXORは0となるため、echoコマンドとlsコマンドのmacのXORの値がわかる。さらに1ブロック目がechoコマンドの場合とXORを取れば1ブロック目がlsコマンドの場合のmacを取得できる。
lsコマンドでflag.txtがあることがわかるので、cat flag.txtでフラグが得られる。最終的なコードは以下の通り。

import socket

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

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('macsh.chal.pwning.xxx', 64791))

data = recvuntil(s, '|$|> ')
print data

cmd_head = 'a<|>tag '

#### ls exec ####
cmd1 = 'echo 0123456789;' * 128 + 'echo'
cmd = cmd_head + cmd1
print cmd
s.sendall(cmd + '\n')
data = recvuntil(s, '|$|> ')
print data
mac1 = data.split('\n')[0]

cmd2 = 'echo 0123456789;' * 128 + 'ls .'
cmd = cmd_head + cmd2
print cmd
s.sendall(cmd + '\n')
data = recvuntil(s, '|$|> ')
print data
mac2 = data.split('\n')[0]

cmd3 = 'echo'
cmd = cmd_head + cmd3
print cmd
s.sendall(cmd + '\n')
data = recvuntil(s, '|$|> ')
print data
mac3 = data.split('\n')[0]

mac_ls = '%032x' % (int(mac1, 16) ^ int(mac2, 16) ^ int(mac3, 16))
cmd_ls = mac_ls + '<|>ls .'
print cmd_ls
s.sendall(cmd_ls + '\n')
data = recvuntil(s, '|$|> ')
print data

#### cat exec ####
cmd1 = 'echo 0123456789;' * 128 + 'echo 0123456'
cmd = cmd_head + cmd1
print cmd
s.sendall(cmd + '\n')
data = recvuntil(s, '|$|> ')
print data
mac1 = data.split('\n')[0]

cmd2 = 'echo 0123456789;' * 128 + 'cat flag.txt'
cmd = cmd_head + cmd2
print cmd
s.sendall(cmd + '\n')
data = recvuntil(s, '|$|> ')
print data
mac2 = data.split('\n')[0]

cmd3 = 'echo 0123456'
cmd = cmd_head + cmd3
print cmd
s.sendall(cmd + '\n')
data = recvuntil(s, '|$|> ')
print data
mac3 = data.split('\n')[0]

mac_cat = '%032x' % (int(mac1, 16) ^ int(mac2, 16) ^ int(mac3, 16))
cmd_cat = mac_cat + '<|>cat flag.txt'
print cmd_cat
s.sendall(cmd_cat + '\n')
data = recvuntil(s, '|$|> ')
print data

実行結果は以下の通り。

   :
|$|>
9daabce6ee4c110034527e8a432abd26<|>ls .
__pycache__
flag.txt
fmac.py
macsh.py
.bashrc
.bash_logout
.profile
   :
|$|>
e04241a0f78ab714e517439cd7f8dccb<|>cat flag.txt
PCTF{fmac_is_busted_use_PMAC_instead}
|$|>
PCTF{fmac_is_busted_use_PMAC_instead}