GreyEnergyはAdvanced Persistent Threat(APT)であり、過去数年にわたりウクライナをはじめとする東欧諸国の産業ネットワークを標的としてきました。私たちは先月、このマルウェアのコンポーネントの概要を発表し、GreyEnergyがシステム内に存在する場合にアラートを受け取ることをお客様にお知らせしました。
それ以来、私はGreyEnergyの感染経路の1つである、悪意のあるMicrosoft Word文書(Maldoc)を標的の組織に送信するフィッシングメールを深く掘り下げてきました。この記事では、誰かがフィッシング・メールを受け取った瞬間から、マルウェア(バックドア)がシステムにインストールされるまでのマルウェアの仕組みについて詳しく説明します。
私のコメントは、GreyEnergy の機能を段階的に理解しようとしているセキュリティ・アナリストの視点からのものです。これらのコメントは、ICS セキュリティ・コミュニティが最新の脅威を把握し、他の人々が産業ネットワークまたは野生の GreyEnergy を特定するのに役立つことを目的としています。
この記事に関連して、Nozomi Networks 、セキュリティ・アナリスト向けの無料ツール「GreyEnergy Unpacker」を公開した。これは簡単に実行できるPythonスクリプトで、maldocによってダウンロードされたパッカーによって保護されたドロッパーとバックドアを自動的に解凍し、さらなる分析を容易にします。
バックドアへのGreyEnergy Maldocの概要
GreyEnergy ICSマルウェアは、感染文書を添付したフィッシングメールという一般的な感染方法を用いている。しかし、このマルウェアのコードは一般的なものではなく、よく練られ、スマートにまとめられており、サイバーセキュリティ製品による検出を打ち負かすように設計されています。図1は、マルウェアの高レベルのフローを示している。このフローを生成するために使用されたエンジニアリング技術については、この記事で詳しく説明している。
GreyEnergy Stage 0 - 悪意のあるWord文書
この攻撃は、誰かが悪意のあるWord文書(SHA-1 177AF8F8D6F4952D13F88CDF1887CB7220A645)を電子メールの受信トレイで受け取ったときに始まる。
この文書はウクライナ語で書かれており、一見すると非常に怪しげだ。画像があるだけでなく、ページ上部にはマクロの存在に関連するセキュリティ警告がはっきりと表示されている。
下にスクロールすると、読者には偽の対話型フォームが表示される。この時点で、読者にはページ上部のセキュリティ警告が表示され続けるが、マクロを有効にするよう促す赤いテキストも表示される。
これは、人を騙して悪質なコードを実行させようとする明らかな試みである。
では、この文書がどのように機能するかを理解するために、テクニカル分析に飛び込んでみよう。
ドキュメントが開かれると、生成されたすべてのネットワーク・トラフィックをキャプチャするために、まずFakeNet-NGを起動する。文書が開かれると、リモート画像を読み込もうとする。これはマクロを有効にする前にも起こる。
実際、マクロは無効化され、コードは実行できない。この動作の最も明白な目的は、成功の最小指標として、何人のユーザーがドキュメントを開いたかを追跡することです。
このコードは、悪意のあるドキュメントによって自動的に実行されるHTTP GETリクエストである。
さて、本当の悪質なコードに移る時だ。ledumpという素晴らしいツールを使えば、以下のように簡単に解凍・抽出することができる:
(コードの重要な部分に焦点を当てるため、出力の一部は削除されている)
ユーザーが「コンテンツを有効にする」ボタンをクリックすると、関数 Document_Open()が自動的に実行される。この関数はTest()関数を呼び出し、悪意のあるコードを含むHashCheck()を呼び出します。
HashCheck()関数は、ほとんどの悪意のあるマクロに見られる一般的なダウンローダーである。この関数の主な目的は、遠隔地からマルウェアのコンポーネントをダウンロードし、システム内に保存し、最後に実行することです。
攻撃者はBase64エンコーディングを使って文字列を難読化しようとしたが、このエンコーディング方式は簡単に逆変換できる。主な目的は、文字列を保護することではなく、サイバーセキュリティ製品によって実行されるパターンベースの検出を回避することであった。次のコードスナップは、ダウンローダーがデコードした文字列を示している:
このマクロはリモートホストに接続する。http://pbank[.]co[.]UA/favicon[.]icoは、システム内に永続的なバックドアを埋め込むように設計されたパックされたドロッパーをダウンロードする。
ドロッパーとバックドア両方の実行ファイルはパッカー自体に含まれており、カスタムアルゴリズムで暗号化され、LZWの変種で圧縮されている。
パッカーがどのように機能するのか、分析を続けよう。
グレイエナジー ステージ1 - パッカー
Word文書によってダウンロードされたパッカー(SHA-1 51309371673acd310f327a10476f707eb914e255)は、2012-01-17 03:24:07にコンパイルされたC++ 32ビットWindows実行ファイルです(PEヘッダに従って)。
この実行ファイルは署名されておらず、既知のパッカーを使って保護されているわけでもないが、コード中に大量のアンチ解析テクニックが散りばめられている。PEヘッダーとセクションには、異常やパックされたコードを示すものは含まれていない。
パッカーとは何か?パッカーとは、実行ファイルの中に別の実行ファイルを暗号化・圧縮し、様々なアンチ・アナライズ・テクニックを実装することで、調査や理解を非常に困難にするものです。 パッカーは、個人や企業の知的財産であるコードを保護するために合法的に使用されます。しかしこの場合、パッカーはマルウェアを隠すために脅威行為者によって使用されます。パッカーは、セキュリティ・アナリストが真の悪意のあるコードを特定することを困難にするために、多くのテクニックを使用します。
パッカーの見分け方は?通常、パッカーには次のような特徴と能力がある。それは
- オリジナルの実行ファイルをメモリにアンパックする
- オリジナルの実行ファイルのインポートを解決する
- バイナリの再配置
- 元のエントリーポイントに実行を移す
- 輸入品が少ない
- 特定のパッカーセクションを含む(UPX0など)
- 異常断面のサイズ
- 主にアンチ・アナライザーのテクニックを使う:
- アンチデバッギング
- アンチVM
- ジャンクコード
- もっともっと
実行ファイルがパッカーであることを示す特徴を理解するために、分析を深めていこう。
オーバーレイ・データ
ファイルをよく観察してみると、実行ファイルは自身の末尾(オーバーレイ)に、生のオフセット0xD800(SHA-1オーバーレイデータBD67AE6C9C4C5DEE10FD8E88913427BF42D0580)から始まる暗号化されたデータを持っていることに気づいた。
分析中に確認された最初の仮定は、ファイルの末尾に追加されたデータは、実行時に何らかの方法で復号化される追加コンポーネントであるということである。いくつかのWindowsインストーラーは、システム内にインストールされるデータを保存するためにオーバーレイを使用しているため、これは必ずしも悪意のある指標ではない。しかし、パズルの一部である可能性はある。
静的解析
IDA Proでドロッパーを開くと、実行ファイルがジャンクコード、アンチフォレンジック、オーバーラップ命令、JMPの大量使用など、いくつかのアンチ解析テクニックを使ってコンパイルされていることがすぐにわかる。これは、解析されたファイルがパッカーであるか、または一般的に開発者が保護したいコードであることを示す指標となる可能性があります。
とはいえ、内部に悪意のあるコードがあるという証拠としてはまだ不十分だ。
たとえ静的解析のアプローチが可能だとしても、私は調査をスピードアップするために動的解析のアプローチに重点を置くことにした。
ここから先は、優れたx64dbgを使ってマルウェアをデバッグすることで情報を得た。
ハードコードされたインポート
パッカーによって呼び出される最も重要なWinAPIは、PEインポートテーブルには含まれていない。API名はmov命令を使ってスタックにプッシュされる。
API名がメモリにロードされると、マルウェアは関連するコードが実際にメモリ上のどこにあるかを見つける必要がある。必要なライブラリは既にプロセスアドレス空間にロードされているため、マルウェアはPEヘッダーを解析してエクスポートテーブルにアクセスし、その後に正しいAPIアドレスを見つける。
この方法で、以下のAPIのアドレスが特定される:
- ファイル作成W
- ファイルサイズ
- ローカルアロック
- リードファイル
- クローズハンドル
このマルウェアは、文字列がメモリにロードされた後、すべての文字列をゼロで上書きするという基本的なアンチ・フォレンジック技術を実装している。
アルゴリズムは単純で、文字列の全バイトをwipe関数が提供するバイト(解析したサンプルでは0x00に固定)で上書きする。
これまでのところ、バイナリーがパッカーであることを強く示唆する複数の指標がある:
- 明らかに暗号化されたオーバーレイ
- アンチ・アナリシス・テクニック
- PEヘッダーの解析により手動で解決されるAPI
- コード内にハードコードされた文字列は、使用後に0x00で上書きされる。
オーバーレイデータへのアクセス
分析の冒頭で示唆したように、マルウェアはファイルの最後に追加されたデータにアクセスしようとしている。そのために、PEヘッダを解析する目的でメモリ内に自身をコピーする。先に特定した5つのAPIを使用して、オーバーレイが開始する正確なオフセットを特定します。
マルウェアが最初に行うべきことは、オープンされたファイルへのハンドルを返すCreateFileWを使って自分自身にアクセスすることである。
次に必要なのは、実行ファイルの正確なサイズであり、メモリに割り当てる容量を知ることである。GetFileSizeというAPIを使って、先に取得したファイルのサイズ・パラメーターを渡す。
渡される2番目のパラメータ0x00は、ファイル・サイズの上位ダブルワードが返される変数へのポインタである。この場合、アプリケーションは上位ダブルワードを必要としないので、NULLに設定されている。
これでマルウェアは、ディスク上の自分自身へのハンドルと、実行ファイルの正確なサイズをバイト単位で手に入れたので、自分自身のためにメモリ内の領域を確保する準備ができた。
現時点では、オーバーレイへのアクセスや、コード全体に広く使われているアンチ・アナリシス技術から、我々が見ているのはパッカーであるという強い指標がある。 しかし、オーバーレイにアクセスするインストーラ・スタブのようなものを見ている可能性もある。
パラメータLMEM_ZEROINIT (0x40)がコール時に使用されるためである。この関数は、割り当てられたメモリのアドレスをレジスタ EAX に返します。
この時点で、疑惑のあるパッカーは、自分自身を格納するメモリ上のアドレスを持っている。次のステップは、ディスクからファイルを読み取り、割り当てられたメモリ領域に格納することである。そのためには、以下の重要な情報が関係する:
- 0xC8 → 読み込むファイルへのハンドル
- 0x00526E68 → 割り当てられたメモリのアドレス
- 0x1D000 → ファイルのサイズ(読み込むデータ量)
マルウェアが実行する最後のステップは、API CloseHandleを使用してハンドルを閉じることである。ハンドル0xC8は解放され、もはや使用できなくなる。
さて、マルウェアは自分自身をメモリにコピーしたので、何らかの方法でオーバーレイデータを指す必要がある。そのために、PEヘッダーを手動で解析し、セクションを移動する。先に進む前に、PEファイルがどのように形成されるかを見てみよう。
下の画像の赤いボックスは、ヘッダー内に含まれるすべてのカテゴリーを示している。 それぞれ、実行ファイルのエントリーポイント、呼び出されたAPI、コンパイルのタイムスタンプ、ファイル内のデータの構造など、特定の有用な情報を記述するフィールドをいくつか含んでいます。
PEヘッダーの最後の部分はセクションヘッダーで、ファイルのセクションがどのように構成されているかを、そのサイズやオフセットも含めて記述する。
.rsrcというセクションを表す最後のエントリにアクセスすると、オフセットの開始点とセクションのサイズを抽出することができる。この情報を知ることで、セクションが終了する正確なアドレスを計算することができる:
- 0xD600 → セクションのある生アドレス
- 0x200 → セクションの生サイズ
画像の下部には、一般的なパディング・テキストPADDINGXXで終わるセクションが表示されている。
0xD600 + 0x200 = 0xD800という単純な足し算をすることで、ファイルの終わりと追加されたデータの始まりを特定することができる。
16進エディターを使って、そのオフセットに何があるかを調べてみよう:
あった!解析の冒頭で気づいた疑わしいオーバーレイデータは、.rsrc セクションの終わりから正確に始まっている。この戦略を使って、マルウェアはPEヘッダーを解析し、すべてのセクションを繰り返し、最後のセクションで追加を実行します。それが終わると、正しいオーバーレイオフセットを取得します。
そのオフセットから始めて、マルウェアは40バイトを読み込み、以下の小さなアルゴリズム(Pythonで再実装)を使って256バイトの配列を初期化する:
初期化された配列は、保護されたオーバーレイデータを復号化するために必要な秘密鍵(以降、keymapと呼ぶ)であるため、復号化アルゴリズムによって必要とされる。
復号化関数は、出力バッファを引数として、キーマップを内部的に使用する。これは、復号化されたデータの格納場所とバッファの長さを指定する。
復号アルゴリズムは非常にシンプルで、以下のPythonコードで再実装されている:
出力バッファの先頭を見ると、0x4D5Aというシグネチャが存在するため、データに実行可能ファイルが含まれていることはすぐにわかる。しかしよく見ると、認識されたパターンの間にいくつかの予期せぬバイトがあり、データがまだ完全に再構築されていないことを示している。
通常、PEヘッダには、復号化されたバッファには存在しないゼロのシーケンスがいくつか含まれており、何らかの方法で圧縮されている可能性を示唆している。
10命令ほどで、復号化されたデータのオフセットをパラメータとする関数が現れたからだ。パラメータは関数のサイズを示し、新しいバッファ(以前に割り当て済み)へのポインタを含む。この関数の実行後、新しいバッファには有効なPEヘッダが含まれ、データが圧縮されたことが確認される。
次に、パッカーは非圧縮バッファを指定し、PEヘッダを解析し、すべてのセクションを繰り返し処理する。この手法は前のものとよく似ている。しかし、今回の目的は、追加されるデータの開始点を外科的に指定することである。
オーバーレイデータにアクセスすると、2つ目のPEヘッダが 含まれていることがわかる。このPEヘッダこそが 、被害者のシステムにインストールされるのを待っている本当の悪意のあるコンポーネント(バックドア)な のだ。
次のステップは、ドロッパーをファイルシステム内に格納することなく、メモリ内で実行することである。この目標を達成するために、バイナリは以下の手順を実行します:
- 新しいバッファは、API VirtualAllocを使ってパッカーの仮想アドレス空間に割り当てられる。そして、ドロッパーのすべてのセクションがその中にコピーされます。
- PEヘッダーに含まれるインポートはすべて、LoadLibraryとGetProcAddressというAPIを使って解決される。
- すべてのセクションのパーミッションは、API VirtualProtectを使用してPEヘッダに従って設定されます。
- ドロッパーバイナリは、.relocセクションに従って再配置されます。
すべてのステップが完了すると、ドロッパー実行ファイルはメモリに正しくロードされ、実行されるのを待ちます。これはバイナリがパッカーであることの最終確認であり、パッカーの主要な特徴をすべて満たしているからです。
パッカーは、ドロッパーのPEヘッダーからエントリーポイントアドレス(バイナリー内でコードがどこから始まるかを記述するために使用される)を抽出し、無条件命令JMPを使用してそこにジャンプする。これが達成されると、実行フローはパッカーのコードからドロッパーのコードに移行する。
実行フローがオフセット0x0040100に割り当てられたパッカーのコード・セクションを離れ、まったく別のオフセット0x0021964にジャンプするので、それに気づくのは簡単だ。この最後のオフセットはOSがVirtualAlloc APIを使って割り当てたものなので、実行されるたびに異なる可能性がある。
GreyEnergy Stage 2 - Dropper
ドロッパーは、被害者のシステム内に本物のマルウェアをドロップすることを目的とした、非常に小さなコード片です。ドロッパーのミッションの一部は、マルウェアを永続化することであり、最終的なシステムの再起動にも耐えられるようにすることです。幸いなことに、ドロッパーはパッカーのように解析から保護されていないため、ロジックの流れを追うのは簡単だ。
シングル・エグゼキューション
悪意のあるマルウェアは、おそらく一度だけ実行されるように開発されている。ドロッパーは、システム内で一意の名前を使用して命名されたミューテックスで別のプロセスが実行されているかどうかをチェックするからだ。この名前は、API GetCurrentHwProfileAを使用して動的に取得され、このAPIはミューテックスを開くパラメータとしてフィールドszHwProfileGuidを使用する。すでに存在する場合、プロセスはそれ自体を終了する。
文字列の暗号化
ドロッパーが使用する文字列はすべて暗号化され、通常すべての読み取り専用データを含む.rdataセクション内に保存されます。
文字列を復号化するアルゴリズムは単純なXOR命令である。しかしこの場合、すべての文字列は4バイトのXORキーを持っており、それは文字列自体の先頭で宣言される。分析したサンプルでは4バイトのキーを使用していますが、データ構造は8バイトまでのXORキーをサポートしているように見えます(下のスクリーンショットでは0x00が4回繰り返されています)。
文字列を暗号化するために選ばれたXORベースのアルゴリズムは破られやすいが、文字列抽出解析からは保護される。不審な文字列が平文で保存されていた場合、パターン・ベースのセキュリティ・システムによるアラームを引き起こす可能性がある。
マルウェアの投下
ドロッパーはWindowsツールrundll32.exeへのパスを動的に取得します。これは、悪意のあるコンポーネントがDLLファイルを実行しようとしていることを示す指標です。バックドアは、ランダムなGUIDと拡張子.dbを使用して、%APPDATA%/Microsoft/ディレクトリ内にドロップされます。ファイル拡張子を変更することは、被害者を騙してファイルが無害なものであると思わせる基本的なソーシャル・エンジニアリングの手法ですが、実際には悪意のある実行可能コードが含まれています。
永続性の設定
システムの再起動に耐えるため、ドロッパーは以下のコマンドを使用して、%APPDATA%にドロップされた悪意のあるファイルを指す、空白の名前%APPDATA%%MicrostWindosPorgrams\Start Menu .lnk(スペース10文字)を持つリンクファイルを作成します:
C:\Windows\SysWOW64\rundll32.exe {4591E270-719A-4B01-A63C-C5B75CF04830}.db,#1
ドロップされたバックドア{4591E270-719A-4B01-A63C-C5B75CF04830}.dbはDLLファイルなので、エクスポートされた関数を実行できるスタブが必要です。そのために、ドロッパーはシステムユーティリティrundll32.exeを使用して、DLLによってエクスポートされた関数#1を呼び出します。
インストールされたバックドアを実行する
最後に、ドロッパーは被害者のシステム内にインストールされた本物のマルウェアを実行する準備が整う。バックドアを実行するために使用されるコマンドは、リブートの生存を保証するために使用されるコマンドと同じです:
C:\Windows\SysWOW64\rundll32.exe {4591E270-719A-4B01-A63C-C5B75CF04830}.db,#1
バックドアがシステム内で実行されると、ドロッパーは感染の痕跡を一掃するために最後のアクションを実行します。API「ShellExecuteW」を使用して、システムのシェル内で以下のコマンドを実行します:
上記の文字列の中で最も重要な部分は、delコマンドであり、これまで説明した実行フローを開始したパッカーの実行ファイルを削除する。 pingコマンドはシステムのループバックインターフェースに4つのICMPパケットを送信し、パッカーがファイルシステムから削除されるという事実を隠すためのおとりであるようだ。
最後に呼ばれるAPIはExitProcessで、ドロッパーのコードがそのアドレス空間内で実行された後、パッカーの実行を終了します。
潜在的に危険なステルス感染
私の分析を終え、GreyEnergyパッカーがリバースエンジニアリングプロセスを遅らせる素晴らしい仕事をしていることは明らかである。使用されている技術は新しいものではないが、使用されているツールと戦術の両方が賢く選択されている。
例えば、この脅威者は、悪意のあるペイロードを保護するのに十分な難易度のカスタムアルゴリズムを実装することを選択しました。さらに、メモリ内の文字列を消去するなどのアンチフォレンジック技術を幅広く使用することで、ステルス性を維持し、感染に気付かれないようにする攻撃者の試みを強調している。
GreyEnergy攻撃が感染後にどのように進行するかについては、以前の要約ブログを参照するか、最初の詳細なESETレポートを参照されたい。注目すべきは、GreyEnergy は産業制御システムに感染するモジュールを含んでいないため、スパイ活動のみに使用されているように見えることである。
しかし、ESETは、「GreyEnergyは、過去数年間ウクライナを恐怖に陥れてきた最も危険なAPTグループの1つの武器庫の重要な一部である」とレポートを締めくくっている。そのGreyEnergyは、将来的に重要なインフラに損害を与えることができるモジュールを含むように進化する可能性がある。
GreyEnergyをリバースエンジニアリングする私の仕事は、当社の新しいThreat Intelligence サービスを含むNozomi Networks 。これは、産業ネットワーク上のGreyEnergyまたはその亜種を識別するための高度な技術を使用しています。
グレイエナジーの分析を促進する無料ツール
この分析の直接的な結果として、私はGreyEnergy Unpackerを開発した。これは、ドロッパーとバックドアの両方を自動的に解凍し、ディスクに展開するPythonスクリプトで、Githubから自由に入手できます。このスクリプトを使用することで、ここで説明したリバースエンジニアリング作業を省くことができ、さらにGreyEnergy分析を容易にすることを目的としています。
2019年2月更新研究論文を発表
このブログの発表以来、私は上記のグレイエナジーのステージの追加分析を行った。私の最も深い調査はパッカーで行われ、私の包括的なリバースエンジニアリング分析は、以下で入手可能な研究論文で提供されている。
以下もリンクされている:
- パッカーが真の機能を隠すために使用するテクニックをまとめた、このトピックに関するさらなるブログ記事
- 2つのGreyEnergyツールを提供するGitHubリンクが更新されました。追加された新しいツールは GreyEnergy Yaraモジュールで、Yaraによって処理されるファイルがGreyEnergyパッカーかどうかを判断します。