zer0pts CTF 2022 Writeup

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

welcome (welcome)

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

zer0pts{3nj0y_th3_CTF_t0_W1N!!!!}

GitFile Explorer (web, warmup)

serviceはgithub, gitlab, bitbucketから選択できる。ソースコードを見ると、githubが単純なパス結合になっていて、該当するファイルを表示する。

URL: <Service>/<GitHub ID>/<Repository Name>/<Branch>/<File Path>
・<Service>: servceパラメータ
・<GitHub ID>: ownerパラメータ
・<Repository Name>: repoパラメータ
・<Branch>: branchパラメータ
・<File Path>: fileパラメータ

serviceには、"github"という文字列が含んでいることが必要。また、URLは^http.+\/\/.*(github|gitlab|bitbucket)にマッチしていることが必要。ディレクトリトラバーサルでこの条件を満たすようパラメータを指定する。
http://gitfile.ctf.zer0pts.com:8001/?service=https%2F%2Fgithub&owner=..%2F..&repo=..%2F..&branch=..&file=flag.txtにアクセスしたら、フラグが表示された。

zer0pts{foo/bar/../../../../../directory/traversal}

Anti-Fermat (crypto, warmup)

RSA暗号で、pは1024ビット素数、qはpのビット反転した数の次の素数。反転は以下の式で表せる。

p ^ ((1<<1024)-1) = 2**1024 - p - 1
   ↓
q > 2**1024 - p - 1

qを1ずつ増やし(i=0, 1, ...)、以下の方程式を解き、整数解が得られるものを探す。

p * (2**1024 - p - 1 + i) = n
#!/usr/bin/env python3
from Crypto.Util.number import *
from sympy import *

n = 0x1ffc7dc6b9667b0dcd00d6ae92fb34ed0f3d84285364c73fbf6a572c9081931be0b0610464152de7e0468ca7452c738611656f1f9217a944e64ca2b3a89d889ffc06e6503cfec3ccb491e9b6176ec468687bf4763c6591f89e750bf1e4f9d6855752c19de4289d1a7cea33b077bdcda3c84f6f3762dc9d96d2853f94cc688b3c9d8e67386a147524a2b23b1092f0be1aa286f2aa13aafba62604435acbaa79f4e53dea93ae8a22655287f4d2fa95269877991c57da6fdeeb3d46270cd69b6bfa537bfd14c926cf39b94d0f06228313d21ec6be2311f526e6515069dbb1b06fe3cf1f62c0962da2bc98fa4808c201e4efe7a252f9f823e710d6ad2fb974949751
c = 0x60160bfed79384048d0d46b807322e65c037fa90fac9fd08b512a3931b6dca2a745443a9b90de2fa47aaf8a250287e34563e6b1a6761dc0ccb99cb9d67ae1c9f49699651eafb71a74b097fc0def77cf287010f1e7bd614dccfb411cdccbb84c60830e515c05481769bd95e656d839337d430db66abcd3a869c6348616b78d06eb903f8abd121c851696bd4cb2a1a40a07eea17c4e33c6a1beafb79d881d595472ab6ce3c61d6d62c4ef6fa8903149435c844a3fab9286d212da72b2548f087e37105f4657d5a946afd12b1822ceb99c3b407bb40e21163c1466d116d67c16a2a3a79e5cc9d1f6a1054d6be6731e3cd19abbd9e9b23309f87bfe51a822410a62
e = 65537

i = 0
found = False
while True:
    p = symbols('p')
    q = 2**1024 - p - 1 + i
    eq = Eq(p * q - n, 0)
    sol = solve(eq, p)
    for p in sol:
        if p.is_Integer:
            found = True
            break
    if found:
        break
    i += 1

p = int(p)
q = n // p
assert p * q == n

phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(c, d, n)
flag = long_to_bytes(m).decode()
print(flag)

復号結果は以下の通り。

Good job! Here is the flag:
+-----------------------------------------------------------+
| zer0pts{F3rm4t,y0ur_m3th0d_n0_l0ng3r_w0rks.y0u_4r3_f1r3d} |
+-----------------------------------------------------------+
zer0pts{F3rm4t,y0ur_m3th0d_n0_l0ng3r_w0rks.y0u_4r3_f1r3d}

survey (survey)

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

zer0pts{4r1g4t0_f0r_pl4y1ng_zer0pts_CTF!}