12月の怒濤のSECCONイベントラッシュが終わり、個人的にはもういつ年を越してもいい気分になっています。 どの部分をどう振り返るべきか難しい上にこういうのを書くのは得意ではないのですが、、SECCON 電脳会議の一部として開催した"SECCON Speedrun Challenge"はまとめないと損が大きすぎるのでちゃんと書くことにします。

SECCON Speedrun Chellengeとは

その名の通りSpeedrunをする競技です。 名前にはCTFとは入っていませんが、CTFの問題をいかに早く解けるかを競います。 CTFでSpeedrunの性質を持つ開催形式にはKing of the Hillが挙げられるので実質これがSECCON決勝戦です(は?)。 他にはGoogleが開催する🔗Hackceler8 なんかもありますね1

配信上では2人の走者が解く速度を競うという形式にしつつ、スコアサーバを公開し視聴者も配信に合わせてスタートボタンを押すことで一緒に競技しているような感覚で参加できるようにしました。

開催したSECCON Speedrun Challengeの配信アーカイブはYouTubeに残しているのでまだ見てない方は軽く眺めてから読むとわかりやすいと思います。

本当は実際のスコアサーバーで試して欲しかったですが、競技の仕様上ずっと開けていると不正しやすくなるのでもう閉じてしまいました。 最後に@hakatashiさんがスコアサーバーのバグを発見しAny%解を送り込んだのが決め手でした。

経緯

SECCON 電脳会議でさすがにCTFチームも何か出し物をしないとな~と考えていたのですが、特に何かができる目処はなく、ふんわり"TSG Live!“で開催されている🔗ライブCTF みたいなものができないかな~と検討するくらいでした。 というのも、裏では色々ありこういうコンテンツに捻出できるような時間的人的リソースが全然足りていなかったんですよね。 ちなみに"TSG Live!“内のライブCTFでは、赤チームと青チームの2チーム対抗で制限時間100分2内にどちらのチームが多く得点を取れるかを競います。 視聴者も同時にCTFに参加することができ、赤チームや青チームと得点勝負をすることができます。

実はライブCTFに関連して、似たようなライブで何かをする企画としてRTA in Japanがよく知られていますが、これをどうにかCTFに輸入できないかというのを考えていました。 普通のCTFでは早解き問題というのは嫌われがちですが、ライブCTFの性質上画面が止まりすぎていると面白さを出すのが難しいので、それならば早く解けるような問題セットのほうがマッチするだろうという感覚がありました。

しかしCTFの運営チームにリソースがないのは変わらず、実現しなさそうなのでこっそり消えようとしていたところにptr-yudai大先生が一言。

この一言で話は急速に進んでいきます。ちなみにこの発言は12月2日のものなので、いかに何もしてなかったのかがよくわかります。

問題作成に苦労する予定が、その部分がいきなり解決されてしまったが為に急に開催が現実味を帯びました。 Speedrunっぽい配信をするために必要な最低限の要素は、「CTFの問題があって解いてる様子が配信でき、なおかつある程度の精度で時間が計れる」だと思うので、配信さえなんとかすればほぼ完成みたいな状況になっているわけです。 急に「なんかできそう」感に包まれたSpeedrun企画メンバーは各々作業に乗り出しました。

ptr-yudai大先生はもちろん問題を作り、theoremoonさんはスコアサーバーを作ってくれました。 記憶があんまり無いけど残りは大方自分がやった気がしています。しているだけかも。

作問

前述の通り、ptr-yudai大先生が全7問を作ってくれました。 筆者はそのうちCrypto4問をレビューしましたが結果は下のような感じでした。 走者には向いていません。

  • SexyRSA: 2:05
    • 順当
  • ProthRSA: 24:13
    • 10分くらい経過した頃にやっと数式を手書きし始めて理解した
    • $s = k_1 k_2$があるので$k_1 + k_2$を求めて2次方程式を解いた
  • LeakyRSA: 1時間オーバーしてヒント見てすぐ
    • $sq+a = 0 \pmod{p}$ は気づいてたけど small_roots のパラメータがうまくいかず溶かした
    • 急に式が簡単になるのでCoppersmithでこれほんとにいけんの?って気持ちが邪魔をする
  • Neighbor RSA: 37:55
    • なんかこういうやつをunbalanced RSAみたいなノリで見たな~と1%くらい思ってたけど30分くらいググらず
    • ググったらこれが出てきて内容読んでないけど書いてあった連分数展開やったら瞬殺

ゲームのRTAと違いCTFでは同じタスクを繰り返して時間短縮するということはできないため、出題する問題の難易度調整はかなり難しいです。 作問する難易度について「既出な感じのやつでいい」という話はしていましたがCryptoに関してはやや重かったと思います。 走者が解けるくらいの難易度を実現するためには、走者が圧倒的に強いか、作問者と走者で一緒にCTFに参加するなどしてレベル感を把握できている必要がありそうです。

配信画面

このイベントでは当然オープンのCTFを開催することよりも解いている様子を配信するほうが優先度が高いです。 SECCON 電脳会議側では業者による配信が入っていましたが、少なくとも複数の画面を入れ替わり立ち替わりするような要求は難しいと思い、最初から別枠で行く方針でいました。 あと外注だとスケジュールというものが発生してしまうので、そもそも何も決まってない状態では何もお願いできないですね。

ゲームのRTAイベントではどういう手法で画面を作っているのかを調べると、🔗NodeCG というフレームワークが使われていることがわかります。 NodeCGは配信画面のレイアウトなどをWebページとして生成し、それをOBSなどからWebページとして取り込むことで配信で使えるようにします。

Webページが単に配信画面になるのでは画像を取り込んでいるのと変わりません。 NodeCGには標準で提供されるダッシュボードがあり、Bundleというモジュールを開発することでダッシュボードの操作をWebページの方に反映させることができます。 Speedrun Challngeではこれを使って画面上に今解いている問題名や経過時間などを表示しています。 リソース的に本番で問題名を手入力したりコピペしたりするのは無理ゲーとわかっていたので、事前の時間でしっかり準備しました。

タイマー部分はちょうど良くcma2819/nodecg-timekeeper があったので使わせていただきました。 そのほかの部分は全部自作で時間も無かったことから怒濤の position: absolute 祭りが開かれています。 できればちゃんとモジュール化してビルドするとかなんとかしたかったところですが、コンポーネントは全然共通化されておらず1ヶ所修正するために数カ所の即値を直すみたいな地獄が発生します。 もし次回があったらきれいに作り直したいですね3

あ、あとスコアサーバーとの連携もだいぶサボって1秒おきに取得して差分を取るみたいな筋肉処理だったのでスコアサーバーの方にも手を入れるべきだったかも知れません。 ダッシュボードのスクショも撮ったんですが、途中でChallengeからTaskに名前を変えたせいで操作中は一切見ない"Challenges View"のところだけが取り残されてますね。見ないでください。

最終的にこの画面と走者の画面を全部合体させたときのOBSはこんな感じになっています。 全部で5シーンをポチポチ切り替えていました。 喋りながらシーンを忘れずに切り替えるのはかなり難易度が高かったです。

配信環境

ここまででなんとなく配信できそうに見えますが、まだまだ番組として完成させるまでにはまだまだ掛かります。 配信準備はほんのり検討はしていましたが、実際に手を付けたのは19日土曜日の夜なのでここから配信準備RTAが始まります。 途中で4K配信チャートを選択してしまったため作業が増大し、準備が終わったのは本番開始の2.5時間前でした。

スクリーン共有編

当たり前ですが、走者の画面や解説用のスライドを配信画面上に載せるためには画面をキャプチャして横流ししてもらう必要があります。 Zoomのような会議アプリでは同時に1人しかキャプチャできないので論外です4。 今はVTuber時代なのでこういう状況に関する情報は潤沢で、ちょっとググるとOBS Ninjaでコラボをする!みたいな記事がたくさん見つかるのでOBS Ninjaを使うことにしました。 クッソ難しいリンク生成アプリみたいなのを使わないといい感じにならないこと以外はスムーズに進んだのでよかったです。

ただ、微妙な仕様の都合かクソムズリンク生成に失敗したのか、同じ部屋に入っている人同士で画面が見えてしまうという問題がありました。 CTFである以上カンニングは防止したほうがいい気がしますが、YouTubeを開けばそもそも見られる上、カンニングしても結局RTAでは勝てないので些細な問題として放置しました。

マシン編

特に一番不安だったのはマシンスペック的な意味での配信環境でした。 筆者が配信するのが配役的に一番安定するのですが、残念ながら配信に適した高性能なマシンを持っていません。 普段使っているノートPCでもスペック的には足りる可能性がありますが、電力や排熱の関係でスロットリングが掛かってしまいフル性能を維持することができませんでした5

そこで、クラウド上に用意したマシンからの配信を考えます。 まずはSECCONインフラスポンサーのさくらインターネット様が提供するさくらのクラウド上でどうにかならないかを試しました。 今時のCPUなら1コアくらいあればH.264のエンコード・デコードはできるんじゃないかと踏んで、8コアのインスタンスを借りましたが全然足りません。 その後も色々試しましたが、CPUオンリーでは結局どうにもなりませんでした。

どうしようもないので次にGPU付きのインスタンスが借りられるクラウドサービスを検討します。 新たに決済回りを登録するのが面倒だったので、1度利用したことのあるGCPでいいインスタンスがないかを探しました。 🔗Azure に展開した仮想マシンで Teams を利用して OBS でライブ配信できるようにしてみました を参考に、N1の4コアにTesla T4が載ったインスタンスを準備しました。 結論を言うとこれが大正解で、5人分の画面と3つのNodeCGを載せても軽々捌いてくれました。

ここが配信準備RTAとしては見所で、クラウド上に作ったWindows Server 2019にRDPで入り、手元に用意しておいたChromeのインストーラをコピペすることでタイムを短縮したりしました。 ちなみにこのテクニックはIE Skipという名前で知られています6。 しかし、その後に入れたVoiceMeeterがインストール後勝手にIEを起動してきやがったのでロスが発生してしまいました。

音声共有編

司会や作問者が喋って配信するためには、何らかの手段で通話をすることになります。 今回はptr-yudai大先生の推薦や、配信拠点がクラウドでアカウント作成がないほうが便利なこともあってJitsi Meetを使いました。

音声共有自体は単純ですが、CTFの問題を解くときは走者同士の音声は切ることにしたため、その部分の運用にかなり苦労しました。

要件はこんな感じです。

  • かけ声と同時にCTFの問題を開きたい
  • 自分で部屋に出入りするとロスになってしまう
  • 時間が経過して解ける見込みがないときには呼び戻したい
    • チャット等で代替は可能ではある

特にスタート後に自分で抜けるような操作が必要になると、配信画面でスタートしているはずが最初に音声通話を切る処理をしているために、同時にスタートしているように見えなくなる可能性があるのが気になりました。 今回は残念ながら競ってどちらが先にフラグを提出するか?という状況にはなりませんでしたが、競ったときに開始時間が揃っていないと配信上では先に提出した方が実は負けているというパターンが起き得ます。

Pwnの走者であるkeymoonさんがJitsiにブレイクアウトルームがあるのを発見してくれたので、その後筆者が実験して次のようなプロトコルを考えました。

  • 走者は開始の合図と共に問題を解き始める
  • 手の空いている人が解いてる人をブレイクアウトルームに送還する
  • 問題が解けた走者は自分でメインルームに戻ってくる
    • 実況が気づかない可能性があるため
  • タイムアップした場合はブレイクアウトルームを破壊することで連れ戻す

Jitsiではここに出てくる操作は部屋にいれば誰でもできるようになっていたのでこのようなプロトコルになりました。 しかし実際は操作ミスなどにより関係ない人がブレイクアウトルームに送還されているなど様々な事故が起きました。 誰か専任でやってもらえば安心だったかもしれませんが、残念ながらそんな余裕はない。

マシン編2

GCPのインスタンスを借りて実験していると、思ったよりもCPUとGPUの使用率が低いことに気づきました。 さらにこの様子を見守っていたSECCON NOCチームのnomuken氏から、GCPからYouTubeへのトラフィックは無料ではないかという指摘があり、これは4K配信やるしかねえ!という空気が沸いてきます。

しかしOBSのキャンバスサイズには1080pまでしかなく、うまくいきません。 これはOBSが恐らく現在の解像度を限界に設定してしまうような処理を持っているためだと推測しています。 一晩寝たらRDPの解像度を4Kにしたら選べるのでは?とひらめき、実際そのようにして4Kキャンバスを実現しました。

え?「4Kなんてなかった?」

ちなみにTesla T4を使って4K配信をしたときのGPU使用率はこんな感じでした。

🔗Tesla T4の製品紹介 を見ると、最大38のFHDビデオをデコードできるとか書いてあったので化け物ですね。 東京リージョンにあったやつを適当に借りただけなのに凄い。 皆さんも複数のデスクトップが映るような配信をするときはGCPで4Kしましょう。

再・配信画面構築

4K配信になると position: absolute で書かれたページは破滅します。 仕方ないのでひたすら calc を挟んで2倍に。

仮想ミキサー編

VoiceMeeter Bananaを入れて使う気満々だったんですが、自分の環境でテストしたやつと同じようにクラウド上で設定してもOBS側まで音が届きませんでした。 渋々デスクトップ音声をそのまま配信するしかなかったわけですが、そのせいで音量調節がスーパーハードモードになりました。

配信当日・まとめ

ここまで苦労した甲斐あって、本番は大きなトラブルなく終えることができました。 細かいのだと少々スコアサーバーが重かったり、画面出す解答ログが壊れたりいろいろありましたが、今後の改善点としてはちょうどいいくらいの量だと思います。 ちなみにGCPに掛かった金額は事前準備・リハ・本番で1200円くらいでした。 これが書き終わってから削除しようと思っているので今もストレージ代が掛かっています。

SECCON 電脳会議の1日目を見ていたときに同時視聴者数が70人くらいだったので、実はSpeedrun配信では自分の中で100人を目標にしていました。 残念ながら100人達成はできませんでしたが、並走した感想ブログや後で解いてみたブログなどが結構上がってきたので感触としては悪くなかったような気がします。 今思うとアンケートを用意すればよかったんですが、思いつかない程度には大変だったので仕方ないですね。 今からでもいいので観戦記とかいろいろ書いてくれるとありがたいです。

ところでこういう催しは定期的にあっていいような気もするんですが、それって競プロの100分くらいのやつ7と同じだし別にそういう世界には行かなくていいな。 みんなでわいわい楽しむくらいでちょうどいいです。


  1. DEF CON CTFの予選かなんかで出たこともありますがJeopardyに入れるなよ、Speedrunを。 ↩︎

  2. 複数回開催してるので物によって違うかも ↩︎

  3. VueとTSが入ったNodeCGテンプレみたいなやつがあったけどうっかり時間を溶かしたくないので敬遠していました。配信準備もRTAしているため ↩︎

  4. それ以外にも論外ポイントはいくらでもありますが…… ↩︎

  5. CPUもGPUも100%まで行かずに頭を打ってしまう ↩︎

  6. いいえ ↩︎

  7. Heuristicじゃない方。なんて言うんですか? ↩︎