2018年9月12日水曜日

DEFCON 26 CTF Finals 参加記

CTO(CTF Training Organizer) の前田です。
8月9日〜12日(現地時間)に行われた DEFCON 26 CTFのFinals にチーム binja の一員として参加してきました。



DEFCON 26 CTF Finals 概要

DEFCON CTF は世界最大の CTF 大会です。

今年は予選の結果 24 チームが決勝に進出し、そのうち 2 チームが日本のチームでした。
私が参加したチーム binja は 24チーム中 8 位という結果でした。



CTFのルール

ルールの詳細については公式のページに記載されているので、ここでは大まかに説明します。

まず、問題は例年通りの Attack&Defense (A&D) 形式の問題のほか、King-of-the-Hill(KoH) 形式の問題も出題されました。運営の説明で "like SECCON" と言っていた通り、問題を上手に解いている上位 5 チームには 5 分ごとに KoH point が加算されます。
"New Era" を強調しているからか、A&D のルールは若干特殊になっていました。
通常であればサービスを稼働させると SLA チェックがあり、フラグを奪ったチームに加点、奪われたチームは減点になるルールですが、今回は KoH 同様 5 分単位のラウンド制でラウンド内でフラグを奪うと奪ったチーム数分の点数が Attack point として入り、奪われたチームに減点はありません。その代わり、ラウンド中にフラグを奪われたチームにはそのラウンドの Defense point が加算されません。
これらの Attack/Defense/KoH のポイントを、40:40:20 になるように調整したものがゲームのスコアとなります。
また、 A&D なので当然アプリケーションを修正して防御することになりますが、この辺りも特殊ルールとなっていて、脆弱性を直接修正する代わりに運営にパッチを送ることで修正を行う形式になっていました。

CTF内で出題された問題

CTFでは 3 日に渡って次々と問題が出題されました。
問題にはライフサイクルが設定されていて、ある程度解かれた問題については途中でクローズされるため、大体常に3問程度の問題に取り組めるように構成されていました。

1日目
  • reverse (KoH) : 
  • pointless
  • twoplustwo
  • doublethink (KoH)
2日目
  • oooeditor
  • poool
  • bew
  • vchat
3日目
  • reeducation
  • propaganda (KoH)

個人の取り組み

binja 内で私が取り組んでいた内容について紹介します。

スコアボード作成

競技開始時は reverse に取り組んでいましたが、スコアサーバ内に現在のゲーム状況を記録した JSON ファイルが置いてあることに気づき、それをスコアボードとして見やすく整形するページの作成に取り掛かりました。
チームのスコアを確認するためにはスクリーンに映されるスコアボードを眺める必要があったため、作業効率をアップさせるためにも作成してよかったです。

自作スコアボードのスクリーンショット

スコアボードには現在の点数、最終ラウンドで獲得した点数、 KoH 内のランキングの表示を実装しました。
1 日目の半分は Attack/Defense/KoH の点数から計算される最終的なスコアの計算式を当てようと頑張っていましたが、結局特定には至らず、最後までランキングの順位表示は壊れたままになってしまいました。
2 日目には A&D 問題への攻撃が増加したため、JSON 内に含まれていたチーム間での攻撃ログとチームの得点履歴も併せて表示するようにしました。
3 日目はランキング表示の凍結とともに運営から JSON が提供されなくなったため、このスコアボードは役目を終えました。

pointless

1 日目の夜〜 2 日目は pointless に取り組みました。
この問題は MIPS のバイナリで、プログラムの最初の部分で暗号を使った認証処理が行われている様子だったのでこの部分の解読に挑戦しました。
かなり時間を掛けたものの完全な理解に至らず、問題はクローズされてしまいました。
この問題で攻撃ができればよかったのですが、この部分を突破できずに攻撃に繋げられなかったのでかなり悔しいです。

認証を通過すると脆弱性のある処理に到達できてしまう仕組みになっていたので、とりあえず認証処理に使われている値を少し変更するパッチを当てて様子を見ました。
しかし最終的には攻撃ログに pointless と binja の文字が登場していたので、守り切ることはできませんでした。

bew

web を逆から読んだ問題名なことから連想されるように、Web の問題です。
Web といっても問題の本質は WebAssembly なのでこれが DEFCON クオリティですね。

問題は容疑者の名前を報告できるという単純な Web サービスです。
サービスは Node.js 上で動いていて、報告した名前は Node.js から呼び出される WebAssembly 内で謎の "sanitize" をした後、そのままJavaScriptとして実行されるという、Web屋からすると謎の問題になっていました。
しかも sanitize される文字列は require と fs のみという非常に簡素なもので、おそらくこれらは require('fs') を使ってフラグを読み出されないようにするための対策だったようです。
また、Node.js のコードには直接手出しはできないようになっていて、パッチを当てられるのは WebAssembly のファイルだけという制限がありました。

WebAssembly 内の sanitize 関数

2 日目の夜にはこの sanitize 関数を読み、簡易の sandbox コードを前後に挟み込むパッチを作成して翌日適用するも、パッチの動作確認で失敗。今考えれば入出力が一致してないので当然アウトになりそうですね。
慌てて WebAssembly 内からデータを eval している部分を飛ばすようにパッチしたところ、これは普通に動いたようで一安心。アプリケーションの動作ガッツリ違うけどそれで通るのか。

他に夜の解析では、任意コード実行ができる脆弱性があるにも関わらず、問題のソースコードの権限がサーバの権限と同じに設定されているという問題や、任意コード実行が express のハンドラ内で起きるため Web アプリ自体を破壊できるという問題が見つかりました。
バグが見つかってもパッチ対象は指定の wasm ファイルだけなので、これらの問題は一旦放置していましたが、実際にこの手の攻撃は横行していて、 binja もパッチの適用に失敗している隙にバックドアを仕掛けられていました。

バックドアを仕掛けていた TokyoWestens のメンバーに聞いたところ、自チームからのアクセスのときだけフラグを表示し、他のチームに対しては表示させないような処理を入れていたそうです。
さすがにこれは運営も想定外だったらしく、ラウンドごとにサーバーの再起動を行うことで永続的なバックドアを仕掛けられないように途中で仕様の変更が入りました。

攻撃の方は夜に平行で攻撃コードをチームメンバーの tyage さんが書いていたので任せっきりでした。こちらはパッチを的確に当ててくるチームが多くて最初は苦戦していましたが、なぜか途中でパッチが外れているチームがあったようでそれなりに得点できていたみたいです。

まとめ

バイナリガチ勢ではないので DEFCON CTF Finals でどこまでバイナリを倒せるかという不安が若干ありましたが、バイナリを触りつつチームのサポートや Web 風の問題など幅広く動けたので自分の持ち味は出せたのかなと思います。

ただ、やはりバイナリの比重が大きいのでその部分で貢献できるようにならないと得点にはつながらないというのも事実で、今後も精進が必要だと感じました。