WaniCTF 2021 開催記
概要
大阪大学CTFチームWani Hackaseは初心者向けCTF大会WaniCTF 2021を11/5(金) 20:00 ~ 11/7(日) 20:00の日程で開催しました。
330名の方に問題を解いていただき、4名の方が全完を達成されました。
経緯
4月のWaniCTF’21-springに引き続き3回目の大会開催です。前回大会を半年スパンで開催したのでその流れで開催することになりました。そして前回、前々回と同じく初心者向けの難易度で計32問を提供しました。
(例の日本トップチームほどではないですが、高頻度に大会を開催するチームとなってしまいました。ちゃんと大会でもいい成績を出せるようにならなければ…)
作問
約半数の問題をチームで毎週行っている勉強会から、残りを大会準備期間で作成しました。
WaniCTFのコンセプトは「初心者の方がたくさん問題を解いて勉強になる」なので作問者自身が解いて面白い・勉強になると思う問題を作り、
- 解法の方向性に気付けるような動線があるか
- 問題を解くのに必要な情報がすべて公開されている(いわゆるエスパーがない)
- (問題の内容が関わらない限り)フラグの箇所が明確
- 問題を解くのに不要な要素を減らす
- 解くのに必要な技術力は高すぎたり低すぎたりしないか
という点を確認しつつ、
- 難易度が大幅に下がってしまうような非想定解
- 問題サーバーを潰されるような脆弱性(想定外のRCEやファイル変更など)
がないかチェックを行っています。
今回の問題は前回大会であったようなミスもなく、無事に問題を提供できました。(前回大会のミスを受け、同様の失敗を防止するCIベースのシステムを導入しました。こちらはインフラの章で詳しく紹介します)
インフラ
前回の構成を踏襲しつつ、複数の改善・新機能追加を行いました。担当してくれたチームメンバーの名前とともに紹介します。(紹介がないところはhi120kiが担当しました)
(参考)インフラの構成
- スコアサーバー (WaniCTFd)
- 監視サーバー (Prometheus, Loki, Grafana, oauth2-proxy)
- 問題サーバー
- nc&pwn問題サーバー
- web問題サーバー1
- web問題サーバー2
- NewRelic
- Infrastructure : スコアサーバーの内部監視
- Synthetics : スコアサーバー&監視サーバーの外部監視
- 問題サーバー外部監視クローラー (AWS Lambda)
- ホームページ (GitHub pages)
- Discord (外部向け)
- Slack (内部向け)
スコアサーバー・監視サーバー・問題サーバーはAWS EC2上でDocker Composeを使ってデプロイしています。
各問題サーバーにはpromtail, node-exporter, cadvisorがインストールされており、問題サービスのログとメトリクス(CPUやメモリ、ネットワークの使用率など)を取得し、監視サーバーへ保存しています。
問題サーバー外部監視クローラーは問題ごとに接続ができるか・解くことができるか確認を行うPythonスクリプトをAWS Lambdaで定期実行し結果を運営に通知する他、スコアサーバーの問題文の下にバッジで表示します。
それぞれの内部監視では様々なメトリクスに対してしきい値が設定されておりそれを超えるとSlackで通知が来るようになっています。(Alertmaneger, NewRelic Alert)
また外部監視クローラーの失敗時にも同様にSlackで通知が来るようになっています。
WaniCTFd
Wani Hackaseで独自開発しているスコアサーバーです。
Golang&Vue.js SPAのWebアプリで適切なキャッシュを導入しておりアクセスが集中しやすい大会開催時・大会終了時でも安定してリクエストをさばくことができます。
また独自開発のメリットを活かし、様々なオリジナル機能を追加し続けています。
テストモード追加 - WaniCTFd
作問期間中はテスト用のスコアサーバーを立てて、そこに問題を登録しメンバーで解きフィードバックを行います。
スコアサーバーは1回フラグを提出し正解すると提出場所が閉じるようになっています。しかし作問期間中は同じ問題に関して修正が加わるたびに何度も解き直してフィードバックを行う必要があるので既存の仕様のままだと不便でした。
また、前回の大会でVery Hard想定のForensics問題「MixedUSB」が作問作業がいくつか欠けておりstringsだけで解ける状態で出題されたというミスがありました。これは作問者が問題ファイルを変更したことに他のメンバーが気付かず、チェックが行われなかったのが原因です。
そこでこのミスを繰り返さないために新たにスコアサーバーへテストモードを導入し、作問期間に登録されている問題の添付ファイルが変更されるたびにその問題の正解者がリセットされるようにしました。
これにより最新の状態の問題がきちんと解かれている状態なのかひと目で確認できるようになり、更新された問題に潜む間違いに気付かずそのまま出題してしまうことを抑制できるようになりました。
(右上に表示される作問締め切り…)
WaniCTFdCLI
問題を管理しているGitHubリポジトリから自動でスコアサーバーに問題を同期するCIに組み込み可能なツールです。 WaniCTFdCLI紹介 - WaniCTF’21-spring開催記
WaniCTFではGitHubですべての問題を管理し、Pull Requestのマージ時にGitHub ActionsでWaniCTFdCLIを自動実行してスコアサーバーに問題を同期しています。
配布ファイル内フラグチェック - WaniCTFdCLI
先ほど紹介した「MixedUSB」問題のミスは適切なチェックが行われなかったことに加えて、配布ファイルにそのままフラグが書かれている状態であるか確認する作業が抜けていたことも原因の1つでした。
問題チェック時にはstringsコマンドでそのままフラグが書かれていないかチェックすることを心がけていますが忘れることもあるので、この作業をWaniCTFdCLIに組み込むことで自動化しすべての配布ファイルに対して必ずチェックを行うようにしました。
(該当コードです。Pull Requestが作成されたときにファイルに対してstringsコマンドを実行しフラグが含まれていないか判定します。)
ps, err := exec.Command("strings", path).CombinedOutput()
if err != nil {
return err
}
if strings.Contains(string(ps), flag) {
return errors.New("FLAG detected in " + path)
}
事故が抑止された瞬間。
ctf.ymlのパラメーター削減 - WaniCTFdCLI
担当 : Laikaさん
今回の問題管理リポジトリではコンフリクトを未然に防ぐために問題ごとにブランチを切って作業するようにしました。
しかし、以前のWaniCTFdCLIでは問題の登録に/ctf.yml
というファイルに問題のパラメーターを登録する作業が必要でした。
https://github.com/wani-hackase/wanictf21spring-writeup/blob/main/ctf.yml#L20
しかしこの/ctf.yml
という単一のファイルに様々なブランチから変更が加わるのは望ましくないので、各問題のREADME.md
ファイルのヘッダーにそれぞれパラメーターを記述するように変更しました。
この変更で作問者からは各問題ディレクトリの中だけで作業が完結するようになり便利になったという感想がありました。
https://github.com/wani-hackase/wanictf2021-writeup/tree/main/web/sourcemap
---
title: sourcemap
level: 1
flag: FLAG{xxxx}
writer: hi120ki
badge: true
---
# sourcemap
## 問題文
...
自動formatチェック
配布ファイルのコードはインデントがずれていたりするとやはりストレスを感じるので、前回まではインフラ担当が大会直前にすべてのコードにまとめてフォーマットを行っていました。
しかしフォーマットをかけるとコメントがずれることがあり、また作問者にフォーマットが当たり前の開発環境で作業してもらうために問題レポジトリにおいてPull Requestを必須とし、そこでCI(GitHub Actions)によって既定のフォーマットがきちんとかけられているか検査するようにしました。
- name: check c files
run: |
find . -name "*.c" -or -name "*.cpp" | xargs clang-format --dry-run --Werror -i
...
- name: check python files
run: |
black --check --verbose .
...
- name: check js files
run: |
find . -name "*.js" -not -name "*.min.js" -or -name "*.php" -or -name "*.yml" -or -name "*.yaml" | xargs prettier -c
AWSリソースのコード化
以前よりLambdaで動作する問題サーバー外部監視クローラーについてはAWS CDKによるリソースのコード化を行っていましたが、スコアサーバー・監視サーバー・問題サーバーについては手作業でコンソールよりインスタンスの作成 -> セキュリティグループの設定 -> ドメインの設定を行っていました。
これらの手作業の手間を省くためにAWS CDKでインスタンスを管理するプログラムを制作しました。
{
prefix: "wanictf2021-web-1",
anyOpenPort: [22, 80, 443],
customOpenPort: [
{
port: xxxx,
allow: "xxxx",
},
{
port: xxxx,
allow: "xxxx",
},
],
instanceClass: ec2.InstanceClass.T2,
instanceSize: ec2.InstanceSize.MEDIUM,
ubuntuVersion: 18,
volumeSize: 30,
publicRecord: [
"service.crypto",
"sourcemap.web",
"nosql.web",
],
sshKey: "xxxx_key",
},
このようにインスタンスの設定を記述してデプロイができるようなCDKプロジェクトを組みました。
手作業に頼ることなく設定値をすぐに把握することができ、サーバー情報のドキュメント作成が不要になり便利になりました。(ついでにGitHub Actionsでデプロイできるようにもしてあります)
レコードを設定するために各インスタンスにEIPを振ってそのEIPに対してAレコードを追加するという処理を行いましたが、複数のインスタンスを作成中にEIPの上限に引っかかってインスタンスが作れないというトラブルに巻き込まれました。事前にEIPの制限緩和リクエストを行うことをおすすめします。 Elastic IP アドレスの制限
問題サーバーの初期設定のAnsible化
担当 : Badlyluckyさん
現在、問題サービスはAWS EC2上でDocker Composeを使ってデプロイしています。
このときEC2の初期セットアップ(apt updateやdockerのインストールなど)にはシェルスクリプトを使ってきましたが、確実に変更ができ、また正確に変更されたか判定可能なAnsibleに切り替えました。
やはりSSHのみで完結するのは便利で、コマンドが失敗したときは再度実行すればいいだけですし一度作ると再利用が可能なのでこれからもWani Hackaseの資産として使っていこうと考えています。
認定証
担当 : EBebBeBebさん, Laikaさん
WaniCTFでは大会終了後にプレイヤーの順位表をホームページで掲載しています。
もちろん順位表があれば頑張りが見えますがやはり個々のプレイヤーにフォーカスを当てて頑張りを称えたいということで認定証システムを制作しました。
大会で点数を獲得された方全員分が掲載されており、Twitterで自分の順位をかっこいい画像とともにツイートできる仕組みになっています。
各ユーザーの「GETボタン」をクリックすると認定証が表示されます。
Discordの一本化
CTFではプレイヤーのサポートのためにDiscordがよく使われますが、何度も大会を開催していると管理しないといけないサーバーの数が多くなり、またプレイヤーも参加するDiscordサーバーが増えすぎてしまう問題がありました。
また、ちょうど数ヶ月前のTSG CTFでは1つのDiscordサーバーを継続して使用し続ける運用をされていたのでこれを真似をさせていただき、WaniCTF'21-springのサーバーをWaniCTFサーバーとして看板を変え運用することにしました。
インフラ総括
過去2回の大会経験によってかなり安定した運用を行える仕組みが構築されており、今回はインフラ担当・作問者・プレイヤーの体験向上のための様々な改善を行いました。(紹介しませんでしたがWaniCTFdのフロントエンドも少しいじってます)
今回の大会準備と運営中にもまだまだ改善したいことはたくさん出てきており、またプレイヤーの方からもご意見をいただきながら「楽に開催でき」「快適に参加できる」大会インフラを作ることができればと思います。
大会運営
インフラ面では障害なく48時間安定したサービスを提供することができ、運営中はこの開催記と週末の魔女のお茶会 CTF勉強会の発表資料を作りながらのんびりしていました。
ただ、スコアサーバーのパスワードを紛失してログインできなくなった参加プレイヤーの方がいらっしゃいました。現在のスコアサーバーではメールアドレスの確認などを行っていないため、本人確認ができず運営側で復旧はできません。この問題に関しては今後運営で協議の上改善を図りたいと考えています。
そして、大会終了後に発行した認定証は多くの方に喜んでいただけたようで嬉しいです。(担当してくれたEBebBeBebさんによるとユーザー名が絵文字の方の認定証生成が難しかったそうです。個人的には次の動物も楽しみにしていますのでよろしくお願いします。)
最後に
前回大会よりは参加者数が少なくなりましたが、多くの方にご参加いただくことができました。
いろいろとCTF運営の知見が溜まってきたので次は国内を飛び出して…などいろいろ計画しています。
また大会開催時にはご参加いただけると嬉しいです。ありがとうございました。
(個人的なお話)
今回はReversing3問とWeb2問を作問しました。
ReversingではPowerShell関連問題を2題出題したのですが、CTFにおいてWindowsでしか解けない問題は敬遠されることが多いためプレイヤーの方に受け入れられるように問題文で必死に「Linux環境でも解けるよ!」アピールをしていました。最近Windowsのセキュリティを触っているのでいろいろ工夫しつつ面白くて役に立つ問題を作りたいなと思っています。
あとWeb問題のtraversalが好評なようで嬉しいです。元々Nginxのmerge_slashes off;
問題を作っていたところでちょうどいいApacheの脆弱性が現れたのでそのまま組み合わせました。WaniCTF2020ではZerologonを扱った問題が出題されていますのでこれからもホットな脆弱性情報を仕入れつつ挑戦して下さい!
そして週末の魔女のお茶会 CTF勉強会にてCTF運営についてLTをする予定です。過去3回の大会運営で学んだことをメインに話をします。大会を開催してみたい・CTFの作問に挑戦してみたい・大会インフラに興味がある・運営が何をしているのか知りたい方に役立つ情報をお伝えできればと思います。他の発表者の方も面白そうなLTをされるのでぜひ見に来て下さい。
(追記)
魔女のお茶会 CTF勉強会のアーカイブ・資料が公開されました。
Youtubeアーカイブ https://www.youtube.com/watch?v=oKNwBLvO9vc
スライド https://speakerdeck.com/hi120ki/guide-for-holding-ctf-events