This post is also available in: English (英語)
概要
署名付きアプリケーションの動作に影響を与える攻撃(サプライチェーン攻撃、ダイナミックリンクライブラリ(DLL)のハイジャック、エクスプロイト、悪意のあるスレッドインジェクションなど)を的確に検出できるよう、私たちはグローバルな統計的アノマリ(異常)を検出できる分析検出器群を考案しました。
この新しい検出器を使ったところ、産業スパイ攻撃と思われる活動がみつかりました。この活動を観測すると、それまで知られていなかったあるマルウェアが、特別な細工をしたDLLハイジャック攻撃を仕掛けている様子が確認されました。このサンプルに確認された複数のアーティファクトをもとに、私たちはこのマルウェアに「Popping Eagle」という名前をつけました。このほかGoで書かれた第2段階の悪意のあるツール(「Going Eagle」と命名)も確認されています。この特定の事例では攻撃者がこの後、複数のネットワークスキャンやラテラルムーブ手順を実行した様子も確認されています。
今回の新たな分析検出器群によるPopping Eagle発見は、以下の各ポイントの重要性を強調するものといえます。
- これらの分析統計手法は、従来見逃していたはずのマルウェアを特定可能
- これらの分析検出器群は、検出回避をねらうマルウェアが署名付きプロセスに自身をロードしても、難読化の試みによってそれを発見可能
本稿は、脅威ハンティングの方法を論じ、攻撃に使用されたツールを分析し、被害環境で攻撃者が行ったアクションを詳細に解説します。
パロアルトネットワークスのお客様は、Cortex XDRと、次世代ファイアウォールのクラウド配信型セキュリティサービスWildFireによって、この種の攻撃から保護されています。詳しくは「結論」のセクションをご覧ください。
本稿で解説する主なマルウェア | Popping Eagle, Going Eagle |
目次
署名付きアプリケーションにおける統計的アノマリ(異常)のハンティング
背景
実装
Popping Eagleの発見
Popping Eagleの第1段階の分析
ロード方法: DLLプロキシ
uxtheme.dllサンプルの分析
Going Eagleの第2段階の分析
ClickRuntime-amd86.dllの分析
ラテラルムーブ
第2段階のタイムライン
関連IoCの検索
仮説
脅威ハンティングと検索の方法論
結論
付録
IoC
ハンティング用Yaraルール
署名付きアプリケーションにおける統計的アノマリ(異常)のハンティング
背景
ここ数年はサプライチェーン攻撃が激増しており、たとえばSolarStorm、NotPetya、Kaseya、KeRangerなどがその例としてあげられます。
これまでの事例からサプライチェーン攻撃を行う脅威アクターたちは、攻撃の第1段階では多数の組織を対象にコードを実行するものの、攻撃の第2段階では少数の価値の高い標的に対象を絞る傾向が強いことがわかっています。
私たちはCortex XDRの大規模なデータセットを活かしてアプリケーションの「正常な」振る舞いのグローバルベースラインを構築し、「異常な」振る舞い(アノマリ)を探索しました。
これらのアノマリを特定すれば、たとえばサプライチェーン攻撃やDLLサイドローディング、悪意のあるスレッドインジェクションなどのさまざまな種類のテクニック(技術)や、正規署名付きアプリケーションの動作を逸脱させるような攻撃を検出することができます。
実装
アプリケーションはそれぞれに実行可能なアクションが異なりますが、複数の環境で共通したアクションは良性の可能性が高いので、そうしたアクションをうまくつかってアプリケーションごとのグローバルベースラインを構築します。
また同じアプリケーションでも組織ごとにアクションが異なる場合があります。たとえば自組織のドメインへの接続がその例です。これを踏まえ、組織ごとやアプリケーションごとのローカルベースラインも構築します。
これらのベースラインをもとに、各アプリケーションのアクションを比較し、異常な活動があればフラグを立てます。
疑わしいケースを集めたら、それらをさらに分析し、それらが実際に攻撃なのかどうかを検証します。
Popping Eagleの発見
既知の悪意のあるIoC(indicators of compromise)を含むケースをフィルタリングした結果、次のようなケースに行き当たりました。
Barco N.V.による署名の付いたアプリケーションclicksharelauncher.exeは、数百の異なる環境で確認されていました。このため、その振る舞いに関して十分なベースラインがあることが示唆されるものでしたが、ある1つの環境でだけ、特異なドメインの解決を行っていました。さらにそのアプリケーションが接続したドメインdnszonetransfer[.]comはその環境でしか確認されず、ほかに何千台もあるエージェントのなかで、ある特定の3台のエージェントでしか確認されませんでした。
調査の過程で、ホストに残された2種類のツールが見つかり、私たちはこれに興味をそそられました。ただハッシュが未知であるというだけでなく、調査中に見つかったほかのすべてのIoC(侵害指標)から見ても未知のものだったからです(詳しくは「関連IoCの検索」を参照)。
Popping Eagleの第1段階の分析
ロード方法: DLLプロキシ
clicksharelauncher.exeの因果チェーン(causality chain)を調べてみると、まずuxtheme.dllという名前の実行ファイルと同じディレクトリから未署名DLLを読み込んで、その後dnszonetransfer[.]comドメインに接続していることがわかりました。
このDLL名は通常%windir%\SysWOW64\UxTheme.dllに存在する既知のMicrosoftの署名付きDLLに属するもので、このDLL名はclicksharelauncher.exeのインポートテーブルにも含まれています。
これはDLL Search Order Hijacking (DLL検索順序のハイジャック)の典型例です。clicksharelauncher.exeは、%windir%\SysWOW64\の検索より先にカレントディレクトリからuxtheme.dllをロードしようとし、MicrosoftのDLLではなく攻撃者のDLLをロードしてしまうのです。
未署名uxtheme.dllのエクスポートテーブルをオリジナルのものと比較すると同じ関数がエクスポートされており、それに加えてpopoという関数がエクスポートされています。
uxtheme.dllサンプルの分析
この実行ファイルは32ビットDLLとしてC++で作成されています。DLLのメタデータにあるオリジナルのコンパイル名はCoL_Final_Lib.dllで、そのコンパイルタイムスタンプには私たちの初認日と同じ日が記録されています。私たちが確認した3台のホストのSHA256ハッシュがそれぞれ異なっていたことと合わせると、これは「その場で」コンパイルされたことを示しているのかもしれません。
ローダーとしてBarcoのソフトウェアが使われていることも、これがこの被害環境に合わせて作られたサンプルであることを示唆しています。Barcoのソフトウェアをローダーとして使うのはかなりユニークだからです。
エントリポイントやエクスポート内容のメモリ位置を確認するとほとんどが文字列で、実際の関数は1つだけです。このことから、このDLLがこれら関数の実ロジックは実装しておらず、プロキシされたDLLを巧妙に模倣するためだけに存在していることが示唆されます。
明示的に呼び出されるまで待たずともロード時すぐに関数内容を実行できるよう、このマルウェアはmainのコードをDllMainエントリポイントで(DLLのロードフローの残りの部分をブロックしないよう)新たなスレッドを作成して実行します。
このmain関数は、単純な1バイトXORでC2のURLをデコードしてからWin32API関数でデコードしたURLに接続します。コード中に見つかった文字列からすると、このマルウェアの作者はネットワークロジックにオープンソースC++プロジェクトのWinHttpClientを使ったようです。その後、マルウェアは主要イベントループに入って以下のアクションを実行します。
- ハードコードされた古いLinuxのユーザーエージェントとメッセージで、デコードしたURLにPOSTリクエストを送信
- 応答が Unicode 726563697074、つまり「recipt」(英語を母語としない作者か?)で始まることを確認
- いくつかの異なるコマンドで構造体をパース、これには以下を含む:
- リモートホストへのファイル保存
- 特定フォルダからのDLLロード・実行
- 「1時間 + ランダムに生成した時間」のスリープ
Going Eagleの第2段階の分析
このDLLは、観測中の大半の期間、アクターからのコマンドを受け取っている様子がありませんでした。ただしあるとき、攻撃者の活動していた数日間、dnszonetransfer[.]comの解決先IPが一時的に51.38.89[.]53に向けられたことがありました。これは検知を回避する一般的な戦術で、マルウェアのコントロールが必要になったときだけC2ドメインが攻撃者のインフラを向くようにしています。この攻撃者のコントロールするIPは、第1段階のマルウェアを使って第2段階のDLL(「Going Eagle」と命名)をロードしていました。
ClickRuntime-amd86.dllの分析
この実行ファイルは32ビットDLLとしてGoで作成されています。DLLのメタデータにあるオリジナルのコンパイル名はiphlpapi.dllです。ちょっと興味深いのがこのDLLは同名の別Microsoft DLLのプロキシになっている(かつ関連する名のついたエクスポート関数をすべて模倣している)点です。第1段階はLoadLibraryでこれをロードしていてDLLハイジャック技術でロードしたわけではないので、これは必要のない処理です。
これらのDLLはC++とGoという異なる言語で書かれていますが、よく似た点がたくさんあります。
- コンパイルタイムスタンプ: 同じ日に作成・ドロップされている
- プロキシDLLとして作成されている
- popoという名前のエクスポート関数を持つ
- 関数DllMainとpopoがある関数を呼び出し、その関数が別スレッドでマルウェアの内部ロジックを呼び出す。これによりマルウェアの内部ロジックはDLLのロード時、または別のpopoによる呼び出し時にただちに実行される
このツールはたった1つのタスクのために作られています。すなわち、リバースSOCKSプロキシを作って攻撃者がマシンをコントロールできるようにする、ということです。これについてはラテラルムーブのセクションで後述します。
このマルウェアはGoで書かれているので平文の文字列からさらにデータを抽出できます。
- オリジナルのパッケージ名 Eagle2.5-Client-Dll(図6の赤枠部分)
- オリジナルの関数名(main.StartEagleなど)
- Go標準ライブラリおよび拡張ライブラリからのパッケージ (bufio、log、x/netなど)
- GitHubリポジトリなど他のリソースからのパッケージ(図6の黄色と緑で囲った部分)
ラテラルムーブ
この攻撃者は第2段階のSOCKSバイナリであるGoing Eagleでマシンをトンネリングし、いくつかのネットワークベースの攻撃を実行していました。
まず複数のホストをスキャンしてオープンなRDP(Remote Desktop Protocol)やSMB(Server Message Block)のポートがあるかを探し、そこからラテラルムーブの対象を見つけようとします。この攻撃者は、ローカルの管理者が複数の異なるホストでパスワードを使いまわしていたことを利用し、Impacketのwmiexecを使って複数のマシンに対し検出コマンドを発行していました。
これにより、以下の検出器がトリガーされました。
wmiexecの利用に加えてRDP経由のネットワーク内のラテラルムーブも行われており、アップロードしたPsExecでSYSTEMとしてtaskmgr.exeを実行後、lsassメモリのダンプによる認証情報収集が行われていました。
Cortex XDRエージェントはこちらの活動もブロックしており、この活動に起因してCortex XDR Analytics、Cortex XDR BIOCがさらに複数のアラートを発報していました。
ある時点でこの攻撃者は特権ドメインアカウントの取得に成功し、このアカウントでImpacketのsecretsdumpを使ってドメインコントローラからシークレットを盗み出そうとしましたが、この試みはCortex XDRエージェントにブロックされていました。
多層にわたる保護対策の導入で目的を達成できなかったことから、この攻撃者はラテラルムーブの試みをやめたようです。
第2段階のタイムライン
時刻(UTC) | MITREテクニック | アクション | 検出 |
---|---|---|---|
1日目 17:28 | Dynamic Resolution | 攻撃者がdnszonetransfer[.]comのIPアドレスの解決先を51.38.89[.]53に変更 | |
2日目 20:19 | Application Layer Protocol | 感染ホストが最初のコマンドを51.38.89[.]53から受信 | |
Signed Binary Proxy Execution | 第2段階のDLLであるGoing Eagle(ClickRuntime-amd86.dll)をロード | Globally uncommon image load from a signed process (Added after the fact) | |
Application Layer Protocol | reporterror[.]netへの初めての送信 | Globally uncommon root domain from a signed process (Added after the fact) |
|
Proxy | 攻撃者のマシンがSOCKSプロキシでトンネリング | ||
2日目 20:29 | Network Service Scanning | 複数のホストをスキャンしてオープンになっているRDP、SMB、リモートプロシージャコール (RPC)用のポートを検出 | Failed Connections |
Day 2 20:35 | Remote Services | wmiexecで1台目のホストに接続 | Remote WMI process execution |
Rare NTLM Access By User To Host | |||
Command execution via wmiexec | |||
Behavioral Threat Protection (suspicious_remote_service) | |||
Behavioral Threat Protection (impacket_cmd) | |||
System Network Configuration Discovery | ディスカバリ(検出)コマンドの実行 | Uncommon IP Configuration Listing via ipconfig.exe | |
Account Discovery | Uncommon user management via net.exe | ||
Uncommon ARP cache listing via arp.exe | |||
Multiple Discovery Commands | |||
2日目 20:50 | Remote Services | wmiexecで2台目のホストに接続 | Remote WMI process execution |
Rare NTLM Access By User To Host | |||
Command execution via wmiexec | |||
Behavioral Threat Protection (suspicious_remote_service) | |||
Behavioral Threat Protection (impacket_cmd) | |||
System Network Configuration Discovery | ディスカバリ(検出)コマンドの実行 | Uncommon IP Configuration Listing via ipconfig.exe | |
Account Discovery | Uncommon user management via net.exe | ||
Uncommon ARP cache listing via arp.exe | |||
Multiple Discovery Commands | |||
2日目 20:53 |
Network Service Scanning | 複数のホストでRDP、SMB、RPCのオープンポートをスキャン | Failed Connections |
2日目 20:54 | Remote Services | wmiexecで3台目のホストに接続 | Remote WMI process execution |
Rare NTLM Access By User To Host | |||
Command execution via wmiexec | |||
Behavioral Threat Protection (suspicious_remote_service) | |||
Behavioral Threat Protection (impacket_cmd) | |||
System Network Configuration Discovery | ディスカバリ(検出)コマンドの実行 | Uncommon IP Configuration Listing via ipconfig.exe | |
Uncommon user management via net.exe | |||
Account Discovery | Uncommon ARP cache listing via arp.exe | ||
Multiple Discovery Commands | |||
2日目 21:40 | Network Service Scanning | 複数のホストでRDP、SMB、RPCのオープンポートをスキャン | Failed Connections |
2日目 21:54 | Remote Desktop Protocol | RDPで4台目のホストにラテラルムーブ | |
2日目 21:56 | LSASS Memory | taskmgrによるlsassのダンプ試行 | Behavioral Threat Protection (minidumpwritedump_handle_terminate) |
2日目 22:01 | LSASS Memory | SYSTEMとしてtaskmgrを実行してlsassのダンプを試行 | Behavioral Threat Protection (minidumpwritedump_handle_terminate) |
Suspicious process executed with a high integrity level | |||
PsExec execution EulaAccepted flag added to the Registry | |||
PsExec runs with System privileges | |||
3日目 01:10 | NTDS | secretsdumpを1台目のDCで実行してブロックされる | heuristic.b.save_sam_or_security_remote (SYNC - Credential Gathering - 3406296443) |
3日目 01:36 | NTDS | secretsdumpを2台目のDCで実行してブロックされる | heuristic.b.save_sam_or_security_remote (SYNC - Credential Gathering - 3406296443) |
8日目 11:16 | Dynamic Resolution | 攻撃者がdnszonetransfer[.]comのIP解決先を良性IPに変更 |
表4 Popping Eagleの攻撃に関連する活動、攻撃手法、検出のタイムライン
関連IoCの検索
マルウェアの振る舞い分析を終えた後、同一アクターによる関連サンプルを探してみることにしました。
仮説
事実の観測:
- 第1段階のDLLが第2段階のDLLをダウンロードしてロードし、そこから関数popoを呼び出す。どちらのDLLも関数popoをエクスポートする。
- 第2段階は不要なDLLプロキシが行われている。
またどちらのDLLもバージョンや開発準備状況を示すインジケータの文字列を含む可能性がある。
- CoL_Final_Lib.dll
- Eagle2.5-Client-Dll
このデータから類推できる攻撃者の手口:
- 既知の公開プロジェクトやライブラリを使い、あまり労力をかけずにツールを複数作成・使用できる。
- 単一のエクスポート関数(このケースではpopo)を持つプロキシDLLを容易に作成できるフレームワークを持っていると考えられる。
- 開発者は複数のプログラミング言語(C++、Go、Python)の知識がある。
脅威ハンティングと検索の方法論
当初、AutoFocusや一般的な公開脅威情報プラットフォームで初期のインジケータ(ハッシュ、ドメイン、IP、URL)を検索しましたが、新たなものは見つかりませんでした。
さらにマルウェア分析中に汎用「hunting」Yaraルールと特定用途の「adversary」のYaraルールを作成し、関連サンプルを検索しました。この汎用ルールは、このアクターとは無関係の「Go socks」サンプルを追加で検出し、そのほとんどがマルウェアであるという驚くべき結果を得ました。
この特定用途の「adversary」ルールでは追加サンプルが見つかりませんでした。
結論
上記の事例で見てきたように、攻撃者はセキュリティ製品の検出回避を狙ってオープンソースコードを使ったカスタムマルウェアを開発しています。高度な攻撃者への対抗には高度な検知技術の駆使が求められます。署名付きアプリケーションの見せる異常な振る舞いを脅威ハンティングすることで、それまでは知られていなかった攻撃や休眠中のバックドア発見に寄与することがわかっています。
このマルウェアは、攻撃対象となったネットワークに合わせて作られたふしがあり、攻撃には汎用ツールが使用されていることから、この攻撃を特定のアクターに帰属させることはできませんでした。
パロアルトネットワークスのお客様は、次の方法でこの種の攻撃から保護されています。
1. Cortex XDRのGlobal Analytics BIOCのアラートには、前述の統計的手法が多く実装されています。
2. Cortex XDR エージェントのBTP(振る舞い脅威防御)は、脆弱なアプリケーションに対するDLLハイジャック攻撃をブロックし、今後同じロード方法を使用するマルウェアを防止します。
3. 次世代ファイアウォール用のクラウド型セキュリティサブスクリプションWildFireとCortex XDRは本稿で言及したすべてのIoCとYaraルールにより特定される将来のすべてのIoCを特定・ブロックします。
付録
IoC
SHA256 | ファイル名 |
e5e89d8db12c7dacddff5c2a76b1f3b52c955c2e86af8f0b3e36c8a5d954b5e8 | uxtheme.dll |
95676c8eeaab93396597e05bb4df3ff8cc5780ad166e4ee54484387b97f381df | uxtheme.dll |
59d12f26cbc3e49e28be13f0306f5a9b1a9fd62909df706e58768d2f0ccca189 | uxtheme.dll |
0dc8f17b053d9bfab45aed21340a1f85325f79e0925caf21b9eaf9fbdc34a47a | ClickRuntime-amd86.dll |
ドメイン |
dnszonetransfer[.]com |
reporterror[.]net |
IP |
51.38.89[.]53 |
51.75.57[.]245 |
URL |
hxxps[:]//dnszonetransfer[.]com/Protocol/extensions.php |
User agent |
Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36 |
ハンティング用Yaraルール
疑わしいGoの実行ファイル
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
rule general_win_golang_socks { meta: author = "paloaltonetworks" date = "2022-03-13" description = "potentially unwanted GO application with proxy communication capabilities" strings: $go_name_1 = "main.go" nocase ascii // default go name for the "func main(){...}" in "package main" $go_name_2 = "eagle" nocase ascii $go_name_3 = "popo" nocase ascii $go_name_4 = "-Client-Dll/" nocase ascii $go_pkg_1 = "github.com/armon/go-socks5" nocase wide ascii $go_pkg_2 = "github.com/hashicorp/yamux" nocase wide ascii $go_pkg_3 = "github.com/fatedier/frp/vendor" wide ascii $go_pkg_4 = "github.com/rofl0r/rocksocks5" wide ascii condition: uint16(0) == 0x5a4d and filesize < 7MB and ( 1 of ($go_name_*) and 2 of ($go_pkg_*) ) } rule general_win_dll_golang_socks { meta: author = "paloaltonetworks" date = "2022-03-13" description = "Highly suspicious GO DLL with proxy communication capabilities" condition: general_win_golang_socks and (pe.characteristics & pe.DLL) and pe.is_dll() } |
この攻撃者のものである可能性があるツール
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
rule general_win_faked_dlls_export_popo { meta: author = "paloaltonetworks" date = "2022-03-13" description = "Detects DLL files with an export function named 'popo'" hash0 = "e5e89d8db12c7dacddff5c2a76b1f3b52c955c2e86af8f0b3e36c8a5d954b5e8" // fake uxtheme.dll hash1 = "95676c8eeaab93396597e05bb4df3ff8cc5780ad166e4ee54484387b97f381df" // fake uxtheme.dll hash2 = "59d12f26cbc3e49e28be13f0306f5a9b1a9fd62909df706e58768d2f0ccca189" // fake uxtheme.dll hash3 = "0dc8f17b053d9bfab45aed21340a1f85325f79e0925caf21b9eaf9fbdc34a47a" // ClickRuntime-amd86.dll condition: (pe.characteristics & pe.DLL) and pe.is_dll() and filesize < 20MB and ( pe.exports("popo") or pe.exports("Popo") ) } |