CTF Advent Calendar 2024 - Adventar 用の記事として書きました。
残念なことに 12/9 から 12/18 までの空白地帯の中日ですので、前後の記事はありませんでした。
今回は、Mandiant の capa というツールを使用して実行ファイルが持つ機能を解析することを試してみます。
このツールを使用すると、ELF や PE、シェルコードなどのファイルを解析し、プログラムが使用している暗号化ロジック(RC4 や AES など)や、サービスのインストールや通信の有無などを確認できます。
参考:capa: Automatically Identify Malware Capabilities | Mandiant | Google Cloud Blog
参考:mandiant/capa: The FLARE team’s open-source tool to identify capabilities in executable files.
この記事では capa バイナリと Ghidra 統合機能を利用してプログラムの解析を試してみることにします。
本記事で使用するバージョンは以下の通りです。
なお、今回は Windows 環境を使用していますが、Linux でもほとんど同じ手順でセットアップできるはずです。
- Windows 11 23H2
- Ghidra 11.2.1
- Ghidrathon 4.0.0
- capa 8.0.0
- Python 3.12.0
また Python3 はたぶん最新のバージョンを使用して大丈夫なはずですが、本記事執筆時点では flare-capa のインストールに必要な依存関係パッケージの 1 つに、Python 3.13 でインストールに失敗する未修正のバグがあったので 3.12.0 を使用しています。
もくじ
capa バイナリのダウンロード
capa のスタンドアロンバージョンのセットアップ方法は非常に簡単で、リリースページからダウンロードした実行プログラムを展開するだけです。
capa の実行バイナリを環境変数に追加しておくと便利です。
capa と Ghidra の統合
Ghidrathon のセットアップ
以下のコマンドを順に実行することで Ghidrathon のセットアップを行います。
依存関係のパッケージをインストールする前には、JAVA_HOME
に適切なパスが登録されている必要があります。
参考:Releases · mandiant/Ghidrathon
cd Ghidrathon
python.exe -m pip install -r requirements.txt
python.exe ghidrathon_configure.py C:\Tools\Ghidra # Ghidra のインストールフォルダ(パスは任意に変更)
ghidrathon_configure.py
の実行に成功すると、Ghidrathon has been configured to use this Python interpreter. Please restart Ghidra for these changes to take effect
という表示が出力されます。
続けて、Ghidrathon の拡張機能をインストールします。
残念ながら Ghidrathon 4.0.0 のリリースファイルに同梱されているパッケージは Ghidra 11.0 用のものでしたが、ビルドが面倒なのでそのまま使用することにしました。
C:\Tools\Ghidra\Extensions\Ghidra
(インストールパスは任意に変更) にリリースファイル内に含まれる Ghidrathon-v4.0.0.zip を配置したら、Ghidra を再起動して [File]>[Install Extension] から Ghidrathon 拡張機能をインストールします。
私の環境の場合、Ghidra 11.2.1 を使用していたので拡張機能のバージョンとミスマッチしていますが、とりあえず動くのでこのままインストールしました。
気になる場合は独自にビルドする必要があると思います。
拡張機能のインストールが完了したら、コードブラウザの [File]>[Configure]>[Ghidra Core] から忘れずにプラグインを有効化します。
セットアップが完了すると、コードブラウザから Ghidrathon を起動できるようになります。
Ghidra Script の登録とルールのダウンロード
Ghidrathon のセットアップが完了したら、以下のコマンドで flare-capa パッケージをインストールします。
python.exe -m pip install flare-capa
パッケージのインストールが完了したら、以下で公開されている capaexplorer.py と capaghidra.py の 2 つのスクリプトを Ghidra のスクリプトフォルダに配置します。
参考:capa/capa/ghidra at master · mandiant/capa
ここで取得したスクリプトを Ghidra で実行することで capa と Ghidra を統合できるようになりますが、flare-capa を使用する場合は別途検出に使用するルールを取得する必要があるようです。
そこで、以下のリポジトリから最新のルールセットをダウンロードし、端末に展開します。(8.0.0 のルールセットを使用した際にエラーになる場合は、7.4.0 やその時点の最新バージョンを使用してください)
参考:Releases · mandiant/capa-rules
ここでダウンロードしたルールファイルを展開したフォルダパスを Ghidra で capaexplorer.py や capaghidra.py を実行する際に指定することで、Ghidra から capa を利用することができるようになります。
これで Ghidra と capa の統合も完了です。
capa でバイナリを解析してみる
capa による暗号化ロジックの検出
capa のセットアップが一通り終わったので、まずはいくつかのバイナリを解析してみることにします。
初めに解析するのは、WMCTF 2023 で出題された RC4 と AES 暗号化ロジックを持つ ELF バイナリです。
参考:Android のネイティブライブラリ関数解析と RC4 と AES の復号を行う【WMCTF 2023】 - かえるのひみつきち
今でこそ RC4 や AES くらいであれば逆アセンブル結果などからある程度スムーズに特定することができますが、以前この問題をに挑戦した際は RC4 の実装に気づくことができず、悔しい思いをしました。
しかし、このバイナリを capa に食わせると、RC4 や AES の暗号化ロジックが含まれていることを簡単に特定できます。
実際に、このバイナリを capa で解析した場合には、出力結果の [MBC Objective]>[CRYPTOGRAPHY] 欄にて AES と RC4 のルールにマッチする実装が検出されたことを確認できます。
capa の存在を知っていれば、以前の CTF でももっと楽ができたかもしれません。。。
capa の解析結果を Ghidra で確認する
さらに、このバイナリを Ghidra で統合した capa で解析してみます。
2 つのスクリプトのうち、capa_ghidra.py スクリプトは、スタンドアロンツールである capa.exe を実行した際と同等の出力をスクリプトウィンドウ内に表示してくれます。
一方で、capa_exlorer.py を使用すると、Symbol Tree ウィンドウ内の [Namespaces]>[capa] 内に capa の解析結果とコードが紐づけされた情報が追加されます。
今回のバイナリの場合、以下のように RC4 が実装されているとみられる関数などが一覧に表示されていました。
しかし、Ghidra に表示された結果を見ると、RC4 の実装が行われている関数はマークされているものの、AES の実装に関わる部分の情報はマークされていないことに気づきます。
スタンドアロンツールである capa.exe を実行した際と同等の出力をスクリプトウィンドウ内に表示する capa_ghidra.py スクリプトを実行した場合も同様で、capa.exe が検出してくれた AES に関するルールマッチが結果に含まれていませんでした。
この問題の明確な原因については特定に至らず、capa のリポジトリの Issue を軽く探した限りでは類似の問題に関する情報は見当たりませんでした。
しかし、いくつか動作確認をした限り、Ghidra 側で実施した Analyze の設定によっては capa スクリプトによる解析結果が変化する場合があるようでしたので、恐らく Ghidra を通して収集する情報と、capa.exe がバイナリファイルを直接解析して得る情報に何らかの差異があるのではないかと予想しています。
JSON フォーマットのエクスポート結果からルールにマッチしたオフセットを特定する
このように、capa の Ghidra 統合は非常に便利ですが、今回使用したバージョンでは、スタンドアロンツールで解析した場合と比較して検出できる項目が少なくなる問題が発生します。
このような場合の対処方法の 1 つとして、スタンドアロンツールで解析した結果を JSON フォーマットで出力し、capa のルールにマッチしたファイルオフセットを特定するという方法があります。
以下のように --json
もしくは --j
オプションを使用して capa を実行することで、解析結果を JSON 形式で得ることができます。
capa.exe --json ./x64.so > output.json
capa の解析結果を JSON ファイル形式で取得したら、まずは base_address
の value を参照します。
私の環境で実行した際には、この値は 0x2000000 でしたので、この値を覚えておきます。
次に、RC4 のルールにマッチした結果が記録されている行から、ルールにマッチした箇所の位置を調べます。
この時 value に記録されている値は 0x2004890 でした。
どうやら、capa が出力した JSON 内の値はルールにマッチした箇所の RVA になっているようです。
実際に、Ghidra の Go To 機能でこのアドレスにジャンプすると、capa_explorer.py でマークされた RC4 関数のアドレスと同じ関数を参照することができました。
では次に、capa_explorer.py で検出できなかった AES 暗号化ロジックに関連するコードを確認していきます。
まずは先ほどと同じように、capa が出力した JSON 結果から AES に関連するルールの検出結果に関わる行を特定し、ここに表示されている値 33564304(0x2002690) から、アドレス 0x2690 を抽出します。
続けてこのアドレスにジャンプすると、DAT_001067e0
に存在する 0x100 バイトの値をコピーするところから始まる関数が実行されていることを確認できます。
実際のところ、このアドレスに存在する値はこのバイナリにおいて AES 暗号化を行う際に利用されるカスタム S-BOX に該当しています。
そのため、capa を使用することで簡単にプログラムの実装の解析と、そのアドレスを特定できたといえます。
ちなみに、capa が出力した JSON 形式の情報は、capa Explorer Web を使用することで簡単に可視化することができます。
このツールは、オフラインで利用することも可能なので、様々な環境でスムーズに capa の解析結果を参照することができます。
他のバイナリも capa で解析してみる
最後にいくつか、過去に解析したバイナリを capa で再解析した場合の出力結果をいくつか見ていくことにします。
まずは、RC4 で暗号化された PE バイナリのデータがハードコードされており、実行時にそれを復号して呼び出すような実装になっているプログラムを解析した場合は、以下のように Executable Code Obfuscation
や parse PE header
などのルールにマッチした結果が表示されました。
例えば、この parse PE header
のルールは以下の通りベースアドレスが 0x400000 の場合の 0x401192 が指す関数をマークしているようです。
実際にこの関数に Binary Ninja(または Ghidra など) を使ってジャンプしてみると、PE ヘッダのチェックを行っていそうなコードの存在を確認できます。
他には、以前 Hero Ransom という問題で出題されたバイナリを capa で解析してみたところ、パッキングされたファイルなので解析ができないという警告が表示されました。
参考:Hero CTF 2023 Writeup - かえるのひみつきち
このバイナリは Process Hollowing によってメモリ内に回答した実行プログラムを展開する機能を持っていますが、こういったバイナリの解析は当然ながら capa による静的解析では対応できなさそうです。
ただ、今回の記事では扱いませんが、CAPE sandbox というサンドボックスと連携することで、パッキングされたマルウェアなどを capa で効果的に解析する方法自体は存在しているようです。
参考:Dynamic capa: Exploring Executable Run-Time Behavior with the CAPE Sandbox | Google Cloud Blog
まとめ
今回は、高機能な静的解析ツールの capa をスタンドアロンツールもしくは Ghidra 統合で使用する方法をまとめました。
CTF で使う際には暗号化ロジックの特定くらいが主な用途になりそうな気がしますが、暗号化処理の特定は初心者にはハードルが高いスキルの 1 つだと思うので、その点で役に立つのではないかと思います。