KDL BLOG

「DEF CON CTF 2018」に参加しました!(後編)

このブログでは、世界中のハッカーが集まるイベント「DEF CON(デフコン)」内で開催されたハッキングコンテスト「DEF CON CTF 2018」の決勝戦の様子を前編に続いて言及していきます。
dc2018_02.jpg

問題

競技時間は3日間に渡り、Attack & Defense 形式が7問、King of the Hill 形式が3問出題されました。その中で印象に残っている問題をいくつかご紹介します。

reverse

King of the Hill形式。まず、問題サービスに接続するためのクライアントの実行ファイルが与えられます。次に、クライアントを使用して接続すると何らかのプログラムと思われるx64のアセンブリコードの断片が歯抜け状態で出力されます。また、歯抜けの箇所に当てはまるであろうコードの選択肢が出力されます。

...
----------------------------------------
0x29ca18: 4889c6 mov rsi, rax
0x29ca1b: 4c89e7 mov rdi, r12
0x29ca1e: e85d16e1ff call sub_2966
0x29ca23: 85c0 ?????
0x29ca25: 7529 jne 0x29ca50
----------------------------------------
test eax, eax
pop rbx
sub esp, 0x4
retn
...

逆アセンブリ結果に対する穴埋めクイズで、元々のアセンブリコードを推測して選択する必要があります。選択肢を間違えるか制限時間内に解答できなければそこで終了になり、より多く解答したチームに点数が入るようでした。人手で多数の問題を回答していくことは難しく、いかにより多くの穴埋めクイズを解くことができるプログラムを組めるかという勝負です。

効率化のためにクライアントを介さずに直接サーバとやり取りをしようとも通信プロトコルは独自のバイナリ形式で、通信プロトコルを特定するためには 1MB に及ぶクライアントの実行ファイルを解析する必要があり、また後半につれて設問が難しくなるなど、一筋縄ではいかないようになっていました。

doublethink

King of the Hill形式。次の14種のアーキテクチャで特定のファイル、もしくはメモリ上に配置されている Flag 文字列を出力するシェルコードを書けという問題です。

AMD64, ARM64, MIPS, IBM-1401, LGP-30, MIX, NOVA, PDP-1, PDP-8, PDP-10,
cLEMENCy, Hexagon, MMIX, Risc-V

実行すべき処理は単純なものなので、作業量が多いだけで簡単そうに見えますが、この問題は複数のアーキテクチャ上で同時に実行できる1つのシェルコードを書けというものでした。より多くのアーキテクチャ上で実行できたチームに点数が入ります。

これはPolyglotとよばれるゲームで、一般的には高級言語のプログラミングで遊ぶものなのですが、それをアセンブリでやろうという趣向です。

ちなみに、アセンブリに詳しい人でも「cLEMENCy」というアーキテクチャはあまり見覚えが無いのではないかと思いますが、これは2017年の DEF CON CTF で登場した独自のアーキテクチャで、1byte が 9bit でミドルエンディアンでデータを扱うらしいです。よくあるアーキテクチャでは 1byte が 8bit でビッグエンディアンかリトルエンディアンという形式になるので、この独自アーキテクチャは嫌がらせですね。

競技中、binja ではバイナリ系やプログラミングに精通している人間(はたして人間なのか?)が7つのアーキテクチャ上で実行できるシェルコードを錬成していました。競技後、9つのアーキテクチャ上で実行できるシェルコードを錬成するためのRubyコードを公開していますので興味がある方はご覧ください。

bew

Attack & Defense形式。「DEF CON CTF で出題される問題はバイナリ系に偏っている」と言及しましたが、なんとこの問題は Web サービスになっていました。
配布物も実行ファイルではなく、Node.js 上で動作する JavaScript のソースコードとサービスの実行に必要なファイル一式となっており、Web 問題が好きな私としては出題された直後は非常に喜んだ記憶があります。

サービスの内容としては、入力値をサーバ上の特定のファイルに書き込む Web フォームのアプリケーションで、これと言った特色はありませんでした。

意気揚々とソースコードを解析したのですが、JavaScript のコード上にはそれらしい脆弱性が無く、コード以外の配布物を調べると node_modules/express-validator/express-validator.wasm という不吉なファイルがありました。
これは「WebAssembly」というブラウザ上で実行できるバイナリ形式の実行ファイルで、結局バイナリを解析する必要がでてきて非常に落胆した記憶があります。
幸いにも WebAssembly に精通していたメンバーがおり、解析とバイナリパッチの適用はなんとかなりました。

wasm 内の関数は JavaScript のコードから呼び出すことができ、配布された JavaScript のコード上でも上述の wasm 内の関数に入力値をそのまま渡して呼び出している箇所がありました。その関数内では与えられた文字列をコードとして評価し実行する関数「eval」に渡るようで、脆弱性自体は何の捻りもないコードインジェクションです。

そのため攻撃は、 eval を利用して相手サーバの Flag ファイルを奪取することが求められました。

逆に防御については、 eval を利用した攻撃をしかけられないよう対策を講じる必要がありました。当初はサービスの動作が規定通りと判定されるには eval が必要だという考えがあり、入力値にコードが与えられてもファイルの読み書きやシェルコマンドの実行は防ぐ施策を考えていました。
ところが思うように対策できず、試しに eval を実行しないようパッチを適用してもらったところ、すんなりサービスの動作チェックが通ってしまいました。防御としては、最も効果のある対策を講じられましたが、それまでの苦労を考えると複雑な気分でした。

結果


binja は1~2日目の成績があまり振るわなかったのですが、エクスプロイト担当各位の頑張りもあり、最終日に一気に追い上げて24チーム中8位になりました。

私自身の反省点は色々あるのですが、長時間のフライトは初めてということもあり、ラスベガスに着いた時点で体力を使い果たして体調を崩してしまったので、やはりもっと体力を付けないといけないというところがあります。

この経験を活かし、精進していきます。