darkCON CTF Writeup

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

Sanity Check (Misc)

問題にフラグが書いてあった。

darkCON{free_Fl4g_4_every0ne_G00d_Luck}

Take It Easy (Crypto)

添付のzipファイルにはgetkey.txtとパスワード付きzipが入っている。getkey.txtにはこう書いてある。

p = 147310848610710067833452759772211595299756697892124273309283511558003008852730467644332450478086759935097628336530735607168904129699752266056721879451840506481443745340509935333411835837548485362030793140972434873394072578851922470507387225635362369992377666988296887264210876834248525673247346510754984183551
ct = 43472086389850415096247084780348896011812363316852707174406536413629129
e = 3

RSA暗号として、復号してみる。

from Crypto.Util.number import *

p = 147310848610710067833452759772211595299756697892124273309283511558003008852730467644332450478086759935097628336530735607168904129699752266056721879451840506481443745340509935333411835837548485362030793140972434873394072578851922470507387225635362369992377666988296887264210876834248525673247346510754984183551
ct = 43472086389850415096247084780348896011812363316852707174406536413629129
e = 3

phi = p - 1
d = inverse(e, phi)
m = pow(ct, d, p)
pw = long_to_bytes(m)
print pw

RSA暗号を復号した結果は以下の通り。

Ju5t_@_K3Y

これでパスワード付きzipを解凍すると、chall.pyとcipher.txtが展開された。この暗号処理の概要は以下の通り。

・chunks: フラグを4バイトブロックに分割
・2ブロック先とのXORを出している。

"darkCON{"から始まることを前提に復号する。

#!/usr/bin/env python3
from struct import pack, unpack

def Tup_Int(chunk):
    return unpack('I', chunk)[0]

ct = [b'\nQ&4', b"\x17'\x0e\x0f", b'1X5\r', b'072E', b'\x18\x00\x15/']

flag = b'darkCON{'
for i in range(5):
    block = pack("I", Tup_Int(flag[i*4:i*4+4]) ^ Tup_Int(ct[i]))
    flag += block

print(flag)
darkCON{n0T_Th@t_haRd_r1Ght}

Tony And James (Crypto)

暗号化処理は以下の通り。

・l: フラグの長さ
・raw, seed = get_seed(l)
 ・rand: lビットランダム整数
 ・以下、randが0より大きい場合に繰り返し実行
  ・rand: 1ビット右にシフト
  ・seed: randをプラス
  ・rawのリストにrandを追加
 ・rawとseedを返却
・random.seed(seed)
・以下フラグの各文字に対して実行
 ・r: 1~2**512のランダム整数
 ・i=0の場合のみ、rを表示
 ・encoded = hex(r ^ m[i] ^ raw[i])[2:]
   ⇒表示

r0はわかている。フラグが"darkCON{"で始まることからm[0]はわかる。r0、m[0]とF0からraw[0]を算出でき、rand(末尾1ビットは動作に関係ない)はraw[0]から左シフトすればよい。そこまで絞れば、seedを算出でき、各フラグに対するrを計算でき、フラグを求めることができる。

#!/usr/bin/env python3
import random

def get_seed(r):
    seed = 0
    rand = r
    raw = list()

    while rand > 0:
        rand = rand >> 1
        seed += rand
        raw.append(rand)

    return raw, seed

r0 = 1251602129774106047963344349716052246200810608622833524786816688818258541877890956410282953590226589114551287285264273581561051261152783001366229253687592

pre_flag = b'darkCON{'

with open('encrypted.txt', 'r') as f:
    encs = [line.rstrip().split(' ')[-1] for line in f.readlines()]

raw0 = r0 ^ pre_flag[0] ^ int(encs[0], 16)
rand = raw0 << 1

raw, seed = get_seed(rand)
random.seed(seed)

flag = ''
for i in range(len(encs)):
    r = random.randint(1, 2**512)
    m = r ^ raw[i] ^ int(encs[i], 16)
    flag += chr(m)

print(flag)
darkCON{user_W4rm4ch1ne68_pass_W4RM4CH1N3R0X_t0ny_h4cked_4g41n!}

Rookie's_Choice_4_you (Crypto)

RC4で同じKEYでの平文、暗号文のペアが複数あり、フラグより長い暗号文があるので、XORで復号できる。

from Crypto.Util.strxor import strxor

pt = 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz'
ct = '3d5d841c4df203758189060d7ba5ef0460c90faeae890dc621dfb563a03cc5f728d42794ae8a08102f2766acece427f3c6514fc7'.decode('hex')
enc_flag = '385e95136bdb2a66baa0593e27b8df03228f1785ea9925c768d08b74b06bffe27bd17da1aed51c21342026bdacb173f8'.decode('hex')

key = strxor(pt, ct)
flag = strxor(enc_flag, key[:len(enc_flag)])
print flag
darkCON{RC4_1s_w34k_1f_y0u_us3_s4m3_k3y_tw1c3!!}