ångstromCTF 2023 Writeup

投稿日: 更新日:

コンテストサイト:https://2023.angstromctf.com/

結果

解けた問題数は MISC:4問、WEB:5問、CRYPTO:3問、REV:1問の計13問で382位でした

meow [misc]

だた、nc challs.actf.co 31337とコマンドを入力すれば良い。

sanity check [misc]

Discodeに登録してgeneralの所に行くとヘッダー部分に書いてある。

Admiral Shark [misc]

Wiresharkで与えられたパケットを見てみる。分析->追跡と進むとストリーム2で何らかのバイナリファイルが流れている。バイナリをよく見てみるとl/worksheets/sheet1.xmlという文字列がある。これを調べるとExcelについての記事がヒットしたのでExcelファイルだと予想した。拡張子.xlsxで保存してみたが開けなかった。更に調べると7zipで開けるので開いてみた。するとxl/sharedStrings.xmlのファイルにフラグを発見した。

better me [misc]

何か適当に話すと会話してくれる。ChatGPTかな?プロンプトインジェクションだと思うので行う。

いろいろ試して何回かやり直した。以下が結果。

catch me if you can [web]

ぐるぐる回ってる。開発者ツールを開けば良い。

Celeste Speedrunning Association

言われるがままhttps://mount-tunnel.web.actf.co/play にアクセスする。どうやら、そこを開いてからPress when done!を押すまでの短さを競うらしい。前ページの1位が0秒なのでそれよりも早くする必要がある。開発ツールを見てみると、fromのとこにname="start"と時刻を記録している値がある。これをある程度大きな数字にしてPress when done!を押すとフラグが得れた。

shortcircuit [web]

とりあえず開発者ツールを開いた。すると、headにフラグらしき文字列が入っている。コードを読むと文字列を30文字ごとに切り出し、swapしている。逆の操作を行えば良いので、swapの部分を書き換え、フラグであろう文字れつを流すとフラグを得た。

directory [web]

pageがものすごくある。page0を開くとyour flag is in another fileと言われた。この大量のページのどれかにあるのだろう。

全てにアクセスするために以下のコードを書いた。フラグが出てくるまでかなりの時間を要した。

import requests

for i in range(5000):
    resu = requests.get(f"https://directory.web.actf.co/{i}.html")
    if not resu.ok:
        print(f"error{i}")
    if resu.text != "your flag is in another file":
        print(resu.text)
        break

Celeste Tunneling Association [web]

与えられたコードを見る。するとnamehostvalueflag.localであるリクエストを送れば良いことが分かる。

SECRET_SITE = b"flag.local"

~~~

num_hosts = 0
for name, value in headers:
    if name == b"host":
        num_hosts += 1

if num_hosts == 1:
    for name, value in headers:
        if name == b"host" and value == SECRET_SITE:
            await send({
                'type': 'http.response.body',
                'body': FLAG.encode(),
            })
            return

以下のコードを作成しフラグを得た。

import requests

headers = {"host":"flag.local"}

resu = requests.get("https://pioneer.tailec718.ts.net/", headers=headers)
print(resu.text)

ranch [crypto]

シーザー暗号。CyberChefのEncryption / EncodingにあるRot13のAmountの値を試して行く。

CyberChef:https://gchq.github.io/CyberChef/

impossible [crypto]

与えられたコードを見てみる。len(fake_psi(one_encoding(x, 64), zero_encoding(y, 64))) == 0の部分から、one_encoding(x, 64)zero_encoding(y, 64)が同じ値を持っていてはならない。そして、x > y and x > 0 and y > 0となるx,yが必要であることが分かる。

それで、one_encoding(x, 64)はシフトして1ビット目が1である数を配列に格納している。zero_encoding(x, 64)はシフトして1ビット目が0である数を格納している。

x26412^{64}-1の時、シフトしてもどの1ビット目も1が立つので返す配列は空となる。これで、len(fake_psi(one_encoding(x, 64), zero_encoding(y, 64))) == 0の条件は満たせる。よって任意のyを選ぶことが出来るので、x>yを満たすものを選ぶ。1を選んだ。

Royal Society of Arts [crypto]

RSA暗号の計算知識が必要。

(p2)(q1)(p-2)*(q-1)(p1)(q2)(p-1)*(q-2)から(p1)(q1)(p-1)*(q-1)を導き出せればば復号鍵が作成出来るので式変形で導く。

とりあえず展開する。

(p1)(q2)=pqq2p+2(p2)(q1)=pq2qp+2(p-1)*(q-2) = pq - q - 2p + 2 \\ (p-2)*(q-1) = pq -2q - p + 2

二つを足す

(p1)(q2)+(p2)(q1)=2pq+3q3p+4(p-1)*(q-2) + (p-2)*(q-1) = 2pq + -3q - 3p + 4

ここで、目標は

(p1)(q1)=pqpq+1(p-1)*(q-1) = pq - p - q + 1

であるので、近い。3で割れば一致させれるのでいじる。

pq=Npq = Nであることを用て両辺に足し、更に両辺を-1すると

(p1)(q2)+(p2)(q1)+N1=3pq3q3p+3(p1)(q2)+(p2)(q1)3=pqqp+1=(p1)(q1)(p-1)*(q-2) + (p-2)*(q-1) + N -1 = 3pq - 3q - 3p + 3 \\ \frac{(p-1)*(q-2) + (p-2)*(q-1)}{3} = pq - q - p + 1 = (p-1)*(q-1)

よって(p1)(q1)(p-1)*(q-1)の値を得た。

あとはこれらの計算を実装する。数字は長いので省略

from Crypto.Util.number import long_to_bytes

N = 
e = 
c = 

# (p-2)*(q-1)
a = 

# (p-1)*(q-2)
b = 

phi = (a + b + N -1)//3

d = pow(e, -1, phi)

m = pow(c, d, N)

print(long_to_bytes(m))

checkers [rev]

ファイルが与えられる。とりあえずstringsコマンドを実行してみるとフラグを得た。

書いた人

profile_image

お茶の葉

物理とプログラミングが好きな人