PIVOTPIPE: 新たな.NET製の非公式Beaconペイロード
2026年7月、IIJは公開ディレクトリ上でホストされた未知の.NET製マルウェアを観測・分析しました。
分析の結果、このマルウェアがCobalt Strike Beacon1に酷似する (あるいは重複する) 機能を持っていることが判明しました。このマルウェアはデフォルトC2プロファイルに近しい構成のCobalt Strike C2サーバとの通信に対応しており、さらにCobalt Strike Beaconに実装されている多くのC2コマンドの実行に対応しています。
しかしながら、検知回避用コード、独自ローダの実装、バイナリ内の文字列の難読化方式など、既存のCobalt Strike Beaconとは異なる実装を持つ機能も多く、単純なCobalt Strike Beaconの再実装版ではないことも確認しています。このことから、我々は本マルウェアを非公式のBeaconペイロードであると評価して、ファイル名やモジュール内の情報をもとに、PIVOTPIPEと命名しました。この記事ではPIVOTPIPEの解析結果や検知ルールなどを共有します。
ローダ
PIVOTPIPEはローダとRATの2つのコンポーネントで構成されています。まず、本項では公開ディレクトリに設置されていたローダの解析結果を紹介します。
ローダが実行されると、まずAMSIバイパス、Indirect Syscallの初期化処理、スリープマスクの有効化など、複数の検知回避およびEDR回避用のコードを実行します。これらの機能はPIVOTPIPEローダおよびRATの両方に実装されています。
MOV EAX,80070057; RET;命令に置換している次にローダは自身のファイル末尾から設定情報を agent.json に、公開鍵を pk.der に、スリープマスク用のCOFFファイルを sleepmask.o に (存在しない場合もある) 、XORエンコードおよびGZIP圧縮されたRATペイロードを core.pak というファイルにそれぞれ抽出して書き込みます。この際、一時フォルダ下に nb_ から始まる名前のフォルダが作成され、それが作業フォルダとして使用されます。
ファイルの書き込みが完了した後、ローダは core.pak をXORデコード、GZIP展開して、RATをメモリ上で実行します。XORデコードに必要な鍵もローダのファイル末尾に含まれており、今回観測した検体においては nbpivotpipe や nblabdbg などの文字列が使用されていました。
なお、ローダの実行時にコマンドライン引数 --foreign が渡されている場合、RATのペイロードをファイル末尾ではなくコマンドライン引数で指定されたURLから取得するよう実装されていました。この場合、PIVOTPIPEの設定情報やRATペイロードのXORデコード鍵は外部ファイル、環境変数、コマンドライン引数などからローダに渡されます。
RAT
ローダによってRATが実行されると、まずローダによって設置されたJSON形式の設定情報 (agent.json) を読み込みます。
なお、今回観測した検体には含まれていませんでしたが、他にも smb_mode, pipe_name, dns_mode といったパラメータが設定情報に含まれている可能性があります。これらのパラメータは本家Cobalt Strike Beaconにも存在するDNSを使用したC2通信やSMB Beacon2といった機能で使用されます。
その後、設定情報の内容をもとにC2サーバと通信します。SMB BeaconあるいはTCP Beacon3を使用するよう設定されている (設定情報内のパラメータ pivot_mode の値が true だった) 場合、PIVOTPIPEに感染した他のホストを経由してC2通信を実施します。
基本的にCobalt Strike Beaconのコマンド体系と同一ですが、PIVOTPIPEが対応しているC2コマンドの一覧は以下の通りです。
| Type | 説明 |
|---|---|
| 3 | RATを終了する |
| 4 | 通信間隔 (Sleep時間) を変更する |
| 5 | 作業フォルダを変更する |
| 6 | 特定の通信データのアンパック用のコマンド |
| 10 | ファイルをアップロードする |
| 11 | ファイルをダウンロードする |
| 14 – 17 | (リバース) ポートフォワーディングに関連するコマンド |
| 19 | ファイルのダウンロードを停止する |
| 22 – 24 | TCP BeaconおよびSMB Beaconに関連するコマンド |
| 27 | ユーザ情報を取得する |
| 28 | RevertToSelf関数を呼び出す |
| 31 | 他プロセスのトークンを取得・偽装する |
| 32 | プロセス一覧を取得する |
| 33 | プロセスをキルする |
| 39 | 作業フォルダを取得する |
| 50 | リバースポートフォワーディングを開始する |
| 53 | フォルダの内容を取得する |
| 54 | フォルダを作成する |
| 55 | ドライブ一覧を取得する |
| 56 | ファイルを削除する |
| 67 | ファイルの末尾にデータを書き込む |
| 68 | SMB Beaconに接続する |
| 73 | ファイルをコピーする |
| 74 | ファイルを移動する |
| 78 | コマンドを実行する |
| 82 | TCP BeaconのListenを開始する |
なお、今回観測した検体 pivot_hop2_kasp.exe はTCP Beacon機能を使用するよう設定情報が構成されていました。TCP Beacon機能が使用されている場合、PIVOTPIPEは他の感染ホストとP2P通信を行い、そのホストを経由してC2サーバと通信します。
開発途中のマルウェアという可能性について
PIVOTPIPEローダおよびRATが実行されると、マルウェア内の特定の処理 (C2通信やエラーハンドリングなど) のタイミングで、以下のファイルパスにデバッグ情報が書き込まれることを確認しています。
C:\WINDOWS\Temp\nb_drip_dbg.txtC:\WINDOWS\Temp\nb_hook_dbg.txtC:\WINDOWS\Temp\nb_fatal.txtC:\WINDOWS\Temp\nb_hook_exports.txtC:\WINDOWS\Temp\nb_hello_postex_ok.txtC:\WINDOWS\Temp\nb_spawn_rewrite.txtC:\WINDOWS\Temp\nb_postex_dbg.txtC:\WINDOWS\Temp\nb_postex_fail.txtC:\WINDOWS\Temp\nb_hb_dbg.txtC:\WINDOWS\Temp\nb_post_last.txtC:\WINDOWS\Temp\nb_export_dbg.txtC:\WINDOWS\Temp\nb_sleep_dbg.txt
また、いくつかの機能の実装において、以下のようなマルウェアの開発環境のものと思われるファイルパスが使用されることを確認しています。
C:\Users\admin\Desktop\cscs\4.5\payloads\dotnet-4.x\sleeve\postex\hello_postex.dllC:\Users\admin\Desktop\cscs\4.5\payloads\dotnet-4.x\sleeve\postex\hello.dll.enc
これらの痕跡から、PIVOTPIPEは観測時点では開発途中であり、今後さらに検知回避機能などがアップデートされる可能性があるといえます。
アンパッカー
我々は分析の効率化のためにローダのファイル末尾を静的に抽出、デコード、展開するPythonスクリプトを作成しました。ぜひインシデント対応や脅威リサーチ等でお役立てください。
unpack_pivotpipe_datablob.py
https://github.com/mopisec/research/blob/main/unpack_pivotpipe_datablob.py
unpack_pivotpipe_datablob.pyさいごに
一部開発途中と思われる機能も確認されましたが、PIVOTPIPEは既に実際の攻撃活動で使用されている可能性があります。引き続き警戒が必要だといえるでしょう。
Appendix A: IoCs
ネットワーク
- 45.32.253[.]166 (JP ; AS 20473 ; The Constant Company, LLC)
- ポート8088 : Cobalt Strike C2サーバ
- ポート8766 : 公開ディレクトリ
ファイル
| SHA256 | ファイル名 |
|---|---|
| AD9A03F3EA93C1A0A350F73B4ADA485CE444F2352EA11EEA05C87F075BE80CF7 | netbeacon_pivot.exe |
| FEEB5CAE714D0D35F68AD1D1B29DCCEC0BDCC58AC076869559DB53F6CB8137E8 | pivot_hop2_kasp.exe |
| 715558E0AD32401C477D01412CC72FD07DC4EF6E122B6A730BA4B0A88A971677 | x64beacon.exe |
Appendix B: YARAルール
rule PIVOTPIPE_LDR {
meta:
description = "Detects PIVOTPIPE Loader Payload"
author = "Internet Initiative Japan Inc."
hash1 = "AD9A03F3EA93C1A0A350F73B4ADA485CE444F2352EA11EEA05C87F075BE80CF7"
hash2 = "FEEB5CAE714D0D35F68AD1D1B29DCCEC0BDCC58AC076869559DB53F6CB8137E8"
hash3 = "715558E0AD32401C477D01412CC72FD07DC4EF6E122B6A730BA4B0A88A971677"
strings:
$magic = "NBPK1"
$path0 = "C:\\WINDOWS\\Temp\\nb_fatal.txt" ascii wide
$path1 = "C:\\WINDOWS\\Temp\\nb_sleep_dbg.txt" ascii wide
$path2 = "C:\\WINDOWS\\Temp\\nb_drip_dbg.txt" ascii wide
$path3 = "C:\\WINDOWS\\Temp\\nb_hook_exports.txt" ascii wide
$path4 = "C:\\WINDOWS\\Temp\\nb_hello_postex_ok.txt" ascii wide
$path5 = "C:\\WINDOWS\\Temp\\nb_spawn_rewrite.txt" ascii wide
$devpath0 = "C:\\Users\\admin\\Desktop\\cscs\\4.5\\payloads\\dotnet-4.x\\sleeve\\postex\\hello_postex.dll" ascii wide
$devpath1 = "C:\\Users\\admin\\Desktop\\cscs\\4.5\\payloads\\dotnet-4.x\\sleeve\\postex\\hello.dll.enc" ascii wide
$str0 = "NB_AGENT_BASE" ascii wide
$str1 = "NB_AGENT_SIZE" ascii wide
$str2 = "NB_AGENT_MOD" ascii wide
$str3 = "NB_AGENT_CLR_CORE" ascii wide
$str4 = "HookGate init failed" ascii wide
$str5 = "--- postex inject chain (Ghidra D2) ---" ascii wide
$str6 = "foreign fetch needs pack key arg3 or NB_PACK_KEY" ascii wide
$str7 = "hello shellcode requires x64" ascii wide
condition:
$magic and ((3 of ($path*)) or (1 of ($devpath*)) or (3 of ($str*)))
}Code language: plaintext (plaintext)
- 著名な脅威エミュレーションツールCobalt Strikeのエージェントプログラム。通常のマルウェアと同様に、C2サーバから命令を受信して、対応する処理を実行できる。 ↩︎
- SMB Beacon – Cobalt Strike User Guide
https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/content/topics/listener-infrastructure_beacon-smb.htm ↩︎ - TCP Beacon – Cobalt Strike User Guide
https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/content/topics/listener-infrastructure_beacon-tcp.htm ↩︎