This post is also available in: English (英語)
概要
マルウェア作者は意表をつくやりかたで検出を回避しようとすることがよくあります。こうした技術に対応すべく、私たちの側も本稿で解説する数々の効果的手法を重ねて分析プラットフォームを調整しています。なかでも、サンドボックス回避型マルウェアに対応するための調整をよく行います。
そうした調整の1つめが、私たちが「依存関係のエミュレーション」と呼んでいるアプローチです。このアプローチでは、通常であれば依存関係が解決できないことからサンドボックス環境で実行できないはずのマルウェアのサンプルをうまく起動できます。ほかには、暗号化ネットワークトラフィック解析用のステルス型インスツルメンテーション(計装)戦略についても解説します。コマンド&コントロール(C2)トラフィックは、SSLを使うことで解析をされづらくすることがありますが、この戦略はこうした手法に対応します。
マルウェア作者らに共通する目標の1つは「最終目標の達成までは検出されないこと」です。以前本稿ブログ シリーズでも詳しくお伝えしたように、サンドボックス アプローチや静的解析アプローチの裏をかくべく、無限といえるほどの回避策や戦略が生み出されています。こうしたマルウェア作者らの検出逃れにかける努力に対応していくのは、果てしなく続くいたちごっこの側面があります。こうしたことから私たちは「自動マルウェア解析プラットフォームにいちばん重要な特性は適応力だ」と理解するようになりました。
パロアルトネットワークスのお客様は、高度なWildFireを通じ、本稿で解説する回避技術の検出力を高められます。
関連するUnit 42のトピック | Sandbox Evasion, Memory Detection |
依存関係のエミュレーション
マルウェア実行の文脈では依存関係がよく話題に登ります。ここでいう依存関係は「実行ファイルが依存する追加コードのうち、当該実行ファイル内に存在しないもの」を指します。これがWindowsであれば、外部依存関係は「実行するプロセスにインポート可能な追加の機能を含むダイナミック リンク ライブラリー(DLL)」を指すことが多いでしょう。
悪意のあるコードの実行に外部ライブラリーを必要としないマルウェアも多いですし、実行のかなり後のほうまで外部ライブラリーの関数を呼び出さないマルウェアもあります。ここ数年は、GUIの提供やクロスプラットフォームのサポート用に外部ライブラリーを要求する悪意のあるWindows実行ファイルが大幅に増えています。それらのライブラリーがなければ、それらのサンプルは実行できません。ライブラリー不足でWindowsがアプリケーションをロードできない場合、「System Error」というエラーメッセージボックスが表示されて不足ライブラリー名が表示されます。
依存関係を解決する必要のある実行ファイルをサンドボックス環境で実行した場合も同じエラーが表示されます。悪意のあるコードが実行されていないのでこのサンプルからは解析情報が得られません。
図1はATMSpitterマルウェア ファミリーのスクリーンショットです。このマルウェアを完全に起動させるにはMSXFS.dllというDLLが必要です。必要なDLLがなければ「Windowsはこのファイルを実行できない」という内容のエラー ダイアログが表示されるだけで終わってしまいます。同じディレクトリに正しいファイルを配置してサンプルを再実行すれば、今度は正常に動作して実行されたシステム コールや変更されたメモリー領域などの情報を抽出できるようになります。
![画像1は「MSXFS.dllがコンピュータにないのでプログラムを開始できない」というシステム エラーのポップアップのスクリーンショットです。「この問題を解決するにはプログラムを再インストールしてみてください」と説明が続きます。](https://unit42.paloaltonetworks.jp/wp-content/uploads/2023/03/figure-1-atmspitter-malware-requires-msxfs-dll-in.png)
Sality、Floxif、Expiro、Ramnitなどのファイル インフェクターは通常、ディスク上に存在する一連の事前定義済み実行可能ファイルに感染します。感染ファイルがオペレーティング システム(OS)に含まれていない特定のライブラリーを必要とする場合、こうした依存関係は環境内にプリインストールされていない可能性が高く、マルウェア解析サンドボックスでは起動しないと予想されます。サンドボックス環境はディスク容量などのリソースに制限がありますし、世の中にはほぼ無数のDLLファイルが出回っています。
通常なら、こうした状況でOSローダーがファイル実行を拒否した場合、動的解析によるデータはまったく残りません。この状況でさらに腹立たしいのは、感染ファイルにとってこれらの依存関係不足がなんら問題とならず、使う予定すらないことも少なくない、ということです。
ファイル インフェクターは通常、外部ライブラリーから関数を呼び出すよりずっと前の、ごく初期の段階に悪意のあるコードを呼び出します。たとえば、最初のほうのcall命令を悪意のあるコードに置き換えたり、PEヘッダーのエントリー ポイントを上書きしたりするのです。オペレーティング システムは、どの依存関係も問題とならないにもかかわらず、サンプル ファイルのロードと実行を拒否してしまいます。
ファイル インフェクターの例
ここではSalityというマルウェアに感染したあるファイルを見ていきます。このマルウェアをサンドボックス内で実行するには外部依存関係を解決せねばなりません。元になったファイルはMicrosoft OfficeのGroove Audit Serviceで、このファイルはGrooveNew.dllとGroveUtil.dllというライブラリーとの依存関係があります(図2参照)。この2つのライブラリーがシステム上になければ実行できません。
![画像2はGroove Audit Serviceというファイルのスクリーンショットです。この図はサンプルの実行に必要な依存関係を表示しています。](https://unit42.paloaltonetworks.jp/wp-content/uploads/2023/03/word-image-127312-2.png)
StudPEなどのPEビューア(図3)で元ファイルと感染ファイルを比べると、このインフェクターはいくつかの値しか変更していないことがわかります。たとえば、PEヘッダー内のイメージ サイズ、チェックサム、最後のセクションを実行可能にするためのセクション フラグなどだけです。
![画像4はコードのスクリーンショットで、元ファイルのエントリー ポイントを含む複数の行を表示しています。](https://unit42.paloaltonetworks.jp/wp-content/uploads/2023/03/figure-4-original-entry-point-.png)
![画像5はコードのスクリーンショットで、感染したファイルのエントリー ポイントを含む複数の行を表示しています。](https://unit42.paloaltonetworks.jp/wp-content/uploads/2023/03/figure-5-modified-entry-point-.png)
依存関係の問題の緩和
さらに大規模に解析を行いたいとき、この依存関係の問題にどう対処していけばよいのでしょうか。私たちが最近プロトタイプをつくってみて有用と判断したアプローチが「依存関係のエミュレーション」です。
このアプローチで中心となる考えかたは「依存関係の不足状況を自動検出し、起動対象ファイルに合わせてサンドボックス環境を適応させ、起動対象ファイルがきちんと起動できる機会を与えること」です。自分たちで管理しているサンドボックスですから、解析対象の実行ファイルが外部ライブラリーを必要としているかどうかを判断し、実行ファイルに対して依存関係の要件がすべて満たされているフリをするのは容易です。
日次で処理するWindows実行ファイルは重複なしで100万件以上におよぶので、外部依存関係のある実行ファイルごとにその特定外部ライブラリーを自動検出・追加するのは、不可能ではないにせよ、かなり難しい作業です。文字通り何億種類ものライブラリーが存在していますし、それぞれのライブラリーにも多数のバージョンが存在します。
ですが、本ブログ シリーズ初回の記事でも説明したように、正確に検出するのに完全な実行が必要でないことも多いのです。解析対象のマルウェア サンプルがWindowsローダーを通過して自身を初期化し、追加ペイロードを展開できれば、検出のチャンスはぐっと高まります。それができないと、ただWindowsローダーからエラーが出るだけで、静的解析で得られる以上の情報が得られません(図1)。
実行ファイルがこれらの依存関係のなかの関数を呼び出そうとした場合はどうなるかというと、残念ながら必要なライブラリーの実コピーを提供しようとしているわけではないので、環境にないライブラリーへの関数呼び出しは正確にはシミュレートできません。
それでもほとんどの場合はこれでじゅうぶん正確に検出できます。実行ファイルに存在するすべてのコード パスを正しく実行する必要はなく、正確な検出に足るだけの実行とメモリー アーティファクトが得られればそれでよいのです。こうした理由から私たちのサンドボックスは、生成されたスタブ ライブラリーの関数が呼び出された場合は実行を停止し、解析対象サンプルが意図せずクラッシュしたりバグを発生させたりしないようにしています。
このアプローチにより、通常なら起動しなかったサンプルを多数起動できるようになり、正しく検出できることが増えました。
仮想マシン イントロスペクション(VMI)を使うSSL/TLS復号
マルウェアの大規模解析で直面したもう1つの課題は「マルウェアに気づかれずにTLS暗号化トラフィックを覗くにはどうすればよいか」というものです。インターネット リソースへのアクセス時、HTTPSなどSSLベースのプロトコルを使うのがごく一般的になってきているので、今ではマルウェア作者らも、当然のようにそれらのプロトコルでペイロードの次のステージをプルしたりC2通信したりしています。
もちろん、中間者攻撃(meddler-in-the-middle)アプローチでサンドボックスからのトラフィックをすべて傍受・解読するのは1つの近道ですが、それだとTLS証明書を調べればマルウェア側に検出されてしまうのがネックです。ほかには「より高次のネットワークAPI呼び出しを実装してそれらを記録する」というアプローチも取れなくはないですが、これも検出されてしまう場合が多く、暗号化通信をあまさず取得できるわけでもありません。
この問題に有用と思われる解決策の1つは、TLS接続の開始タイミングを検出して、仮想マシンのイントロスペクション(VMI)を使い、SSL/TLS接続用に生成された対称鍵を記録することです。
まずはTLSハンドシェイクについて簡単におさらいし、その後でこの検出方法を見ていきます。
TLSハンドシェイク
SSL/TLS接続を確立するさいは、ローカル システム(クライアント)とリモート サーバーとの間で特定のデータを交換してそれぞれの側の信頼性を検証し、データを暗号化するための対称鍵を生成します。
このデータには以下の内容が含まれます。
- 推奨されるTLSのバージョン
- サポートされる暗号スイート
- 鍵生成アルゴリズムに用いる32バイトの乱数値
- Ephemeral ECDH(ECDHE)による鍵交換の場合はデータ署名
図6にECDHEの「Server Hello」メッセージの一例を示します。
![画像6はWiresharkのスクリーンショットです。この図には3つの赤い四角が描かれていて、これらの四角は、上から順に、使われているTLSのバージョン、ランダム データの値、暗号スイートをハイライトしています。これは開始時のSSL接続のハンドシェイクです。](https://unit42.paloaltonetworks.jp/wp-content/uploads/2023/03/figure-6-wireshark-screenshot-illustrating-the-in.png)
DH(Diffie-Hellman)ハンドシェイクの場合、その後で追加のDHパラメーターが交換され、クライントとサーバーがそれぞれにプレマスター秘密鍵を生成します。最後に、このプレマスター秘密鍵、クライアントの乱数値、サーバーの乱数値を利用し、両サイドでそれぞれに同じマスター秘密鍵を生成します。
生成されるマスター秘密鍵の長さは48バイトです。リバース エンジニアリングしたところ、Windows OSの最近のバージョンではncrypt.dllライブラリーがこの鍵の生成を行っていることがわかりました。
鍵の生成はメモリー上で行われ、ディスクに書き込まれることはありませんし、ネットワーク上を流れることもありません。ですが、コード内で各マスター秘密鍵が生成されている正確な場所と、メモリー上の正確な場所がわかれば、鍵を抽出できます。これはたとえば、仮想マシン イントロスペクション(VMI)を経由する解析エンジンで実現できますし、これによってマルウェアからシステムを隠すことができます。鍵の生成にOpenSSLなどのサードパーティー ライブラリーが使われている場合でも同様のアプローチをとれます。
図7に、TLSトラフィックの復号に必要なデータの一覧を出力したものを示します。
![画像7は、抽出された乱数(クライアントおよびサーバー)、TLSのバージョン、マスター秘密鍵、RSAセッションID、サーバー名を表示したスクリーンショットです。](https://unit42.paloaltonetworks.jp/wp-content/uploads/2023/03/figure-7-extracted-random-value-and-master-key-.png)
ネットワークトラフィックの暗号化と復号に使う最終的な鍵や初期ベクトル(IV)は、このマスター秘密鍵からの鍵の拡張を経て生成されます。オープンソースツールのWireshark/Tsharkは、キャプチャしたpcapトラフィックを自動的に復号するための鍵ファイルを受け付けてくれるので便利です。
WiresharkによるSSL復号の例
ここではFormBookマルウェア ファミリーに属する実際のサンプルを例にとって説明します。このサンプルは、Delphiで書かれたローダーによってロードされ、HTTPS経由でパブリック ファイル ストレージ サービスから次のステージをダウンロードします。
キャプチャしたpcapデータをWiresharkで開き、このpcapに私たちの解析プラットフォームで抽出したSSL/TLS鍵を与えると、ダウンロードしたデータを含むパブリック ファイル ストレージ サービスへのSSL暗号化トラフィックを確認できるはずです。
なお、クライアントの乱数値とマスター秘密鍵はWiresharkがサポートする特定のファイル形式で保存する必要があります。このファイル形式は以下の通りです。
1 |
CLIENT_RANDOM <random_client_value> <master_secret_key> |
Wiresharkに復号鍵を与える場合はssl.keylog_fileというオプションを使う必要があります。このオプションはコマンドライン経由で渡せます。たとえば以下のようにします。
1 |
wireshark -r guest_traffic.pcap -o "ssl.keylog_file:key_capture.keys" |
Wiresharkでキャプチャ(pcap)を開くと、TLSで暗号化されたデータが復号されるので、httpフィルタで復号されたHTTPSトラフィックを取得できます。そのようすを図8に示します。
![画像8は復号されたHTTPSトラフィックを示すWiresharkのスクリーンショットです。](https://unit42.paloaltonetworks.jp/wp-content/uploads/2023/03/Screenshot-2023-03-17-at-12.56.30-PM.png)
図9と図10は、パブリック ファイル ストレージ サービスへの通信のようすを示しています。
結論
本稿は私たちの分析用環境の調整に使った2つの重要な手法を解説しました。以前のブログでも解説したとおり、マルウェア検出という課題に対応しつづけるには、なによりもサンドボックスの適応力が求められます。脅威は絶えず進化しています。したがってそれに対応する分析システムも、スタンドアロンのモノリシック アプリケーションでなく、より柔軟でうまく抽象化されたソフトウェア開発キットとして構築する必要があります。
こうしたことを念頭に、本稿ではプラットフォームの適応力向上をもたらした高度なWildFireにおける2つの重要ポイントを解説してきました。1つめのポイントは「依存関係のエミュレーション」です。これにより、マルウェアの実行率があがり、正確な検出にかかせない実行ログをより多く収集できるようになりました。2つめのポイントは「仮想マシン イントロスペクション(VMI)を使うSSL/TLS復号」です。この方法により、マルウェア作者に検出されずに、すべてのSSL/TLS通信を可視化できます。
長文をここまでお読みいただいた読者の皆さん、ありがとうございます。インターネットに蔓延するありとあらゆる悪質ファイルの正確な検出に向けた、あくなき努力の一環として、私たちが手掛けている興味深い仕事の一部をちょっと覗いてお楽しみいただけていたならうれしいです。
IoC
SHA-256値 | 名前 |
c5b43b02a62d424a4e8a63b23bef8b022c08a889a15a6ad7f5bf1fd4fe73291f | ATMSpitter |
a3b2de8f0d648f3e157300d0a88971919eb273b7d1c7b9ed023f26b5cc0ac3ca | Salityの感染ファイル |
4e32a6000a2b33ed0b8e4cf1256876c356cf5508ce0df2752fcfa214b6c2795b | Formbook (SSL復号) |