FortiGuard Labs 脅威リサーチ

ヒントとテクニック:.NET難読化ツールの逆利用

投稿者 Gergely Revay | 2023年1月18日

私は最新の分析レポート「Warzone RATをドロップするハンガリー政府偽装メール」で、ハンガリー政府を騙ってWarzone RATをドロップするフィッシングメールについて解説しました。この偽メールは複数の断続的な.NETバイナリを使用しており、難読化のレベルを次第に上げていきます。私が分析に用いたリバースエンジニアリングの手法をすべて説明していたら、このレポートはあまりにも長いものになっていたでしょう。しかし、それでも私は、これらの手法を知ることが絶好の学習機会になると考えています。このブログでは手法のうちの一つ、すなわち難読化ツールそのものを利用して、バイナリ内の文字列の難読化を解除する方法を紹介します。背景状況について詳しくは、こちらの分析レポートをご覧ください。

問題ステートメント

前回のレポートで説明したとおり、マルウェアの第2段階は.NET DLL(ダイナミックリンクライブラリ)で、関数(sk41Ua2AFu5PANMKit.abiJPmfBfTL6iLfmaW.Y5tFvU8EY())を呼び出すことでメモリに解凍され、実行されます。私たちはdnspyをデバッガーとして使用し、メモリからこのDLLをダンプすることができました。このDLLは、元はKeyNormalize.dllという名前で、SmartAssemblyという難読化ツールを使用して難読化されていました。難読化解除ツールとしてよく知られているDe4dotによって、使用された難読化の手法をいくつか解明することができました。しかし、バイナリ内の文字列をデコードすることはできませんでした。文字列はプログラムの動作を理解するうえで非常に有益であるため(だからこそ脅威アクターは文字列を隠そうとします)、文字列の難読化を解除できれば大きな成果が得られます。ただしそのためには、次の2つの課題に対処しなければなりません。

  • ランタイムデコードの動作を理解する。
  • 独自のデコーダーを実装する。

ランタイムデコードの理解

ダンプされたKeyNormalize.dllの関数sk41Ua2AFu5PANMKit.abiJPmfBfTL6iLfmaW.Y5tFvU8EY()(このDLLのエントリポイント)を見てみると、図1のようなエンコードされた文字列を確認できます。

図1:Strings.Get()でデコードされるエンコード文字列

このプログラムは、何らかの整数値を受け取るStrings.Get()関数を使用して文字列を作成していることがわかります。ここで何が行われているかを正確に理解するには、Stringsクラスを調べる必要があります。このStringsクラスはSmartAssemblyの一部である点に注意してください。まずはコンストラクタ(図2)を見てみましょう。

図2:リソースを読み込むコンストラクタ

次の2つのことがわかります。

  • Stringsクラスはある種のキャッシングを実装する。
  • データは「{d0d17239-57f1-4b72-b2aa-7b2e35d8851d}」というリソースから読み込まれ、変換されたのちStrings.bytesクラス属性に保存される。このリソース(図3)は明らかにエンコードされているため、詳しく調べてもあまり役には立ちません。また、おそらく文字列はエンコード形式でリソースに格納されています。
図3:リソース内のエンコード文字列

続いてStrings.Get()クラス(図4)を調べましょう。

図4:Strings.Get()クラス

単純な関数によって、まずstringIDが変換されます。次に、キャッシングが使用されているかどうかに応じて、Strings.GetFromResource()またはStrings.GetCashedOrResource()が呼び出されます。 キャッシングは無視してかまいませんので、図5のGetFromResource()に進みましょう。

図5:Strings.GetFromResource()の実装

最初に、データが Strings.bytes属性から読み込まれています。ここにはリソースのデータが格納されています。そのあと何らかのデータ操作が行われていますが、幸いこれについて理解する必要はありません。最後に、base64変換と文字列のエンコードが実行されます。こうして最終的な文字列が結果変数として返されます。これで文字列のデコードは終了です。私たちが得た有益な情報は次のとおりです。

  • エンコードされた文字列はリソース{d0d17239-57f1-4b72-b2aa-7b2e35d8851d}内にある。
  • キャッシングが使用されているが、無視してよい。
  • 文字列はエンコードされているだけで、暗号化やシークレットは使用されていない。したがって、文字列の復元は可能である。

なぜエンコードを詳細に理解する必要がないかというと、私たちの目的はSmartAssemblyの立場を逆転させることであり、SmartAssemblyに対してSmartAssembly自身のStringsクラスを使用し、文字列を復元することだからです。私はマルウェアのリバースエンジニアリングや侵入テストでも、この手法をよく使用しています。アプリケーションがデータを操作したり、ある種の複雑な変換処理を行ったりしている場合、そのアプリケーションのコードを使ってデータを復元できることがよくあります。この方法は、暗号化とエンコードには特に有効です。その場合、プログラム自身の復号 / デコード関数の実装を利用して、隠されていると思われるデータを復元することができます。ありがたいことに、相手が脅威アクターの場合、知的財産権の保護を気にかける必要はありません。

デコーダーの実装

前述したとおり、SmartAssemblyに対してSmartAssembly自身のコードを使用します。これにはさまざまな方法があります。たとえば、Powershellのリフレクションを使用したり、DLL全体をインポートしてその関数を呼び出したり、あるいはコードをコピーアンドペーストするだけの場合もあります。

今回はコードを部分的に変更する必要があったため、コピーアンドペーストを選択しました。

Visual Studioとラッパーコードの設定

まず、Visual StudioでC#プロジェクトを作成します。私はVisual Studio 2022 Community Editionを使用しました。これを起動して新規プロジェクトを作成します。[C# Console App(C#コンソールアプリ)](ここではStringDecoderと呼びます)を選択します。正しい.NETバージョンの選択が必要な場合もありますが、今回は最新バージョン(.NET 6.0)で問題はありませんでした。

デフォルトのProgram.csは「Hello, World!」を印刷します。これはひとまずそのままにしておきます。

Stringsクラスの作成

次に、File/New/File/General/C# Classにもう一つのソースファイルを作成します。このファイルにStringsクラスを貼り付けることができます。dnspyでStringsクラス全体をコピーし、Visual Studioで新規作成したファイルに貼り付け、Strings.csとして保存します(図6)。

図6:StringDecoderにコピーアンドペーストされたStringsクラス

このクラスには、修正が必要な点がいくつかあります。ただしその前に、プログラムの残りの部分を設定し、このプログラムを実行状態にします。これにより、動作していないすべての部分をデバッガーで順次修正することができます。

基本的なメインプログラムの作成

Program.csに戻りましよう。ここではStringsクラスをインポートし、Strings.Get()を呼び出し、コンソールで結果を印刷する簡単なコードのみが必要です。図7にこのコードを示します。

図7:テスト用メインプログラムの単純な実装

SmartAssembly.StringsEncodingをインポートする理由は、これが図6で示したネームスペースの名前だからです。Strings.Get(107349344) は、テストに使用したKeyNormalize.dllから、文字列のデコードをランダムに呼び出します。このプログラムを実行すると例外がスローされます。ただし、その例外はStringsクラスでスローされなければなりません。これにより、Strings.Get()の呼び出しが成功したことを確認できます。

エンコード文字列を含むリソースの追加

最初の例外は、エンコード文字列が含まれたリソースからデータを読み込めないことによって発生します(図8)。

図8:期待されたリソースが存在しないためスローされた例外

このプログラムにそのリソースは存在しないため、これは当然のことです。このリソースを追加しなければなりません。

まず、dnspyからデータをダンプします。{d0d17239-57f1-4b72-b2aa-7b2e35d8851d},まず、dnspyからデータをダンプします。[Save raw…(未加工で保存…)]を選択します(図9)。リソースに「encoded_strings.resource」という名前を付け、StringDecoderのProgram.csと同じプロジェクトフォルダに保存します。

図9:ファイルへのリソースのダンプ

これ以降、Visual Studioのソリューションエクスプローラーにこのファイルが表示されます。ソリューションエクスプローラーでこのファイルを選択し、[Properties(プロパティ)]で[Build Action(ビルドアクション)]を[Embedded resource(埋め込みリソース)]に変更します(図10)。

図10:リソースファイルの構成

KeyNormalize.dllと同様に、プロジェクトがビルドされると、最初のバイナリにこのリソースファイルが埋め込まれます。

Stringsクラスの修正

次に、Stringsクラスを更新して、新しく作成されたencoded_strings.resource.からエンコード文字列を読み込めるようにします。そのために使用するコードを図11に示します。元のコードが106行にコメントアウトされています。107行は、StringDecoder.encoded_strings.resourceからResourceStreamを作成します。プレフィックスのStringDecoderに注目してください。これはこのプログラムのネームスペースです。

図11:リソースを正しく読み取るためのコンストラクタ修正

もう一度このプログラムを実行してみると、正常に動作しています。図12では、私たちがデコードしている107349344が文字列「SearchResult」を参照しています。

図12:文字列のデコードに成功

このように、難読化ツール自身のコードを使用して、文字列の難読化を解除することができます。レポートはこれで終了しますが、FortiGuard Labsは当初の分析において、Strings.Get()関数の呼び出しをすべて収集し、Program.cs内のすべての文字列をデコードしました。文字列の中にはあまり重要でないものもあります。なぜなら、一部の文字列はKeyNormalize.dll内のコードによってさらに変換されるからです。ただし、さらに詳しい分析が必要な場合は、このプログラムでそれらの文字列を再実装することも可能です。

結論

この分析レポートでは、マルウェアに対してマルウェア自身のコードを使用する方法を解説しました。FortiGuard Labsは、文字列をデコードするSmartAssemblyのコードを使用して、リソースファイル内のエンコード文字列をデコードできるプログラムを実装しました。ターゲットバイナリのコードの使用は、多くの場合、多種類のカスタムアルゴリズムの再実装という、時間のかかる作業を回避するうえできわめて有効です。

フォーティネットのソリューション

Fortinetアンチウイルスエンジンは、以下のシグネチャを使用して上記のすべてのバイナリに対応しています。

MSIL/Kryptik.AGIJ!tr – Uj bejelentkezEsi adatai·pdf.exe
W32/PossibleThreat – KeyNormalize.dll
MSIL/Agent.UDJ!tr – Metall.dll
W32/Agent.TJS!tr – Warzone payload
W32/AntiAV.NIZ!tr – Privilege Escalation payload WM_DSP

C2サーバーは、FortiGuard Webフィルタリングサービスによって「不正」に分類されており、適宜ブロックされます。

FortiMailとFortiSandboxは、この攻撃の不正な添付ファイルを検知して隔離し、フォーティネットのCDR(コンテンツ無害化)サービスがそれを無効化します。

FortiEDRは添付された悪意ある実行ファイルとWarZone RATペイロードを、その振る舞いに基づいて「不正」として検知します。

これらの保護機能に加えて、フォーティネットはフィッシング攻撃の検知 / 理解に関するユーザートレーニングも支援します。

FortiPhishフィッシングシミュレーションサービスでは、実際の攻撃をシミュレーションし、フィッシングの脅威に対するユーザーの認識や備えをテストするほか、フィッシング攻撃を受けた場合の適切な対処方法を訓練および強化できます。

フォーティネットが無償で提供するNSEトレーニングプログラム:NSE 1 – 情報セキュリティ意識向上には、インターネットの脅威に関するモジュールが含まれ、エンドユーザーはフィッシング攻撃を識別して自らを保護する方法を学習できます。

IOC(Indicators of Compromise:侵害指標)

ファイル名

sha256ハッシュ

Uj bejelentkezEsi adatai·pdf.exe

21d09c77de01cc95209727752e866221ad3b66d5233ab52cfe5249a3867ef8d8

KeyNormalize.dll

8b533ffaed24e0351e489b14aaac6960b731db189ce7ed0c0c02d4a546af8e63

Metall.dll

66319bf905acac541df26fecc90843a9a60fdbc1a8a03e33f024088f586cb941

<Warzoneサンプル>

27743b5b7966384cc8ef9cfef5c7a11c8b176123b84c50192926c08ab7e6d7d7

 

ネットワークアドレス

タイプ

171[.]22[.]30[.]72:5151

C2サーバー

ATT&CKフレームワークのTTP

Warzone RATのTTPの詳細については、https://attack.mitre.org/software/S0670/でご確認いただけます。

フォーティネットのTraining Advancement Agenda(TAA)のイニシアチブである無料のサイバーセキュリティトレーニング、またはFortinet認定ネットワーク セキュリティ エキスパートプログラム、Security Academyプログラム、およびVeteransプログラムの詳細を参照してください。