ペネトレーションテスト&バグバウンティ
Reverse Engineering(リバースエンジニアリング) CTFは、プログラム(機械語:二進数)の中身を深く理解し、制御の流れや内部の処理を暴いていく、気の遠くなるような知的なゲームです。
でも、知識がないと「なんのこっちゃ」わかりません。
非常に難しいです。なるべく、分かりやすく説明しますので、イメージだけでも理解していただければ嬉しいです。
Reverse Engineering CTFとは
Reverse Engineering CTFとは、コンパイルされた実行ファイルを解析して、隠されたフラグを見つける形式の問題です。
たとえば、「kurochan」ファイルを解析するとしましょう。
以下のような問題パターンがよく出題されます。
・入力チェック型:正しいパスワードでのみフラグ表示
・難読化型:XORやBase64でフラグが暗号化
・逆算型:演算処理を解析して入力を逆算
・メモリ型:メモリ内にだけ存在するフラグ
これらを解くことで、バグハンティングやマルウェア解析にも通じるスキルが身につくと考えます。
解析のための基本ステップ
準備
解析するための実行ファイルを作成します。
(1)Linuxで作成します。(私はKali Linuxを利用します。)
(2)プログラムはC言語で作成します。
(ソース名は"kurochan.c")
#include <stdio.h>
int main()
{
printf("Hello kurochan\n");
return 0;
}
(2)コンパイルします。
gcc -Wall -o kurochan kurochan.c
(3)実行すると
./kurochan
Hello kurochan
"Hello kurochan"と表示されました。
以下、この"kurochan"ファイルを利用して進めていきます。
解析のための基本の流れ
(1)ファイルの調査を行い、形式や文字列を確認します。
まず、提示されたファイルの情報をのぞいてみましょう。
Reverse Engineering CTFの第一歩は、提示されたファイルが一体なんなのかを調べることです。
Linux標準のコマンド「file」を利用します。
"file kurochan"
この「file」コマンドは、バイナリファイルの種類を教えてくれます。
上記のkurochanファイルの情報は
kurochan: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=742c35a064cc16a7e9f30fa3958d2b9dc5c5c5aa, for GNU/Linux 3.2.0, not stripped
となります。
出力結果の内容
・ELF
「Executable and Linkable Format」の略。LinuxなどのUnix系OSで使われる実行ファイルの形式。
・64-bit
64ビットアーキテクチャ向け。
・LSB
「Least Significant Byte」=リトルエンディアン(Intel系でよく使われるバイト順)。
・pie executable
Position Independent Executable。実行時にアドレスがランダムに変わる(ASLR対応)。セキュリティ強化のための設定。
・x86-64
IntelやAMDの64ビットCPU向けの命令セット。
・version 1 (SYSV)
ELF仕様のバージョンと、UNIX系(System V)準拠であること。
・dynamically linked
実行時に外部の共有ライブラリ(.so)を読み込む。
・interpreter /lib64/ld-linux-x86-64.so.2
リンクされた共有ライブラリを実行時に解決するための「ローダー」。Linuxがこのファイルを使ってプログラムを起動する。
・BuildID[sha1]=...
このバイナリ固有のビルドID(ハッシュ)。デバッグ情報との照合などに使われる。
・for GNU/Linux 3.2.0
このバイナリが対象としている最小のLinuxカーネルバージョン。
・not stripped
デバッグシンボル(関数名や変数名など)が削除されていない。つまり、GhidraやGDBで関数名などがそのまま見えるため解析が楽になる。
ネットで調べれば、これらの情報は簡単に見つけることができるのですが、プログラムのソース内容とは別に、いろいろな情報が格納されているのですね。
・・・気が遠くなってきそうです。(^^;
このファイルから得られる判断材料として
・Linuxの64bit環境で動かせる。
・PIEなので実行時アドレスはランダム化。
・not strippedなので、静的解析(Ghidraなど)が非常にやりやすい。
となります。
(2)動作観察
実行して“何が起きるか”を確認します。
ファイルの種類や構造がわかったら、次は実際に実行してみることが大切です。
このステップでは、入力や出力にどんなヒントが含まれているかを確認します。
※但し、このファイルはCTFでのファイルであることが前提です。メールなどに添付される不明なファイルなどは実行を考えないといけません。
./kurochan
具体例より、入力や出力のヒントを調べます。
a.入力を求められる例
./kurochan
Enter the password:
このような出力があれば、入力された内容をチェックしている処理があることが分かります。
CTFではこのような入力に対して、正しいパスワードを入力するとフラグが表示されることがあります。
b.不正解時のメッセージから推測する例
./kurochan
Enter the password: test
Wrong password. Try again.
このように「Wrong password」などの出力があれば、どこかで比較処理(strcmp()やmemcmp()など)をしている様子です。
その比較される「正解の文字列」を、コードを実行せずに解析を行う静的解析(Ghidra/IDA)や、コードを実行して解析を行う動的解析(GDB)で確認することになります。
c.ヒントっぽい出力例
./kurochan
Access Denied. Try input between 4 and 8 characters.
このようなメッセージがあると、「長さの制限がある」とか「文字数で分岐している条件がある」など、コード内に strlen() のような関数がある可能性が高いと推測できます。
d.正しい入力を入れても何も出ない例
./kurochan
Welcome.
入力を求められない場合でも、標準入力やコマンドライン引数を使っている可能性があります。
scanf()やfgets()で標準入力を受け取る。
argv[] でコマンドライン引数を見ている。
その場合、次のように入力して反応の様子をみます。
./kurochan correct_password
d.観察のポイントとして
・入力を求められるか
入力形式・長さ・必要性の有無
・出力メッセージ
「Wrong」「Try again」「Length must be...」などのキーワード
・入力後の反応
出力が変わる/落ちる/無反応(=何か条件分岐がある)
・入力方法の種類
標準入力 / コマンドライン引数 / ファイル読み込み
このように、動作を観察することで「どこを解析すればよいか」のヒントが浮かび上がってくるのです。
リバースエンジニアリングCTFでは、目に見える情報を丁寧に拾うことが解析のスタートラインになります。
CTFでよくある問題のパターンと攻略法
パターン:入力チェック型
攻略方法:strcmpやifで比較される値を探して特定
パターン:暗号化型
攻略方法:XOR, Base64などの逆変換を行う
パターン:ループ検査型
攻略方法:1文字ずつの検査を解析して再現
パターン:メモリ型
GDBでスタック・ヒープを探索
パターン:難読化型
攻略方法:Ghidraで整理しながら流れを可視化
パターン:アンチ解析型
攻略方法:ptrace回避や静的解析に切り替え
初心者におすすめのCTFサイト&ツール
CTFサイト
・picoCTF:中高生にもやさしい設計
・Crackmes.one:難易度別で挑戦できる
解析ツール
・GDB + pwndbg:実行中の挙動観察
・Cutter:軽量で直感的なGUIツール
バグハンターがCTFで学ぶReverse Engineering入門(初心者が知るべきバイナリ解析の世界とは)のまとめ
リバースエンジニアリングCTFは、内部のコードが見えない状態から推測し、検証し、再現する力を育ててくれます。
でも、基本を疎かにしてはいけません。
アセンブラ言語、C言語は当然理解していないと頭の中で内部コードの処理イメージが湧きません。
処理イメージが湧けば、パズルを解くようにロジックをたどり、メモリを覗き、暗号化を解いて、ついにはフラグへたどり着くことができるのではないでしょうか。
※難しい言葉が沢山でてきました。ネットで調べて自分の物にしてくださいね。