DeadSec CTF 2023 Writeup

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

Welcome (Welcome)

Discordに入り、#announcementチャネルのメッセージを見ると、フラグが書いてあった。

Dead{W3c0me_t0_D3edSec_CTF}

Compress (Misc)

16バイトごとに1ブロックで、4バイトのsha256ダイジェストの先頭3バイトを結合後、16バイト全体のsha256ダイジェストの先頭3バイトを結合している。
元のデータがprintableな文字で書かれていることがわかっているので、ブルートフォースで条件に合うものを16バイトごとに割り出す。

#!/usr/bin/env python3
from hashlib import sha256 as H
from itertools import product
from string import *

chars = printable.encode()

dic = {}
for x in product(chars, repeat=4):
    text = bytes(list(x))
    h = H(text).digest()[:3]
    if h in dic:
        dic[h] += [text]
    else:
        dic[h] = [text]

with open('data.z1p', 'rb') as f:
    z1p_data = f.read()

z1p_blks = [z1p_data[i:i+15] for i in range(0, len(z1p_data), 15)]

code = b''
for blk in z1p_blks:
    codes = []
    for i in range(4):
        b = blk[i*3:i*3+3]
        codes += [dic[b]]

    found = False
    for c0 in codes[0]:
        for c1 in codes[1]:
            for c2 in codes[2]:
                for c3 in codes[3]:
                    text = c0 + c1 + c2 + c3
                    h = H(text).digest()[:3]
                    if h == blk[12:]:
                        found = True
                        code += text
                        break
                if found:
                    break
            if found:
                break
        if found:
            break
    if found == False:
        print('Error')

with open('data', 'wb') as f:
    f.write(code)

元のdataファイルを見てみる。

$ cat data
Congratulations, it seems like you have managed to write a decompressor for this file format!

Here is the "official" writeup:

from itertools import product
from hashlib import sha256 as H
from string import printable
from collections import defaultdict
from tqdm import tqdm

lookup = defaultdict(set)

for chunk in tqdm(product(printable[:-2], repeat=4), total=len(printable[:-2])**4):
    tmp = ''.join(chunk).encode()
    h = H(tmp).digest()[:3]
    lookup[h].add(tmp)


with open("data.z1p", "rb") as fd:
    while True:
        h1,h2,h3,h4,hh = (fd.read(3) for _ in range(5))
        if h1 == b'': break
        for g1,g2,g3,g4 in product(lookup[h1], lookup[h2], lookup[h3], lookup[h4]):
            if H(g1+g2+g3+g4).digest()[:3] == hh:
                print((g1+g2+g3+g4).decode(), end="")


The flag is the sha256 hash of this entire file, as lower case, and wrapped in the flag format.

元のdataファイルのsha256ハッシュをフラグの形式にすればよい。

$ sha256sum data
7eeee4060c39b7e5936cd652edc040126849bb3b03714df6fda711875c11e994  data
Dead{7eeee4060c39b7e5936cd652edc040126849bb3b03714df6fda711875c11e994}

Survey

アンケートに答えたら、フラグが表示された。

Dead{thanks}