FortiGuard Labs 脅威リサーチ

GoTrim:WordPress Webサイトにブルートフォース攻撃を仕掛けるGoベースのボットネット

投稿者 Eduardo Altares, Joie Salvio および Roy Tay | 2023年3月2日

FortiGuard Labsは先日、これまでに報告されていない、Goプログラミング言語(Golangとも呼ばれる)で記述されたCMS(コンテンツ管理システム)スキャナとブルートフォースプログラムを発見しました。フォーティネットがこのマルウェアを調査した理由は、これが複数のオンラインフォーラムで取り上げられ、侵害されたWordPressサイトにインストールされていると説明されているものの、一般公開された分析レポートがなかったからです。

  • 影響を受けるプラットフォーム: Linux
  • 影響を受けるユーザー:     すべての組織
  • 影響:             リモートの攻撃者による脆弱なシステムの乗っ取り
  • 深刻度:            クリティカル

Go言語のブルートフォースプログラムは、目新しいものではありません。たとえば、フォーティネットは2019年にStealthWorkerキャンペーンについて報告しています。今回の新しいブルートフォースプログラムは、我々がGotrimと名付けた新型キャンペーンの一部です。Goで書かれ、C2サーバーとやり取りするデータが「:::trim::」で区切られているため、そのように名付けました。

StealthWorkerと同様に、GoTrimもボットネットワークを利用して分散型ブルートフォース攻撃を実行します。我々が発見した最も古いサンプルは、2022年9月に出現したものです。このキャンペーンは現在も開発が続けられています。

本ブログでは、現在活動中のこのボットネットがWordPressとOpenCartをどのように使用し、Webサイトをスキャンして侵害するかを解説します。2022年9月から11月までに収集されたサンプルの違いについても、ブログの最後で取り上げます。

攻撃チェーン

図1:GoTrim攻撃チェーン

GoTrimは、ボットネットワークを使用して標的への分散型ブルートフォース攻撃を実行します。各ボットには一連の認証情報が送信され、それを使用して長大なリストに含まれている標的Webサイトへのログインが試行されます。ログインが成功すると、新たに侵害されたシステムにボットクライアントがインストールされます。ボットクライアントは、脅威アクターからの次のコマンドを待機します。こうしてボットネットワークが拡大していきます。

GoTrimはブルートフォースが成功した場合のみ、C2サーバーに認証情報を報告します。GoTrimでは、自己増殖したり他のマルウェアを展開したりするコードは確認されませんでした。ただし、GoTrimボットクライアントをダウンロードして実行するPHPスクリプトが見つかりました。脅威アクターは、漏洩した認証情報を何らかの方法で悪用してPHPスクリプトを配信し、システムをGoTrimに感染させるようです。

図2:PHPタウンローダーのスクリプト

通常、各スクリプトはハードコードされたURLからGoTrimマルウェアをダウンロードし、スクリプト自身と同じディレクトリ内のファイルに保存して実行します。トラックを隠すために、ダウンローダーのスクリプトとGoTrimブルートフォースプログラムは感染したシステムから削除されます。感染したシステムでマルウェアの永続性は維持されません。

静的分析

別途記載のない限り、この記事で説明する分析は、次のSHA-256ハッシュ値を持つサンプルに基づいています。
c33e50c3be111c1401037cb42a0596a123347d5700cee8c42b2bd30cdf6b3be3

GoTrimはGoバージョン1.18でビルドされています。すべてのGoアプリケーションと同様に、コードに使用されているすべてのサードパーティライブラリは、マルウェアと静的にリンクしています。そのため、実行可能バイナリのファイルサイズはかなり大きくなります。ただしこれには、外部ファイルに依存せずにマルウェアを正確に実行できるという利点があります。サイズ問題を解消するために、マルウェアはUPXを使用して6 MBから1.9 MBに圧縮されています。

Goを使用するもう一つの利点は、同じソースコードをクロスコンパイルして、他のアーキテクチャやオペレーティングシステムをサポートできることです。サンプルのソースコードパスを調べたところ、GoTrimの開発中にはWindowsが使用されていました。しかし、実環境では64-bit Linuxを標的にしたサンプルしか確認されていません。

C2通信

GoTrimは、次の2通りの方法でC2(コマンド&コントロール)サーバーと通信します。すなわちクライアントモードでは、HTTP POSTリクエストをC2サーバーに送信します。サーバーモードではHTTPサーバーを起動し、POSTリクエストの着信を待ち受けます。C2とやり取りされるすべてのデータはAES-GCM(Advanced Encryption Standard in Galois Counter Mode)で暗号化されます。暗号化には、マルウェアバイナリに埋め込まれたパスフレーズから生成した鍵が使用されます。

感染したマルウェアがインターネットに直接接続される場合、つまり、被害者の送信 / ローカルIPアドレスがプライベートではない場合、GoTrimはデフォルトによってサーバーモードで動作します。それ以外の場合は、クライアントモードに切り替わります。

GoTrimが実行されると、感染したマシンに固有のID(ボットID)を表すMD5ハッシュが生成されます。このハッシュは次の文字列で構成され、それぞれの情報は「:」で区切られています。

VICTIM_EXTERNAL_IP:HTTP_SERVER_PORT:1:OUTBOUND_IP:AES_PASSPHRASE

  • VICTIM_EXTERNAL_IP:マシンの外部 / パブリック IP。
  • HTTP_SERVER_PORT:HTTPサーバーポート。これは、サーバーモードのときにHTTPサーバーに対してランダムに生成される4000~8000までの数値です。クライアントモードでは常に0です。
  • マルウェア初期化フラグ:ボットIDが計算されるまでに、必ず1に設定されます。
  • OUTBOUND_IP:被害者マシンの送信 / ローカルIPアドレス。
  • AES_PASSPHRASE:各サンプルに埋め込まれたハードコード文字列。マルウェアは、あとでこの文字列のSHA-256ハッシュをAES-GCM鍵として使用して、C2サーバーとの通信を暗号化します。これと同じAESパスフレーズは、我々が観測したすべてのサンプルで共通しています。

ボットIDの生成後、GoTrimは非同期のgoroutine(マルチスレッドに類似)を作成します。このルーチンは、クライアントモードとサーバーモードのいずれにおいても、C2サーバーにビーコンリクエストを送信します。

C2リクエストのURLはバージョンによって異なります。これについては後述します。今回のサンプルでは、ビーコンリクエストのURLは「/selects?dram=1」です。

図3に示すように、このビーコンリクエストに被害者とボットの情報が格納されてC2サーバーに送信されます。

図3:C2サーバーに送信されたデータのスクリーンショット

ビーコンリクエストで送信されるフィールドには、以下のような興味深いものがあります。

1. ボットID:ボット固有のID
2. 外部IP:被害者マシンのパブリックIPアドレス
3. HTTPサーバーポート:ランダムに生成されるHTTPサーバーのポート番号(クライアントモードでは0)
4. マルウェア初期化フラグ:このリクエストが作成されるまでに、必ず1に設定されます。
5. 送信IP:被害者マシンのローカルIPアドレス
6. ステータスメッセージ:後続のビーコンリクエストでは、「GOOD」メッセージは別の文字列に置換されます。この文字列により、実行中のCMS検知またはブルートフォースタスクのステータスが通知されます。
7. ステータスフラグ:C2サーバーからマルウェアに現在割り当てられている処理タスクがあるかどうかと、それらのタスクのIDを示します。
8. MD5チェックサム:上記のリクエストの一部とハードコードされたAESパスフレーズを使用して生成されます。この値は、メッセージの整合性チェックサムとして使用されます。

各フィールドが:::trim:::文字列で結合されているため、それをこのキャンペーンの名前に採用しました。データはこのあと、AES-256-GCM鍵、すなわち前述したパスフレーズのSHA-256ハッシュを使用して暗号化されます。

サーバーは通常、「OK」、「404 page not found」、または「BC」で応答します。これらはすべて、同じAES-GCM鍵で暗号化されています。「BC」を受信した場合、GoTrimはボットIDを生成し、サーバーモードからクライアントモードに切り替わります。

最初のビーコンリクエストは、新しいボット(被害者)をボットネットワークに登録することを目的としています。

各ビーコンリクエストのあと、GoTrimは次のリクエストを送信するまで数秒~数分間スリープ状態になります。この時間は、C2サーバーの応答と、マルウェアがC2から割り当てられたタスクを実行中であるかどうかによって異なります。マルウェアは定期的にビーコンリクエストを実行し、ブルートフォースのセクションで説明したように、ボットのステータスに関する更新情報(有効な認証情報など)をC2サーバーに伝えます。ビーコンリクエストを100回試行してもC2サーバーから有効な応答が得られない場合、GoTrimは処理を終了します。

ビーコンリクエストが非同期で送信されてC2サーバーのステータス情報が更新されている間、GoTrimはコマンドを受信するためC2サーバーにリクエストを送信するか(クライアントモード)、あるいはHTTPサーバーを起動してタスクリクエストの着信を待ち受けます(サーバーモード)。

クライアントモード

クライアントモードでは、マルウェアはC2サーバーからコマンドを受信するために、POSTリクエストを「/selects?bilert=1」に送信します。

C2サーバーは、同じAES-GCM鍵で暗号化されたコマンドで応答します。復号されたコマンドの例を図4に示します。

図4:コマンドとオプションが格納された応答のスクリーンショット

:::trim:::」文字列でデータを区切ると、以下の7つのフィールドを確認できます。

1. MD5チェックサム:メッセージの整合性をチェックするために使用されます(例:83217f8b39dccc2f9f2a0157f0236c4f)。
2. コマンドID:現在のタスクのコマンドを示します。
3. 同時実行レベル:各タスクに対してgoroutineを実行する回数を指定します。
4. コマンドオプション:コマンドのオプションが7E 6A 71 6D 70 C2 A9(~jqmp©)バイトで区切られて格納されています。解釈はコマンドによって異なります。

a. ターゲットリスト:これはGZIPで圧縮されたデータで、解凍すると、ログインを試行する標的となるドメインのリストが格納されています。
b. コマンドオプション1(マスキング済み)認証コマンドのユーザー名が格納されます。各ドメインに同じユーザー名を使用する代わりに、C2サーバーが一連のバイト(C2 A9 64など)を指定して、ドメインをユーザー名として使用することができます。
c. コマンドオプション2(マスキング済み)認証コマンドのパスワードが格納されます。
d. コマンドオプション3:WordPress認証用の未知のオプション。
e. コマンドオプション4:WordPress認証でPOSTリクエストまたはXML-RPCを使用して認証情報を送信するためのオプション。

5.内部値:マルウェアそのものでは使用されていない数値(42255など)。現在のコマンドに対応する内部タスクIDを示していると思われます。  

マルウェアは以下のコマンドをサポートしています。

  • 1:送信された認証情報をWordPressドメインに照らして検証します。
  • 2:送信された認証情報をJoomla!ドメインに照らして検証します(現時点では未実装)。
  • 3:送信された認証情報をOpenCartドメインに照らして検証します。
  • 4:送信された認証情報をData Life Engineドメインに照らして検証します(現時点では未実装)。
  • 10:ドメイン上のWordPress、Joomla!、OpenCart、またはData Life Engine CMSのインストールを検知します。
  • 11:マルウェアを終了します。

フォーティネットは、1つのWordPress認証コマンドで最大30,000のドメインがターゲットリストに含まれることを確認しました。さらに、リスト内のすべてのドメインを試すために、認証コマンドはパスワードを1つしか指定しないことも判明しました。以上のように、分散型ブルートフォース攻撃は、感染したマシンのネットワークでさまざまなドメインと認証情報を試すコマンドによって実行されると考えられます。

コマンドの処理を完了したマルウェアは、しばらくスリープ状態になったのち、C2サーバーから新しいタスクを受信するために別のPOSTリクエストを送信します。

サーバーモード

サーバーモードでは、GoTrimは4000~7999までのランダムなポートでサーバーを起動し、脅威アクターから送信されるPOSTリクエストに応答します。脅威アクターは、サーバーモードの方がボットとの通信をより迅速に行えます。たとえば、ボットのHTTPサーバーで処理される特定のURLにPOSTリクエストを送信するだけで、次のビーコンリクエストを待たずにボットのステータスを確認できます。

マシンにコマンドを発行するには、POSTリクエストを「/BOT_ID?lert=1」に送信し、その本文にはAES-256-GCMで暗号化されたコマンドデータを含めます。このデータは、クライアントがコマンドをリクエストしたときにC2サーバーから返される応答(図4)とほぼ同じです。サーバーモードは、クライアントモードと同じコマンドをサポートしています。

パラメータ「/BOT_ID?intval=1」を指定してリクエストを送信すると、現在動作しているタスクのステータスと、割り当てられたタスクが完了したかどうかを表示することもできます。

CPU使用率が一定のレベル(現在のタスクに使用されている同時ワーカーの数に応じて75%または90%)を下回ると、各ドメインを処理するために個別のgoroutineが生成されます。

ボットネットコマンド

CMSの検知

GoTrimは、標的のWebサイトで4つのCMS(WordPress、Joomla!、OpenCart、DataLife Engine)のいずれかが使用されているかどうかを確認しようとします。それには、Webページのコンテンツで特定の文字列をチェックします。

興味深いことに、GoTrimは自己ホスト型のWordPress Webサイトだけを標的にしており、そのためにReferer HTTPヘッダーで「wordpress.com」をチェックしています。通常、wordpress.comのようなマネージドWordPressホスティングプロバイダーは、自己ホスト型のWordPress Webサイトよりも強力なセキュリティ対策を実装してブルートフォース攻撃を監視、検知、ブロックしているため、発見されるリスクに見合うほど攻撃の成功率が高くありません。

インストールされたCMSを判断するには、以下の文字列が使用されます。

WordPress

  • “wp-content/plugins/” and “wp-content/themes/”
  • “wp-content/uploads/”
  • “wp-includes/js/”
  • “/xmlrpc.php”

Joomla!

  • 「generator" content=\"Joomla!」および「/templates/」
  • 「/media/system/js/mootools.js」および「/media/system/js/caption.js」
  • 「index.php?option=com_」
  • 「/modules/mod_」
  • 「/components/com_」

OpenCart

  • 「/index.php?route=common」および「/index.php?route=information」
  • 「image/cache/catalog」
  • 「catalog/view/theme/」
  • 「catalog/view/javascript」

DataLife Engine

  • 「DataLife Engine」および「~engine/classes/js/dle_js.js」
  • 「index.php?do=search&」
  • 「var dle_」

GoTrimは上記の4つのCMSを使用しているWebサイトを検知できますが、現時点ではWordPressとOpenCartのWebサイトに対する認証のみをサポートしています。これは、このボットネットが現在も開発中であることを示唆しています。

WordPress認証情報の検証

GoTrimは、C2サーバーから入手するユーザー名のほかにも、さらに多くのユーザー名を収集するために、GETリクエストを「/wp-json/wp/v2/users」に送信します。

そのあと、「/wp-login.php」にPOSTリクエストを送信し、C2コマンドで入手したユーザー名のリストとパスワードを使用して、WordPress Webサイトへのログインを試みます。ログインするためのPOSTリクエストの例を図5に示します。

図5:WordPress認証リクエスト

このリクエストにより、ログインが成功するとWordPress Webサイトの管理者ページ(/wp-admin)へのリダイレクトが実行されます。ログインとリダイレクトが成功したことを確認するため、GoTrimは応答に「id=\"adminmenumain\」が含まれているかどうか調べます。

C2サーバーは、WordPressのXML-RPC機能を介して認証の実行を指示することもできます。XML-RPCは、遠隔地からXMLを使用してWordPressをプログラムで操作できる機能です。Webサーバーのバックエンドと直接通信することで、通常であればWebサイトのページへのアクセスによって起動するcaptchaなどのアンチボットメカニズムを回避することができます。

ログインの成功後、以下の情報(「|」で区切られます)が更新されてグローバルステータスメッセージに挿入され、次のリクエストとともにC2サーバーに送信されるか(クライアントモード)、着信リクエストへの応答として送信されます(サーバーモード)。

  • ターゲットURL
  • ユーザー名
  • パスワード
  • コマンドID(WordPressでは1、OpenCartでは3、など)
  • ブルートフォースのステータス(成功した場合は「0GOOD」)

OpenCart認証情報の検証

GoTrimは、オープンソースのeコマースプラットフォームであるOpenCartが動作するWebサイトにもブルートフォースを仕掛けることができます。

まず、標的の「/admin/index.php」にGETリクエストを送信し、ログインリクエストに必要な認証関連のトークンとヘッダーを収集します。次に、同じURLに対し、ユーザー名とパスワードが格納されたエンコード形式のデータとともにPOSTリクエストを送信し、実際に認証を行います。

ログインリクエストが成功したことを確認するため、WebサイトからOpenCartのユーザートークンが返されたかどうかをチェックします。そのために、「/dashboard&user_token=」を検索し、受信したデータの「redirect」の値が空でないことを確かめます。

有効な認証応答は次のようになります。

{"redirect":"https://example.com/opencart/admin/index.php?route=common/dashboard&user_token=USER_TOKEN_HASH"}

ログインが成功するとグローバルステータスメッセージが更新され、WordPressへのブルートフォース攻撃が可能になります。

アンチボットチェック

GoTrimは、WebホスティングプロバイダーやCDNで使用されているアンチボット技術(Cloudflare、SiteGroundなど)を察知し、単純なチェック機能を回避することができます。

また、64bit Windows上のMozilla Firefoxから送信される正規のリクエストを模倣しようとします。そのために、このブラウザから送信されるのと同じHTTPヘッダーを使用し、同じコンテンツエンコードアルゴリズム(gzip、deflate、Brotliなど)をサポートしています。

WordPress Webサイトでは、以下のCAPTCHAプラグインがインストールされているかどうかも確認します。

  • Google reCAPTCHA
  • reCAPTCHA by BestWebSoft
  • WP Limit Login Attempts
  • Shield Security Captcha
  • All in One Security (AIOS) Captcha
  • JetPack Captcha
  • Captcha by BestWebSoft

GoTrimには、上記プラグインのうちいくつかのCAPTCHAを回避するコードが含まれています。ただし、その回避技術が機能するかどうかは検証の必要があります。我々は、GoTrimはGoogle、WP Limit Login Attempts、およびShield SecurityのCAPTCHAを回避できないと結論付けました。

通常、セキュリティプラグインを回避できない場合、GoTrimはそれをC2サーバーに報告します。そのためには、ログインが成功したときに送信するデータと同様の情報で、グローバルステータスメッセージを更新します。ただし、ブルートフォースステータスには「3GOOD」を使用します。これは、認証情報の検証がスキップされたことを示します。

ページコンテンツに「1gb.ru」文字列が含まれたWebサイトを見つけた場合も、GoTrimはブルートフォースステータスとして「3GOOD」を送信します。これは、そのプロバイダーがホストしているWebサイトを標的にしないという判断のようですが、その意図はいまだ不明です。

キャンペーンの更新

私たちはこのキャンペーンに関連する他のサンプルを探すうちに、C2サーバー89[.]208[.]107[.]12で、「/selects?param=1」と「/selects?walert=1」という異なるURLを使用した、2022年9月以降のPHPスクリプトとバイナリを発見しました(図6)。PHP/GoTrim!tr.dldrとして検知されたこのPHPスクリプトは、同じインストール方法を使用しており、ダウンロードURLだけが収集されたサンプルによって異なります。

図6:異なるC2サーバーを使用する2022年9月以降のバージョンのコードスニペット

2022年11月に出現したバイナリのバージョンでも、HTTP POSTのURLが更新されていました(図7)。ビーコンリクエストのURLは「/selects?dram=1」から「/route?index=1」に、コマンドリクエストのURLは「/selects?bilert=1」から「/route?alert=1」にそれぞれ変更されています。データ伝送に使用される暗号化アルゴリズムと鍵に変更はありません。

図7:GoTrimの2つのバージョンからWiresharkでキャプチャしたPOSTリクエスト

結論

このマルウェアは現在開発中であるとはいえ、十分に機能するWordPressブルートフォースプログラムとアンチボット回避技術を兼ね備えていることから、警戒すべき脅威であるといえます。特に、WordPress CMSは絶大な人気があり、数百万のWebサイトで世界的に利用されていることを考えればなおさらです。

ブルートフォースキャンペーンが危険な理由は、それがサーバーの侵害やマルウェアの配信につながるからです。このリスクを軽減するには、ユーザーアカウント(特に管理者アカウント)に強力なパスワードを使用するよう、Webサイト管理者が徹底する必要があります。CMSソフトウェアとそれに関連するプラグインを最新の状態に保つことでも、パッチが適用されていない脆弱性を悪用したマルウェア感染のリスクを減らすことができます。

FortiGuard Labsは、今後もGoTrimの進捗を監視していきます。

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

FortiGuardアンチウイルスサービスは、この脅威を ELF/GoTrim!trおよびPHP/GoTrim!tr.dldrとして検知しブロックします。

FortiGuardアンチウイルスサービスはFortiGateFortiMailFortiClientFortiEDRによってサポートされます。これらの各ソリューションには、Fortinetアンチウイルスエンジンが含まれています。最新のアンチウイルスアップデートをお使いのお客様は、脅威から保護されています。

FortiGuard Labsは、GoTrim C2の活動に対するGoTrim.Botnet IPSシグネチャを提供しています。

FortiGuard Webフィルタリングサービスは、このレポートで取り上げたC2サーバーとダウンロードURLをブロックします。

FortiGuard IPレピュテーションおよびアンチボットネットセキュリティサービスは、フォーティネット分散ネットワークから不正な送信元のIPデータを集約し、攻撃を事前にブロックします。この分散ネットワークでは、脅威センサー、CERT、MITER、協力関係にある他社、その他のグローバルソースが連携し、悪意ある送信元に関する最新の脅威インテリジェンスを提供しています。

IOC(Indicators of Compromise:侵害指標)

ファイル

646ea89512e15fce61079d8f82302df5742e8e6e6c672a3726496281ad9bfd8a

4b6d8590a2db42eda26d017a119287698c5b0ed91dd54222893f7164e40cb508

c33e50c3be111c1401037cb42a0596a123347d5700cee8c42b2bd30cdf6b3be3

71453640ebf7cf8c640429a605ffbf56dfc91124c4a35c2ca6e5ac0223f77532

3188cbe5b60ed7c22c0ace143681b1c18f0e06658a314bdc4c7c4b8f77394729

80fba2dcc7ea2e8ded32e8f6c145cf011ceb821e57fee383c02d4c5eaf8bbe00

De85f1916d6102fcbaceb9cef988fca211a9ea74599bf5c97a92039ccf2da5f7

2a0397adb55436efa86d8569f78af0934b61f5b430fa00b49aa20a4994b73f4b

ダウンロードURL

hxxp://77[.]73[.]133[.]99/taka

hxxp://77[.]73[.]133[.]99/trester

hxxp://77[.]73[.]133[.]99/pause

C2

hxxp://77[.]73[.]133[.]99

hxxp://77[.]73[.]133[.]99/selects?dram=1

hxxp://77[.]73[.]133[.]99/selects?bilert=1

hxxp://77[.]73[.]133[.]99/route?index=1

hxxp://77[.]73[.]133[.]99/route?alert=1

hxxp://89[.]208[.]107[.]12

hxxp://89[.]208[.]107[.]12/selects?param=1

hxxp://89[.]208[.]107[.]12/selects?walert=1