SECCON CTF 2018 国内決勝 writeup
SECCON CTF 2018 国内決勝 writeup
yharima
チームで参加. 1141 pts で 7位でした.
はじめての国内決勝だったので緊張しまくりでしたが,結構頑張れたと思いたい.
松島
ポーカーをする問題で,フルハウス以上を出すと 100pts, フォーカード以上を出すと 300?400?pts もらえる.
フォーカード以上出すと,デフェンスキーワードも入れれるようになる.
開幕問題が空いてなくてやっていなかったが,空いてからはわりかしすぐに着手しはじめた.
問題のバイナリ見てたら,メンバーがもうフルハウス出た,とかいっていて笑っていた.
解析していくと結局は rand 叩いていて seed は time に依存しているっぽいことがわかった.
time を hook して未来予測していけばいいのか,と思ったがめんどくさそう.
よくよく考えるとローカルの時間変えて実行すればいいのでは,と思い調べてみると date コマンドでできるっぽいことがわかった.
一度適当にプレイしてみて,その時間のカードとローカルでプレイした時間に差し替えたものとを比較してみると完全に一致した.
$ sudo date -s "12/23 03:38:42 2018" && ./generate_random_hands Sun Dec 23 03:38:42 UTC 2018 {"game_id":(null),"deck":[19,28,18,37,22,24,42,23,44,5],"max_score":3195}
というわけで,この方法でいけると思い以下のスクリプトを書いて判定していった(shell + node という謎の組み合わせ).
$ cat a.js const arg = process.argv[2]; const s = arg.indexOf('['); const e = arg.indexOf(']'); x = eval(arg.substring(s, e+1)) ans = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; x.forEach((e) => { ans[Math.floor(e/4)] = ans[Math.floor(e/4)] + 1; }); ans.forEach((e, i) => { if (e == 4) { console.log("OK:" + i); } });
$ cat poker.sh #/bin/sh for m in {20..59}; do for s in {0..59}; do t="12/23 04:${m}:${s} 2018" echo $t sudo date -s "${t}" >/dev/null && ./generate_random_hands | xargs node a.js done done
ただ,なぜかフォーカードが出てもフルハウスのときのフラグしかでなくて,うーんうーん言っていたら,メンバーに聞いてこいと言われたのでおとなしく運営に聞きに行った.
説明が悪かったのかうまく伝わらなかったけどフォーカード出してる画面をみせると,納得してもらえて調べてもらうことになった.
結果,カードを変えてフォーカードより強くなるケースがあるとフォーカードでも駄目,ということでアナウンス + ルール追記されること.
(max_score
の値によってどうこうみたいな話だったが,解析する時間よりフォーカード片っ端から入れたほうが早そうと思ってそうした.)
マジかーという気持ちになりながらスクリプト叩きまくって最終的に以下の時間の結果でフラグを得ることができた.
$ sudo date -s "12/23 04:38:0 2018" >/dev/null && ./generate_random_hands {"game_id":(null),"deck":[2,47,46,16,51,45,0,44,39,48],"max_score":23}
天橋立
任意の html ページを上げ, GET の parameter によって alert('XSS')
が発火すれば良い,みたいな問題(説明へたですみません).
どうも40分で問題コンセプトを破壊してしまったようで,罪悪感があり申し訳ない気持ちになりました.なんかすみません.
最初,全然意味がわからなくてチームメンバーに詳しく教えてもらってなんとか理解した.
jjencode 的なことすればいいかと思ったけど,バイト数制限もあって厳しいなーと思った次のタイミングで,
SHA256 前の値を parameter にとって,それがハードコードしてある SHA-256 と一致すれば alert('XSS')
が発火 するようにすればいいのでは?と思い至る.
適当に SHA-256 の実装をもってきて送りつけると全然解かれない(当たり前).
ただ,問題をよく理解してなくて title にデフェンスキーワード入れないとだめだったのに test
とかしていてディフェンスポイントをかなり無駄にしていたっぽい.
気がつけばハッシュ値が変えただけのまったく同じ実装がアップロードされはじめて,これはもったいないことをしてしまったと頭を抱えていました.
以下,うちのチームの答え.
おまけ
最後のほうにやることがなくなっていくつか問題をみていると Team Enu
の問題が SHA-256 じゃなくて解けそうだったのと,
その時点でうちのチームより1つ上だったので,頑張って剥がしてみようと思い解析をはじめた.
わりと適当な感じで解析を進めると k
で parameter を分割して前の部分はそのまま,後ろの部分は base64 で encode されたものを decode してから利用する.
あとはなんか色々な前処理をしたあと xor してペイロードを組み立てて eval して発火させる,という仕組み.
かなり辛い感じで色々ミスったんですが,頑張って解析して最終的に以下のペイロードをぶちこむことで撃墜できた(?
はいらなかった).
aaaaaaaaaaaakcdD9bDbxohN9PooO
本来の問題のコンセプトはこういうことで,非常に面白かっただけに SHA-256 ゲーにしてしまった自分がちょっとアレだなという気持ちに….
なお Team Enu の解いた5分後くらいには SHA-256 の問題になってて「はい」ってなりました(笑).
(頑張ったので,この思い Team Enu の人に届くといいな.)
撃墜したらその問題でゲットしてたデフェンスポイントがもらえる仕組みとかだったら嬉しかったのかもしれない.
とはいえ SHA-256 問題がアレなのでそこをどうにかしないと厳しいのですが….
宮島
出された問題を満たす関数を指定バイト数以内のアセンブラで書く問題.いわゆるアセンブラゴルフ.
いくつか手を出していたが, dodododo が強すぎてまじで無理ゲーだ…となっていました.
基本的にメンバーが解いてくれていたので自分はあんまり手を出していません.
アセンブラ短歌の本買って出直します.
懇親会(追記)
お風呂に入る気持ちが強くて書き忘れていた.
社会性がないので他チームと交流できず,メンバーと話していたら insecure チームの方々が話かけてきてくれて色々話せた.ありがとうございます.
色々問題について話せたりできた良かったです!またどこかでお会いできたらよろしくおねがいします.
まとめ
初の国内決勝にでれてうれしかったです. yharima
チームとしても,個人としても一つの区切りを迎えれたのかなと思う.
まだまだ精進しないと駄目ですね….特にバイナリ.
色々と思うところもありますが,自分は SECCON 国内決勝に出ることを1つの目標として頑張ってきたので,来年以降も開催されることを願っております.
なくなってしまうと,そういうモチベーションを失ってしまう人が自分以外にもいるかもしれませんので.
運営のみなさま,ありがとうございました & お疲れ様でした.そしてなんかごめんなさい.