マルウェア解析に役立つ、実行ファイルのケーパビリティ検知ツールcapaの入門
2022年12月07日 水曜日
CONTENTS
【IIJ 2022 TECHアドベントカレンダー 12/7(水)の記事です】
はじめに
本記事では、マルウェア解析に活用することができるcapaと呼ばれるツールの概要と使い方を紹介します。日本語での本ツールに関する情報は多くありません。そこで、日本のマルウェア解析者の方に活用していただければと思い、本記事を作成しました。capaという名前を聞いたことはあるが、使ったことはないという方など、今回の記事を通して、実際に触るきっかけとなれば幸いです。
capaとは
capaは、PEやELFファイルなどの実行ファイルのケーパビリティを検知することができるツールです。さらに、.NETモジュールやシェルコードに対して実行することも可能です。ここで表現しているケーパビリティとは、実行ファイルが有する機能のことです。例えば、ネットワーク越しのデータ送受信や、Mutexの作成、新規にプロセスを作るなどです。これらケーパビリティの検知には、YAMLで表現されるcapaルールが用いられます。特に、capaの作成元であるMandiantが、capaルールを公開しており、マルウェアが使う多くのケーパビリティを検知できるように網羅されています。したがって、capaを使うことで、マルウェア解析の経験が少ない人であっても、対象ファイルがどういった機能を有するのか把握することができます。また、解析経験が豊富な方にとっても、マルウェアの持つ機能の概要を知ることができ、解析方針を立てる際に活用できます。
capaを使ってみる
capaは、シングルバイナリとしてリリースされているため、GitHubのReleaseページから簡単にダウンロードして利用し始めることができます。また、マルウェア解析用VM構築ツールFLARE VMを利用している方は、自動的にインストールされます。しかしながら、capaルールやバイナリも定期的に更新されているため、利用する際は常に最新版を使ったほうが良いかと思います。
最も簡単な利用方法は、下記のように対象ファイルのみを引数として渡す実行方法です。出力結果の中の一番下に「CAPABILITY」という要素があり、これが検知した実行ファイルが持つケーパビリティを表しています。
詳細な情報を得たい場合は、「-vv」オプションを併用します。本オプションを利用することで、capaルールの内容を実行ファイル中のどこで検知したのか、なぜ検知したのかといった情報を出力してくれます。例えば、先ほどと同様のファイルに対して、「-vv」オプションを併用すると下記のように、具体的なアドレスなども合わせて確認することができます。なお、検知箇所を知るだけであれば、「-v」オプションでも可能です。
ここでは、画像の一番最後に検知している「basic block @ 0x10001573 in function 0x10001510」について、逆アセンブルした実際の結果と見比べてみます。このブロックでは、nzxor(non-zero xor)と呼ばれるゼロ初期化ではないXOR処理と、tight loopと呼ばれるループ処理について検知しています。XOR命令は、「XOR RAX, RAX」のような同じレジスタ同士のXOR演算を行い、その性質上0を算出し、格納します。つまり、レジスタのゼロ初期化などに利用されることが多いです。そのため、マルウェア解析においては、こうした使われ方以外を調査します。ゼロ初期化以外の具体的なXOR命令の使われ方として、XORエンコードしておいたデータを格納しておき、利用時にそれをデコードするといった使い方や、暗号処理のアルゴリズムの一部で利用されることがあります。では、実際に0x10001573で検知しているアドレスの逆アセンブル結果を見てみます。
逆アセンブル結果を見慣れている人にとっては、一目瞭然だと思いますが、本ブロックはループ処理がされていることがわかります。0x100015ABのcmp命令にて2つのレジスタの値を比較し、その結果に基づいて次のjb命令で制御を移すか、そのまま次の命令を実行するかの分岐が行われます。また、赤線を引いた箇所では、ゼロ初期化ではないxor命令があります。capaでは、これら2つの要素をもとに、xorによるエンコード処理がされていると結果を出力しています。なお、本処理は、Emotetのnext-stageにあたるDLLを0x10001596でロードしているアドレスに格納されている文字列を鍵としたXORデコードする処理になっています。
capaルールを読み解く
では、最後にここまでブラックボックスであった、capaルールの中身を見ていきます。capaルールの構造を知ることで、自分でcapaルールを書くことができるようになり、外部公開レポートなどにも、IOC情報と合わせて記載していくこともできるようになるでしょう。大きな構造としては、非常にシンプルです。最上位の要素に「rule:」があり、その中に、「meta:」と「features:」という要素が並びます。例として、ここまで見てきたcapaルール「encode data using XOR」の中身を見ていきたいと思います。
meta要素
meta要素では、capaルールのメタ情報となるデータを記載します。いくつか大事な要素だけ解説します。nameで指定した値は、「capa -t “encode data using XOR”」のようにcapaルールを個別指定する際に利用するため、わかりやすいルール名が良いかと思います。namespaceでは、ルールを管理する実際のファイルシステム上と同じ構造にしておくとよいです。scopeは、capaルールが検知するための範囲を指定する場所です。本例では、「basic block」となっており、基本ブロック単位を検知対象としています。基本ブロックとは、内部に分岐処理を持たないコードの単位のことです。条件分岐命令やret命令などは、基本ブロックの終わりを意味します。この他にも、ファイル全体や関数単位などを表すことができる値も存在します。このscopeに応じて、後述するfeatures要素内で利用できる検知機能の要素が異なってくるため、そういった観点でもどのscopeを選ぶのかが重要となってきます。
features要素
features要素は、実際の検知ロジックを表現する場所です。andやor、notといった論理演算子を活用して、複数の条件を組み合わせることができます。このルールでは、2つの要素のandとある要素のnotが検知ルールとなっています。後者の要素は、false positiveのためのフィルターであるとdescriptionに書かれています。そのため、ロジックの中核となるのは、2つのcharacteristicという要素のようです。characteristicは、デフォルトで用意されているケーパビリティ集のようなものです。例えば、「tight loop」は、scopeが「basic block」か「function」でのみ使える値になっており、基本ブロックにおいて自分自身に分岐するような密な(tight)ループ処理を表しています。「nzxor」は、前述の通りゼロ初期化ではないxor処理を表しています。おそらく、これだけだと誤検知が多くなってしまうため、notによる後続の処理が必要になると推測されます。
ゼロからcapaルールを書きたくなったら…
今回例として取り上げたルールでは、characteristicつまりデフォルトの解析エンジンが抽出してくれる特徴を用いたルールでしたが、numberやmnemonicといった値やアセンブリ命令ベースでの検知ロジックを記載することも可能です。capaルールの基本的な構造は、公式のGitHubリポジトリのrule formatページにまとめられているので、実際にゼロからcapaルールを記載したい場合は、本ドキュメントを参考にしてみてください。また、rule formatページ内では専用のlinterやformatterも紹介されているため、これらを活用することで幾分か作成が楽になるはずです。
おわりに
本記事では、マルウェア解析に活用することができる、実行ファイルのケーパビリティ検知ツールであるcapaを紹介しました。ある実行ファイルに対してcapaを適用した際の実行結果や読み解き方、capaルールの具体的な構成について簡単に紹介しました。紹介した例は、機能のごく一部ですので、ぜひ公式ドキュメントなどを読み、さらなる活用方法を探ってみてください。
Twitterフォロー&条件付きツイートで、「IoT米」と「バリーくんストラップ」と「バリーくんシール」のセットを抽選でプレゼント!
応募期間は2022/12/01~2022/12/31まで。詳細はこちらをご覧ください。
今すぐツイートするならこちら→ フォローもお忘れなく!