ふるつき

v(*'='*)v かに

InterKosenCTF2020 開催記

 もう高専に何を感じることもなくなったけど、今年もInterKosenCTFを開催しました。一昨年、去年に続いて3回目の開催になります。過去の開催では高専生向けの開催を行っていましたが、今年は初級〜中級程度のCTFプレイヤー向けとして開催しました。これには、そもそも高専生向けというと対象が狭すぎて参加者があまり見込めないとか、なんだかんだと言って此れまでの開催でも非高専生の参加者にも楽しんでもらっていたとか、今年は高専セキュリティコンテストもなさそうな雰囲気であるとか*1、最初にも言ったけど高専に対して何ら感じるところがなくなったとかの理由があります。それでも"InterKosenCTF"という名前で開催したのは、2年と短くはあるものの、一応のブランドとしての"InterKosenCTF"が存在したこと、kosenctf.com というドメインを持っていたのでまあそれなら……ということが理由です。

 さて前置きが長くなりましたが、今回も日記・自分用記録を兼ねてInterKosenCTF回りで考えたこと、感じたこと、目指したこと、行ったことなどを述べていきます。

InterKosenCTF 2020

2020年9月5日 10時00分 〜 2020年9月6日 22時00分 までの36時間、 insecure(ptr-yudaiyoshiking)としてInterKosenCTF 2020を開催しました。1ポイント以上獲得したチームは133チームで、1ポイント以上獲得した個人は188名でした。ご参加頂きありがとうございました。

f:id:Furutsuki:20200906223509p:plainf:id:Furutsuki:20200906223538p:plain
f:id:Furutsuki:20200906223503p:plainf:id:Furutsuki:20200906223505p:plain

作問に関する振り返りと反省

 今年はWelcome / Survey 問題を含めて 25問、除くと23問を作成・出題しました。去年が22問だったので大体同じようなバランスです。今年は特に幅広い難易度、ジャンルで良い問題を作ることを心がけていました。良い問題というのはコンセプトが素直に提示されている問題、一筋縄では解けないような問題や、ちょっとマイナーな知っていると面白いような知識を要求される問題などで、かつ問題が台無しになるような非想定解が存在しないものです。逆にひたすら実装を面倒にした問題やあまりに「やるだけ」の問題等は、作問・レビューの段階でできる限り弾く努力をしてきました。その甲斐あって、いろんな層の人が問題を解く楽しみを感じることができ、また何か少しでも実力に繋がるような問題セットを提供できたと思っています。

問題の管理・チェック

 作問の管理には今年もHackmdを使っていたのですが*2、今年はなんとなくのジャンル感と難易度感を表形式で管理してみました。これはなかなか良かったと思っていて、どんな問題が足りていないかということがある程度把握でき、また作問はしたもののレビューを受けていない問題がひとめでわかります。

f:id:Furutsuki:20200906192213p:plain
問題の管理を行っていた表。難易度感は自己申告なのでちょっと低めに出ていた

問題のレビューは「その問題が解けること」「適切な難易度であること」「出題の基準に沿っていること」を確認しつつ「非想定解があれば指摘する」「権限まわりなどのミスを指摘する」ことを目的としています。担当外のジャンルのレビューをすることになるのでヒント等をもらうことはあっても用意された解法は見ずに、できるだけフラットな視点で問題に取り組むように注意していました。実際に権限の不備や非想定解の発見、問題のrejectがそれぞれあり、レビューの重要性が明らかでした。まあそれでも非想定解は残っていたんですが……(後述)。てかめっちゃ残ってましたね。チェックは何重にも行ったほうが良いです(教訓)

難易度表記の非採用

 今回は内部ではある程度の難易度の推定を行ってはいましたが、スコアサーバでは難易度に関する表記は行わないことにしました。これはそもそも難易度の推定が難しいから動的配点を導入しているのに、難易度の表示自体はされるのはちょっとずれているのではないかという考えと、難易度表記に惑わされず、フラットな姿勢で問題に挑戦してほしいという考えによるものです。ただ、初心者のプレイヤーがそれで一問も解けない、あるいはいきなり難しい問題に挑んでしまって心折れる、ということがないようwarmup, lunaticのタグの表記は行いました*3。これが結果として良かったのかどうかはきちんとはわかりませんが、悪くはなかったような気がしています。ただやはり、公開が遅い問題はsolve数が伸びない傾向にあるようで、それほど難しくない問題がなかなか解かれずに残っているということがありました。それでも全ての問題が公開されてからCTFが終了するまでに24時間はあったので、ある程度均されてはいきました。

非想定解: miniblog

 また非想定解を作ってしまいました。しかも前回のInterKosenCTFでの非想定解と同じです。また、正規表現でフィルタしている部分を改行文字を挿入することで突破できる非想定解を作りました。どの程度この非想定解が使われていたのかはちょっとわからないし調査をするつもりもあんまりないですが、問題の一段階をすっ飛ばすことができ、想定解法との難易度が大きく変わってしまいました。本当に反省しています。どうして学習しないのか……

非想定解: bitcrypto

pythonで文字列長を見てバイトで扱うときは非ascii文字をかんがえましょう。ごめんなさい

非想定解: padrsa

boss問題のつもりで出したのに非想定解を入れました。ごめんなさい

反省: miniblog

 もう一つminiblogについてです。typoがあり、サーバのスレッド化が行われておらず、問題のレスポンスがとても悪くなり解けない状態が出来てしまいました。幸い、ガチャガチャやって治して、そんなにダウンタイムがあったわけではなかったのですが、反省にはかわりありません。

CTFプラットフォームに関する振り返りと反省

雑に言うと私はLMTとかではないので限界があるし、実力不足を痛感しました。あれやこれや、やりたいことはあったんですが結局最低限の環境になりました。

スコアサーバ

 また作りました。懲りないので。もう作りたくないと毎度思いながら、次回また作っている。毎回作ってしまうことには反省しかありません。今回のスコアサーバはzer0ptsCTF 2020で作ったサーバをベースに作ったので作業量がそう多くはなかったとはいえ、やはり大変でした。zer0ptsCTFではファイルディスクリプタのクローズ漏れからサーバが数時間程度で落ちてしまう問題がありましたが、今年はwebsocketではなく定期的なポーリング + redisによるデータのキャッシュを行うことにしてリアルタイム性、レスポンス速度を保ちながら負荷軽減とバグの解消を試みました。結果として情報はほとんど最新のものが得られ、安定して稼働する良いサーバになったのではないかと思っています。問題の表示方法や見た目についてはアンケートにご意見をいくつかいただきましたので、次回のCTFでは改善していきたいと思っています。

DigitalOcean

 これまでのCTFではAWSを使っていましたが、今年は3kCTFの賞品でDigitalOceanで使えるcreditを$100程度いただきましたので、これと、初回登録時にもらえる$100を使って、DigitalOcean環境でサーバやデータベースをホストしていました。AWSにはあったあれこれがDigitalOceanにはない、DigitalOceanのコンソール時々挙動がおかしいことがある等の苦しみはありましたが、概ね問題なく使うことが出来ました。はやめに対処して置かなければならないのが作成できるDroplet数の制限で、初期では3台までしか作成できない上、上限引き上げに際してはフォームに申請を行わなければならず、面倒です。

 ちなみにDigitalOceanでなくて困ったものはFargate相当のもの(Kubernetes Clusterは作成できますがそうではなく、あくまでFargateを求めていました)、Cloudwatch Logs相当のもの(各インスタンスのネットワーク、CPU使用率などを一覧できないのは厳しいものがありました)、Spaces + CDNにおいて、デフォルトで用いられるファイルの指定ができないこと(URLの末尾にindex.htmlがつくのがとても格好悪かったです)、日本リージョンがないことです。

デプロイ方法

 これまでのdocker-composeの資産を活かしつつ、リクエストを分散できる、ということでdocker swarmのclusterを構築してそこにdocker stack deployをしていくような仕組みを構築していたのですが、overlay networkをうまく作れなかった、パケットを上手にキャプチャできなかった等の理由から開催の前日か前々日くらいに没にして、結局これまでどおりいくつかサーバを建てて、そこに問題リポジトリをクローンしてきて手動でdocker-compose up -dをする方法を取りました。なんだかんだでこれが一番安定している気がします。

solvability check

f:id:Furutsuki:20200906203621p:plainf:id:Furutsuki:20200906203738p:plain

 SECCON Beginnersで導入されていた、問題が解けるかどうかの自動チェックが良かったので真似をしようという話になりましたが、きちんと実装するのは大変だったので、サーバでdocker-compose run solve を回しては5分休むようなスクリプトを書いてお茶を濁しました。問題が解けない状態になっていると、discordに通知が飛びます。解ける状態になっていることが確認できたときは、admin専用のチャンネルに通知するようにしました。感想としてはSECCON Beginnersで行われていたように、何度か失敗したときに通知するようにしないと、確率で失敗するエクスプロイト(特にpwn)では、問題は正常に稼働しているのにアラートが飛んできてしまうな、ということと、チェックに失敗した後、復旧したことも通知する必要があるな、ということでした。これらは当然の話で、事前のテストの不足が伺えます。ただ、やはり自動でsolverを回してくれるというだけでもかなり便利で、時折不安になって自分でソルバを回すという手間がなくなったのは良いと思いました。solvability checkの仕組みは今後もきちんと整えて運用できるようにしていきたいところです。

競技前〜競技中の行動に関する振り返りと反省

スコアサーバ公開とか宣伝とか

ptr-yudaiの要請もあり、少し早めに、開催1週間ほど前からスコアサーバを公開していました。が、結局登録があるのは前日夜とか当日とかで、それまでは登録チーム数はあまり伸びず、このままでは参加者が少なく、盛り上がりにかけたCTF担ってしまうのではという恐怖がありました。そのせいもあってTwitterで少しうるさくなってしまったのは大変申し訳無く感じています。

このCTFはカジュアルなCTFということもありctftime.org には登録していなかったので、それも参加者が増えなかった要因であるとは思うのですが、twitter以外の宣伝の手段をとれなかったのも問題だなと思っています。とはいえtwitter以外でどのような手段で、どのような層に宣伝すればよかったのかは全然わからないのですが……。

競技中

私、ptr-yudai、yoshikingの3人だけで運営を回していたこともあり、とても忙しく、とくに序盤は神経を使いました。スケジュールに合わせて問題を公開し、アナウンスをし、サーバが落ちていないか確認をしたりトラフィックを見たりして過ごしました。Discordのctf-logというチャンネルではだれがどの問題を解いた、という情報が流れるのですが、Fisrt, Second, Third bloodについては、それぞれ金・銀・銅メダルの絵文字をつけたりしていました。特に事前打ち合わせをしていたわけではないのですがなんとなく運営みんなこれをやっていて、参加者からも盛り上がってよかったと概ね好評だったようです。

f:id:Furutsuki:20200906205313p:plain

その他には、Twitterで関連するツイートをサーチしてRTしたりもしました。これは割りとカジュアルなCTFだからこそ、という感じですね。Twitterは趣味みたいなものです。

問題に関する質問はほとんどありませんでした。これは日本人の気質という所もあると思いますが、楽でした。

総括等

 CTFの運営は楽しいですが、つかれます。やはり3人でCTFを回すのは正気の沙汰ではないような気がしますね……。CTF自体はとても楽しいので続けると思いますし、ptr-yudaiがいる限りは安心してもらって良いですが、この体制で続けるかは今の私にはわかりません。InterKosenCTFという名前は少なくとも消えて別の名前になると思います。それでは、またどこかのCTFでお会いできると嬉しいです

*1:去年の開催記を見直していたら、去年もあるかどうかわからないけど……と言っていた

*2:というかCTFに関するドキュメントはだいたい全部Hackmdで管理しているのですが

*3:難しい問題を表すのにlunaticを使っているのは以前からで、理由はなんとなく格好良いからです