pbctf 2023 Writeup

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

Blocky - 0 (Crypto)

サーバの処理概要は以下の通り。

・key = get_random_block()
 ・key: ランダム243未満のコードで構成される9バイト文字列
・cipher = BlockCipher(key, 20)
 ・sks: keyの各値bについてGF(b)の配列
 ・以下180回繰り返し
  ・sksにsks[-1] + SBOX[sks[-9]]を追加
 ・cipher.subkeys = [sks[i:i+9] for i in range(0, (rnd + 1) * 9, 9)]
 ・cipher.rnd = 20
・以下繰り返し
 ・inp: 入力
 ・inpが'E'の場合
  ・inp: 16進数表記で入力(180バイト未満、各バイトのコードは243未満)
  ・inp: inpをhexデコード
  ・inpが'gimmeflag'の場合、NG
  ・pt = pad(inp)
   ・mac = get_mac(pt)
    ・mac: ptのsha256ダイジェストの先頭9バイト
    ・macの各値を243で割った余りをbyte文字列にして返却
   ・ptの長さが9バイトの倍数になるようパディングし、macを連結して返却
  ・iv: ランダム243未満のコードで構成される9バイト文字列
  ・enc = iv
  ・ptの各ブロックごと(pt[i:i+9])に以下を実行
   ・t = add(pt[i:i+9], iv)
   ・iv = cipher.encrypt(t)
   ・encにivを連結
  ・encを16進数表記で表示
 ・inpが'D'の場合
  ・inp: 16進数表記で入力(216バイト未満、各バイトのコードは243未満)
  ・inp: inpをhexデコード
  ・iv: inpの先頭9バイト
  ・ct: inpの先頭9バイト目以降
  ・dec = b''
  ・ctの各ブロック(ct[i:i+9])に以下を実行
   ・t = cipher.decrypt(ct[i:i+9])
   ・decにsub(t, iv)を連結
   ・iv = ct[i:i+9]
  ・pt = unpad(dec)
  ・ptがb'gimmeflag'の場合、フラグを表示
  ・ptがb'gimmeflag'でない場合、ptを16進数表記で表示

上記のように処理を書き出してみたが、よく見るとコードにミスがある。暗号化する際のチェックで、以下のように書いてある。

if inp == 'gimmeflag':

inpの型はbytesであるため、入力する際にhexデコードしてb'gimmeflag'になるものを指定すれば、b'gimmeflag'の暗号化文字列が入手できる。

>>> b'gimmeflag'.hex()
'67696d6d65666c6167'
$ nc blocky-0.chal.perfect.blue 1337
> E
Input (in hex): 67696d6d65666c6167
Result: 5c3cdbb10802059490cfdc1d9782ec9829cace5b937e72124f32067eee889d79d542de5a
> D
Input (in hex): 5c3cdbb10802059490cfdc1d9782ec9829cace5b937e72124f32067eee889d79d542de5a
pbctf{actually_I_made_the_same_mistake_in_CODEGATE_Finals}
pbctf{actually_I_made_the_same_mistake_in_CODEGATE_Finals}