BSides Indore CTF 2023 Writeup

この大会は2023/6/17 0:30(JST)~2023/6/18 0:30(JST)に開催されました。
今回もチームで参戦。結果は3059点で605チーム中6位でした。
自分で解けた問題をWriteupとして書いておきます。

Sanity Check (Misc)

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

BSidesIndore{mogaMb00_w3lcOmeS_y0u_to_CTF!!!}

Operation Cipher Vault, (Web)

入力文字列が短いと、以下のように表示される。

Error: Length too short

少しずつ長くしていく。

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Error: Length too short

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Error: Length too short

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Congratulations! You found the flag: BSidesIndore{br4v0_y0u_cr4ck3d_17}
BSidesIndore{br4v0_y0u_cr4ck3d_17}

Can you WIN from EVT? (Forensics)

ログイン失敗の数と、最後にログイン成功した日時を答える必要がある。ログイン成功、失敗のイベントログについては、Security.evtxを見ればよい。
ログイン失敗のイベントIDは4625なので、その条件でフィルタリングする。

その数は6であることがわかる。
ログイン成功のイベントIDは4624なので、その条件でフィルタリングし、日付と時刻でソートする。

最終時刻は2022/08/23 19:56:09であることがわかる。UTCの時刻にすると、2022/08/23 10:56:09。

BSidesIndore{6_8/23/2022_10:56:09AM}

Hide and Seek (Forensics)

$ zsteg challenge.png 
extradata:imagedata .. 

    00000000: 01 2f 23 00 ff 0a 0c 00  00 14 17 00 00 24 2e 03  |./#..........$..|
    00000010: 00 ff 01 fe 00 f4 f1 00  00 d6 d3 ff 00 f1 ef 00  |................|
    00000020: 00 03 01 00 00 0f 0f 00  00 1a 19 07 00 14 15 04  |................|
    00000030: 00 f4 fd f9 00 fa fc 01  00 f9 fd 00 00 f2 f0 fc  |................|
    00000040: 00 f9 f6 ff 00 01 fb 05  00 f3 f0 fb 00 f7 f8 00  |................|
    00000050: 00 fc fd 00 00 f1 f2 00  00 00 00 00 00 f5 f5 00  |................|
    00000060: 00 06 06 00 00 2f 36 05  00 12 18 06 00 09 0b fe  |...../6.........|
    00000070: 00 fa f7 f7 00 00 fd 06  00 f5 ef fa 00 ef e8 00  |................|
    00000080: 00 ff fe 00 00 fb fd 00  00 f4 f4 00 00 01 01 00  |................|
    00000090: 00 0d 0d 01 00 20 20 08  00 0d 0c 02 00 02 03 fd  |.....  .........|
    000000a0: 00 f3 f9 fd 00 f9 fb 02  00 eb eb fa 00 ee f0 01  |................|
    000000b0: 00 fd fc ff 00 00 fe ff  00 0f 12 00 00 0b 0c 03  |................|
    000000c0: 00 f9 fa fd 00 1a 16 0c  00 0e 0d 0a 00 fe fc f9  |................|
    000000d0: 00 f1 f4 f1 00 fc fd 00  00 01 02 0a 00 eb ee ff  |................|
    000000e0: 00 f4 f3 fb 00 f6 f5 fc  00 f2 ee 00 00 05 03 00  |................|
    000000f0: 00 11 12 00 00 26 2b 12  00 f3 f8 f4 00 f3 f4 fa  |.....&+.........|
imagedata           .. file: Tower/XP rel 2 object not stripped
b1,g,msb,xy         .. file: OpenPGP Secret Key
b1,rgb,lsb,xy       .. text: "eTB1X2YwdW5kX20zISEhISEhISEhIX0"
b1,bgr,lsb,xy       .. text: "q<\"niS\tg"
b4,b,lsb,xy         .. file: PDP-11 kernel overlay
b4,rgb,lsb,xy       .. text: "\ta'\nA\" 2"

lsbにbase64らしき文字列がある。

$ echo eTB1X2YwdW5kX20zISEhISEhISEhIX0= | base64 -d
y0u_f0und_m3!!!!!!!!!!}

IHDRチャンクにある画像の高さを大きくする。

画像の下にフラグの初めの部分が現れた。

BSidesIndore{H3y

"_"を追加して連結してフラグにする。

BSidesIndore{H3y_y0u_f0und_m3!!!!!!!!!!}

DiffieHellman (Cryptography)

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

・p: 1024ビット素数
・a, b, s: p未満ランダム整数
・na, nb: p未満ランダム整数
・A = compose_f(s, na)
 ・na回以下繰り返し
  ・z = f(z)
   ・z = (a * z + b) % p
 ・zを返却
・B = compose_f(s, nb)
・shared_secret = compose_f(A, nb)
・m: flagの数値化したもの
・hint = (shared_secret * m) % p
・p, a, b, s, A, B, hintを表示

compose_f関数で2回までの計算は以下のようになっている。

s1 = (a * s0 + b) % p
s2 = (a * s1 + b) % p

上記から以下の式が成り立つ。

s2 - s1 = a * (s1 - s0)

さらに汎用化し以下の式になる。

sn+1 - sn = a**n * (s1 - s0)

このことから次が言える。

(a * A + b - A) % p = a**na * (a * s + b - s) % p
(a * B + b - B) % p = a**nb * (a * s + b - s) % p

以上からshared_secretをxと置くと、次の式が成り立つ。

(a * x + b - x) % p = a**(na + nb) * (a * s + b - s) % p
                    = a**na * a**nb * (a * s + b - s) % p
                    = (a * A + b - A) * (a * B + b - B) * inverse(a * s + b - s, p) % p

つまりxは以下の式で算出できる。

x = ((a * A + b - A) * (a * B + b - B) * inverse(a * s + b - s, p) - b) * inverse(a - 1, p) % p
 ||<
あとはhintにxのinverseを掛ければflagになる。
>|python|
#!/usr/bin/env python3
from Crypto.Util.number import *

with open('output.txt', 'r') as f:
    params = f.read().splitlines()

p = int(params[0].split(' ')[-1])
a = int(params[1].split(' ')[-1])
b = int(params[2].split(' ')[-1])
s = int(params[3].split(' ')[-1])
A = int(params[4].split(' ')[-1])
B = int(params[5].split(' ')[-1])
hint = int(params[6].split(' ')[-1])

shared_secret = ((a * A + b - A) * (a * B + b - B) * inverse(a * s + b - s, p) \
    - b) * inverse(a - 1, p) % p

m = hint * inverse(shared_secret, p) % p
flag =long_to_bytes(m).decode()
print(flag)
BSidesIndore{yOu_5hou1D_7ry_S0M3ThIn9_elSe_o7h3r_TH4n_lcg}

FeedBack (Misc)

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

BSidesIndore{Sayonara}