エグゼクティブ サマリー
2025年5月初旬、Unit 42の研究者は、AdaptixC2が複数のシステムの感染に使用されていることを確認しました。
最近確認されたオープンソースのAdaptixC2は、ポストエクスプロイトの侵入テスト担当者向けの攻撃者エミュレーション フレームワークで、脅威アクターがキャンペーンで使用しています。多くの有名なC2フレームワークとは異なり、AdaptixC2はほとんど注目されていませんでした。実際の攻撃におけるその使用を実証する公開文書は限られています 。私たちの調査は、AdaptixC2に何ができるに着目し、セキュリティ チームがそれに対して身を守る手助けをします。
AdaptixC2は 汎用性の高いポストエクスプロイト フレームワークです。脅威アクターはこれを使用して、侵害されたシステム上でコマンドの実行、ファイルの転送、データの流出を行います。オープンソースであるため、脅威アクターは自分たちの特定の目的に合わせて簡単にカスタマイズし、適応させることができます。そのため、非常に柔軟で危険なツールとなっています。
AdaptixC2が脅威アクターによって実際に使用されるツールとして登場したことは、攻撃者が検出を回避するためにカスタマイズ可能なフレームワークを使用する傾向が強まっていることを浮き彫りにしています。
Palo Alto Networksのお客様は、以下の製品を通じて、本書に記載するツールに対する確実な保護を構築いただけます。
- Advanced DNS Security
- Advanced Threat Prevention
- Advanced URL Filtering
- Advanced WildFire
- Cortex XDRおよびXSIAM
情報漏えいの可能性がある場合、または緊急の案件がある場合は、Unit 42インシデント レスポンス チームまでご連絡ください。
Unit 42の関連トピック | Pentesting Tools, C2 |
AdaptixC2攻撃者フレームワークの手法分析
AdaptixC2はオープンソースのC2フレームワークで、最近、いくつかの実際の攻撃での使用が確認されました。
私たちは2件のAdaptixC2への感染を確認しました。ソーシャル エンジニアリング手法を利用したケースも1件ありました。私たちは、相手方がAIベースのコード生成ツールを使用したことを高い信頼性で評価しています。
AdaptixC2の機能性
AdaptixC2は、敵対行動を実行するために使用可能なレッド チーミング ツールで、拡張してカスタマイズできます。脅威アクターがこれを利用すると、影響を受けたマシンを包括的にコントロールし、次のような幅広いアクションを実行することができます。そのいくつかを次に示します:
- ファイル システムの操作
- ディレクトリのリスティング
- ファイルやフォルダの作成、変更、削除
- 実行中のプロセスの列挙
- 特定のアプリケーションの終了
- 新しいプログラムの実行開始
脅威アクターは、これらの機能を利用して、環境内に足場を築き、維持し、侵害されたシステムをさらに探索し、ネットワーク内で横方向に移動します。
秘密通信を容易にし、ネットワーク制限を回避するために、フレームワークはSOCKS4/5プロキシ機能やポート転送などの高度なトンネリング機能をサポートしています。これにより、ネットワークが厳重に保護されていても、攻撃者は通信チャネルを維持することができるのです。
AdaptixC2は、リスナーとエージェントの両方のプラグインのように動作する「エクステンダー」を使用して、モジュール化できるように設計されています。これによってハッカーは、攻撃対象のシステムに特化したカスタム ペイロードや検知を回避する方法を作り出すことができます。AdaptixC2は、Beacon Object Files (BOF)もサポートしており、攻撃者は検出を回避するために、エージェントのプロセス内で直接C言語で書かれた小さなカスタム プログラムを実行することができます。
AdaptixC2のビーコン エージェントは、迅速かつ密かにデータを転送するための専用コマンドを備えています。これらのエージェントはx86とx64の両アーキテクチャをサポートし、以下のような様々なフォーマットで生成することができます:
- スタンドアロン実行可能ファイル (EXE)
- ダイナミック リンク ライブラリ (DLL)
- サービス実行ファイル
- 生のシェルコード
攻撃者はAdaptixC2フレームワークを使用して、侵害されたネットワークからデータを盗むことができます。ネットワークに基づく検出では比較的小さいセグメントを疑わしいものとみなさない傾向があるため、このデータ流出機能では、ファイルのダウンロードとアップロードのチャンクサイズを設定できます。
AdaptixC2インターフェースは、リンクされたエージェントとセッションをグラフィカル ビューに表示します。図1は、多段攻撃がどのように進行し、攻撃対象のネットワークを移動するためにどのような経路が利用可能かを攻撃者の視点で見たものです。

AdaptixC2には、攻撃者がオペレーショナル セキュリティ (OpSec)を維持するための機能もあります。これらには、通常のネットワーク トラフィックに紛れ込むためのパラメータが含まれています:
- KillDate - ビーコンの動作を停止する日付を設定します
- WorkingTime - ビーコンが特定の時間帯のみアクティブになるように設定します
さらに、脅威アクターは、カスタムの難読化、アンチ解析および回避テクニックを使用してエージェントに変更を加えて強化することができるため、継続的に進化する脅威となっています。
設定
AdaptixC2の設定は暗号化されており、特殊なプロファイル構造によって3つの主要なビーコン タイプをサポートしています:
- ウェブベースの通信用BEACON_HTTP
- 名前付きパイプ通信用BEACON_SMB
- 直接TCP接続用BEACON_TC
HTTPプロファイルは最も一般的なビーコンで、以下のような典型的なウェブ通信パラメータを含んでいます:
- サーバー
- ポート
- SSL設定
- HTTPメソッド
- URI
- ヘッダー
- ユーザー エージェント文字列
SMBプロファイルは、HTTPがブロックまたは監視される可能性がある場合、Windowsの名前付きパイプを使用します。TCPプロファイルは、基本的なプロトコルの難読化のためにデータを先頭に追加するオプション付きの直接ソケット接続を作成するために使用されます。
AdaptixC2には、典型的なデプロイ パラメータを示すデフォルト設定が組み込まれています。デフォルトのHTTPプロファイルは、/uri.phpエンドポイントへのPOSTメソッドとビーコン識別用のX-Beacon-Idパラメータを使用して、HTTPS通信で172.16.196.1:4443をターゲットにします。
図2は、ビーコンの設定方法を示しています。

[Create(作成)]をクリックすると、ビーコン ビルダーは設定ををRC4で暗号化し、コンパイルされたビーコンに埋め込みます。暗号化された設定は以下のように保存されます:
- 4バイト:設定サイズ(32ビット整数)
- Nバイト:RC4で暗号化された設定データ
- 16バイト:RC4暗号化キー
次のコードは、AgentConfig.cppから抜粋したキー抽出ロジックです。:
1 2 3 4 5 6 7 |
ULONG profileSize = packer->Unpack32(); this->encrypt_key = (PBYTE) MemAllocLocal(16); memcpy(this->encrypt_key, packer->data() + 4 + profileSize, 16); DecryptRC4(packer->data()+4, profileSize, this->encrypt_key, 16); |
悪意のあるサンプルから設定を抽出する
暗号化はシンプルで予測可能なため、防御者はサンプルから設定を自動的に抽出する抽出器を開発することができます。この抽出ツールは、ビーコンが自身の設定をロードするのと同じように動作するものです。
抽出器はPEファイルの.rdataセクションにある設定を見つけます。そして、サイズ(最初の4バイト)、暗号化されたデータブロック、RC4キー(最後の16バイト)を抽出します。埋め込まれたRC4キーを使ってデータを復号化した後、以下のフィールドをパースして平文の設定を解析します:
- エージェント タイプ
- SSLフラグ
- サーバー数
- サーバー/ポート
- HTTPパラメータ
- タイミング設定
この方法を用いて、AdaptixC2サンプルを処理し、その埋め込み設定を取得できるツールを作成しました。完全な抽出器コードはBEACON_HTTPの亜種をサポートしています。このツールは設定抽出器の例セクションで提供されています。研究者は、AdaptixC2サンプルの解析にこの抽出器を使用したり、他の亜種用にコードを適応させたりすることができます。
以下は、ビーコンに内蔵のデフォルト設定である。
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 39 |
{ "agent_type": 3192652105, "use_ssl": true, "servers_count": 1, "servers": ["172.16.196.1"], "ports": [4443], "http_method": "POST", "uri": "/uri.php", "parameter": "X-Beacon-Id", "user_agent": "Mozilla/5.0 (Windows NT 6.2; rv:20.0) Gecko/20121202 Firefox/20.0", "http_headers": "\r\n", "ans_pre_size": 26, "ans_size": 47, "kill_date": 0, "working_time": 0, "sleep_delay": 2, "jitter_delay": 0, "listener_type": 0, "download_chunk_size": 102400 } |
AdaptixC2 シナリオ
シナリオ1:偽のヘルプデスクサポートがAdaptixC2感染につながる
2025年5月、私たちは脅威アクターがAdaptixC2ビーコンをインストールした複数のインシデントを調査しました。いくつかのケースでは、図3に示すように、脅威アクターが同じ攻撃ベクトルを使用していることが確認されました。

最初の侵害
脅威アクターはMicrosoft Teamsの信頼性を利用し、人々を騙して会社のシステムへのアクセスを許可させました。あるケースでは、攻撃者は フィッシング攻撃を使い、([「ヘルプデスク(外部 | Microsoft Teams」といった件名で) ITサポート担当者になりすましました。これにより、従業員はクイック アシスト リモート監視・管理(RMM)ツールのようなツールを使って正規のリモートアシスタンスセッションを開始しました。
脅威アクターはしばしば、その悪質な目的を達成しようと正規製品を悪用します。これは必ずしも、悪用されている正規製品に欠陥や悪意があることを意味するものではありません。
Unit 42インシデント レスポンス レポート(2025年版):ソーシャル エンジニアリング編では、このようなソーシャル エンジニアリング手法は、私たちが観測している侵害の最初のアクセス ベクトルとして最も一般的なものです。この初期アクセスにより、攻撃者はファイアウォールや侵入検知システムなどの境界防御を迂回することなく、標的システム内の足がかりを得ることができます。
シェルコード実行によるAdaptixC2のデプロイと永続化
攻撃者は、正当なサービスへのリンクから暗号化されたペイロードをダウンロードする多段階のPowerShellローダーを使用して、AdaptixC2ビーコンをデプロイしし、
ダウンロードされると、PowerShellスクリプトは単純なXORキーを使用してペイロードを復号化します。このスクリプトは、検出が容易なように復号化されたペイロードをディスクに書き込む代わりに、.NETの機能を活用してPowerShellプロセス自体にメモリを割り当てます。そしてスクリプトは、実際にはシェルコードである復号化されたペイロードを、この割り当てられたメモリ領域にコピーします。このファイルレスアプローチは、システム上での攻撃者のフットプリントを大幅に削減します。

このスクリプトは、「動的呼び出し」と呼ばれるテクニックを使って、メモリから直接シェルコードを実行します。これはGetDelegateForFunctionPointerメソッドを使用して行い、メモリ上のシェルコードの先頭を指すデリゲート(型安全な関数ポインタ)を動的に作成します。スクリプトは次に、このデリゲートを通常の関数であるかのように呼び出し、実行ファイルをディスクに書き込むことなく、シェルコードを効果的に実行します。再起動後に悪意のあるプロセスが自動的に起動することを保証するために、スクリプトはスタートアップフォルダにショートカットを作成します。図4にPowerShellスクリプトを示します。

この攻撃でロードされたビーコンの亜種は、次のような設定でした:
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 39 40 41 42 43 44 45 46 47 |
{ "agent_type": 3192652105, "use_ssl": true, "servers_count": 1, "servers": [ "tech-system[.]online" ], "ports": [ 443 ], "http_method": "POST", "uri": "/endpoint/api", "parameter": "X-App-Id", "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.6167.160 Safari/537.36", "http_headers": "\r\n", "ans_pre_size": 26, "ans_size": 47, "kill_date": 0, "working_time": 0, "sleep_delay": 4, "jitter_delay": 0, "listener_type": 0, "download_chunk_size": 102400 } |
エクスプロイト後の活動と封じ込め
AdaptixC2のデプロイに成功した後、攻撃者は、侵害されたシステムとネットワークに関する情報を収集するために、コマンドラインツールを使用して偵察活動を開始しました。これには、nltest.exe、whoami.exe、ipconfig.exeなどの情報収集用コマンドが含まれました。
ビーコンはその後、リモートサーバーとの通信を確立し、脅威アクターが感染したマシン上でC2を取得できるようにします。
シナリオ2:AIが生成したスクリプトによる感染
別のケースでは、脅威アクターはAdaptixC2ビーコンをデプロイするように設計されたPowerShellスクリプトを展開しました。私たちはこのスクリプトはAIが作成したものであると自信をもって評価します。このデプロイは、インメモリ シェルコード インジェクションと、ファイルベースのDLLハイジャック永続化メカニズムを使って行われました。図5に示すスクリプトは、ハッカーに強力な足がかりを与えるために、影響を受けたシステム上に隠れることに重点を置いています。

AIが生成したPowerShellの詳細分析
- シェルコードのダウンロードとデコード:このスクリプトは、Invoke-RestMethodを使用してBase64でエンコードされたシェルコードのペイロードをリモート サーバーからダウンロードします。ダウンロードされたコンテンツはデコードされます。
- メモリの割り当て、シェルコードのコピー、メモリ保護の変更:スクリプトは管理対象外メモリのブロックを割り当てます。AdaptixC2のシェルコードは、次に割り当てられたメモリにコピーされ、割り当てられたメモリ領域のメモリ保護属性を VirtualProtectを介して0x40 (PAGE_EXECUTE_READWRITE)に変更します。これにより、シェルコードの実行が可能になります。
- 動的呼び出しによるシェルコードの実行:前のケースと同様に、攻撃者はGetDelegateForFunctionPointerを使用して、メモリ内のシェルコードの先頭を指すデリゲート インスタンスを作成しました。攻撃者はその後、Invoke()メソッドを使ってシェルコードを実行し、メモリ内のビーコンを起動しました。
- DLLハイジャックの永続性:このスクリプトは、msimg32.dllを使用して、DLLハイジャック用のAPPDATAMicrosoftWindowsTemplatesディレクトリをターゲットにします。このDLLはビーコン版でもあります。
- レジストリの実行キーによる永続化:スクリプトは実行キーに、loader.ps1スクリプトを実行するPowerShellコマンドを含む、"Updater"という名前のレジストリエントリを作成します。これにより、ユーザーがログインするたびにloader.ps1スクリプトが実行され、ビーコンが実行されます。
AIスクリプト生成
このPowerShellスクリプトの構造と構成は、攻撃者がAI支援生成を使用したことを強く示唆しています。AIツールが生成するコードには、次のような文体的要素がよく見られます:
- 冗長な番号付きコメント:
- "# === [1] シェルコードのダウンロードとデコード ==="
- 出力メッセージのチェックマークアイコン:
- Write-Output "[✔] Runキーで永続性を設定し、DLLハイジャックDLLを$templatesPathにドロップ"
私たちは、このコードがAIの助けを借りて生成されたと自信をもって評価します。これは、上記の要因に加え、攻撃者のサーバーから収集した証拠と、2つの別々のAI検知器から抽出した結果に基づいています。
十分なガードレールのないAIツールは、攻撃者が悪意のあるコードを迅速に開発し、感染したネットワークで操作を実行することを容易にする可能性があります。
ケース間の類似点
これらの事件には一貫したパターンが見られました:
- PowerShellベースのローダー
- 脅威アクターはこれらのローダーを使ってAdaptixC2ビーコンをデプロイし、ステルス性と持続的なアクセスを優先しました。
- リモートサーバーからペイロードをダウンロードし、メモリ内で実行する
- 正規のリソースを使用することで、ディスク上の検出可能な痕跡を最小限に抑えることができ、攻撃者はレーダーをかいくぐることができました。
- メモリ割り当てと動的呼び出しのために.NETの機能に頼る
- 脅威アクターはGetDelegateForFunctionPointer メソッドのようなのような組み込みのシステム機能を活用して、効率とステルス性を保証するシェルコードを実行しました。
- 永続化メカニズムによるビーコン削除の防止
- 最初のスクリプトは、永続性を保つ為にスタートアップフォルダ内のショートカットのみに依存していた一方で、2番目のスクリプトではDLLハイジャックを追加しました。
- これにより、攻撃者は侵害されたシステムにとどまる方法を増やすことになります。
- スクリプトと実行キーに類似した命名規則を使用する
- あるケースでは、攻撃者は悪意のあるスクリプトにupdate.ps1という名前を付けていました。別の例では、永続化のための実行キーがアップデーターと呼ばれていました。
- このネーミングは、スクリプトやキーが正規のシステム プロセスに紛れ込むのを助けます。
AdaptixC2フレームワークの普及が進む
私たちのテレメトリと脅威インテリジェンスによると、AdaptixC2がより一般的になっていることを示しています。私たちは新しいAdaptixC2サーバを引き続き確認しており、これはより多くの脅威アクターが攻撃ツールキットの一部としてこのフレームワークを採用していることを示唆しています。
この傾向は、典型的なポストエクスプロイトのシナリオにとどまりません。たとえば、攻撃者は最近のアジアにある金融機関に対する攻撃において、AdaptixC2とともにFogランサムウェアをデプロイしました。このことは、AdaptixC2が多用途であり、ランサムウェアのような他の悪意のあるツールと併用することで、より幅広い目的を達成できることを示しています。
結論
AdaptixC2は適応可能な脅威であり、脅威アクターの間で人気が高まっていることや、そのデプロイ手法が複雑であることがそれを示しています。このフレームワークのモジュール性は、AI支援によるコード生成の可能性と相まって、脅威アクターが迅速に戦術を進化させることを可能にするかもしれません。セキュリティ チームは、AdaptixC2の能力を常に認識し、この脅威に対抗するために防御を積極的に適応させる必要があります。
Palo Alto Networksのお客様は、以下の製品を通じて、上記の脅威に対する確実な保護を構築いただけます。
- Advanced URL FilteringとAdvanced DNS Securityは、この活動に関連する既知のドメインとURLを悪意のあるものとして識別することが可能です。
- Advanced Threat Preventionには、エクスプロイトをリアルタイムで検出できる機械学習ベースの検出機能が組み込まれています。
- Advanced WildFireの機械学習モデルと分析技術は、本研究で共有されたインジケーターに照らして見直され、更新されています。
- Cortex XDRおよびXSIAMでマルウェア防止エンジンを採用することで、マルウェアを防止します。このアプローチは、既知のマルウェアと未知のマルウェアの両方がエンドポイントに害を及ぼすのを防ぐように設計された複数の保護レイヤーを組み合わせたものです。マルウェア防御エンジンが採用する軽減技術は、エンドポイントのタイプによって異なります。
情報漏えいの可能性がある場合、または緊急の案件がある場合は、Unit 42インシデント レスポンス チームまでご連絡ください。
- 北米:フリーダイヤル: +1 (866) 486-4842 (866.4.UNIT42)
- 英国: +44.20.3743.3660
- ヨーロッパおよび中東: +31.20.299.3130
- アジア: +65.6983.8730
- 日本: +81.50.1790.0200
- オーストラリア: +61.2.4062.7950
- インド: 00080005045107
パロアルトネットワークスは、本調査結果をサイバー脅威アライアンス(CTA)のメンバーと共有しています。CTAの会員は、この情報を利用して、その顧客に対して迅速に保護を提供し、悪意のあるサイバー アクターを組織的に妨害しています。サイバー脅威アライアンスについて詳細を見る。
侵害のインジケーター
値 | タイプ | 内容 |
bdb1b9e37f6467b5f98d151a43f280f319bacf18198b22f55722292a832933ab | SHA256 | AdaptixC2ビーコンをインストールするPowerShellスクリプト |
83AC38FB389A56A6BD5EB39ABF2AD81FAB84A7382DA296A855F62F3CDD9D629D | SHA256 | AdaptixC2ビーコンをインストールするPowerShellスクリプト |
19c174f74b9de744502cdf47512ff10bba58248aa79a872ad64c23398e19580b | SHA256 | AdaptixC2ビーコンをインストールするPowerShellスクリプト |
750b29ca6d52a55d0ba8f13e297244ee8d1b96066a9944f4aac88598ae000f41 | SHA256 | AdaptixC2ビーコンをインストールするPowerShellスクリプト |
b81aa37867f0ec772951ac30a5616db4d23ea49f7fd1a07bb1f1f45e304fc625 | SHA256 | DLLとしてのAdaptixC2ビーコン |
df0d4ba2e0799f337daac2b0ad7a64d80b7bcd68b7b57d2a26e47b2f520cc260 | SHA256 | EXEとしてのAdaptixC2ビーコン |
AD96A3DAB7F201DD7C9938DCF70D6921849F92C1A20A84A28B28D11F40F0FB06 | SHA256 | AdaptixC2ビーコンをインストールするシェルコード |
tech-system[.]online | ドメイン | AdaptixC2ドメイン |
protoflint[.]com | ドメイン | AdaptixC2ドメイン |
novelumbsasa[.]art | ドメイン | AdaptixC2ドメイン |
picasosoftai[.]shop | ドメイン | AdaptixC2ドメイン |
dtt.alux[.]cc | ドメイン | AdaptixC2ドメイン |
moldostonesupplies[.]pro | ドメイン | AdaptixC2ドメイン |
x6iye[.]site | ドメイン | AdaptixC2ドメイン |
buenohuy[.]live | ドメイン | AdaptixC2ドメイン |
firetrue[.]live | ドメイン | AdaptixC2ドメイン |
lokipoki[.]live | ドメイン | AdaptixC2ドメイン |
veryspec[.]live | ドメイン | AdaptixC2ドメイン |
mautau[.]live | ドメイン | AdaptixC2ドメイン |
muatay[.]live | ドメイン | AdaptixC2ドメイン |
nicepliced[.]live | ドメイン | AdaptixC2ドメイン |
nissi[.]bg | ドメイン | AdaptixC2ドメイン |
express1solutions[.]com | ドメイン | AdaptixC2ドメイン |
iorestore[.]com | ドメイン | AdaptixC2ドメイン |
doamin[.]cc | ドメイン | AdaptixC2ドメイン |
regonalone[.]com | ドメイン | AdaptixC2ドメイン |
Yaraルール
防御者は、これらのYaraルールを使用して、マシン上のAdaptixC2ビーコンの存在をチェックすることができます。
AdaptixC2 HTTP/SMB/TCPビーコン
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 |
rule u42_hacktool_beacon_adaptixC2 { meta: description = "Detects AdaptixC2 beacon via basic functions" reference = "https://github.com/Adaptix-Framework/AdaptixC2" strings: $FileTimeToUnixTimestamp = {D1 65 F8 83 7D F4 1F 7E 17 8B 55 E4} $Proxyfire_RecvProxy = {B9 FC FF 0F 00 E8 6A 04 00 00} $timeCalc1 = {8D 82 A0 05 00 00 89 44 24 3C EB 07} $timeCalc2 = {FF D2 0F B7 44 24 28 66 3B} $b64_encoded_size = {83 C0 01 39 45 18 7E 22 8B 45 E4 C1 E0 08 89 C1} $manage = {C6 44 24 5F 00 48 8B 45 10 48 8B 00} condition: any of them } |
AdaptixC2 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 |
rule u42_hacktool_beaconGo_adaptixC2 { meta: description = "Detects AdaptixC2 beacon in GO via basic functions" reference = "https://github.com/Adaptix-Framework/AdaptixC2/tree/a7401fa3fdbc7ae6b632c40570292f844e40ff40/Extenders/agent_gopher" strings: $GetProcesses = {E8 96 4D E1 FF E8 96 4D E1 FF E8 96 4D E1 FF} $ConnRead = {0F 8E BD 00 00 00 4C 89 44 24 30 4C 89 54 24 40} $normalizedPath = {48 85 C9 74 0A 31 C0 31 DB 48 83 C4 38 5D C3 90 0F 1F 40 00} $Linux_GetOsVersion = {48 8D 05 51 D6 10 00 BB 0F 00 00 00} $Mac_GetOsVersion = {48 8D 05 AE 5A 0A 00 BB 30 00 00 00} condition: any of them } |
AdaptixC2 Loader
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 39 40 41 42 43 |
rule u42_hacktool_adaptixC2_loader { meta: description = "Detects AdaptixC2 shellcode loader via API Hashing" reference = "https://github.com/Adaptix-Framework/AdaptixC2/blob/main/Extenders/agent_beacon/src_beacon/beacon/ApiDefines.h" strings: $hash_NtFlushInstructionCache = { 9E 65 A1 91 } $hash_VirtualAlloc = { 76 63 CE 63 } $hash_GetProcAddress = { DE 2A 4F 18 } $hash_LoadLibraryA = { FA D0 59 11} $Calc_Func_resolve_ApiFuncs = {06 00 00 0F B6 11 48 FF C1 85 D2 74 14 44 8D 42} condition: ( $hash_NtFlushInstructionCache and $hash_VirtualAlloc and $hash_GetProcAddress and $hash_LoadLibraryA ) or ( $Calc_Func_resolve_ApiFuncs ) } |
ハンティングルール
- クエリの説明:次のXQLクエリは、RMMの実行につながるTeamsアプリケーションを経由して行われたフィッシング アクティビティを検索します。これらの属性は、攻撃者がAdaptixC2ビーコンをデプロイする際によく攻撃対象になります。
- 調査メモ:ユーザー セッション タイトルをチェックすることから始めます。RMMツールの実行と、RMMツールを使用した子プロセスまたはファイルの作成を確認します。侵害されたユーザー(actor_effective_username)によるcmdやPowerShellなどのアラートや不審な実行を探します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
config case_sensitive = false | dataset=xdr_data | fields _time as TeamsTime ,event_type,agent_hostname,actor_effective_username,event_sub_type, title, actor_process_image_name as teams_image_name, actor_process_image_sha256 , actor_process_image_command_line, agent_hostname, _time, action_process_image_name, agent_os_type, agent_id | filter agent_os_type = ENUM.AGENT_OS_WINDOWS and event_type = ENUM.USER_SESSION and teams_image_name in ("ms-teams.exe","updater.exe") and ((title contains "(external)" and title not contains "Chat |" ) and (title contains "help" )) | join type = inner ( dataset=xdr_data | fields _time as RmmStartTime ,agent_os_type , action_file_extension , event_type,agent_hostname,actor_effective_username,event_sub_type, actor_process_image_name , action_process_image_path, agent_hostname, action_process_image_name, agent_id, event_id | filter agent_os_type = ENUM.AGENT_OS_WINDOWS and (event_type=ENUM.PROCESS and event_sub_type = ENUM.PROCESS_START and action_process_image_name in ("*quickassist.exe","*anydesk.exe","*screenconnect.*.exe","*logmein.exe")) ) as rmm rmm.agent_id = agent_id and rmm.actor_effective_username = actor_effective_username and (timestamp_diff(rmm.RmmStartTime,TeamsTime , "MINUTE") < 10 and timestamp_diff(rmm.RmmStartTime,TeamsTime , "MINUTE") >= 0) | comp values(TeamsTime) as _time ,values(RmmStartTime) as RmmStartTime, values(teams_image_name) as teams_image_name, values(action_process_image_path) as action_process_image_name, values(actor_process_image_name) as ActorProcess, count(Title) as CountOfTitle by title,actor_effective_username,agent_hostname , agent_id, event_id | filter (array_length(action_process_image_name)>0) |
設定抽出器の例
次のコードは、HTTPビーコン ファイルから設定を抽出する設定抽出器の例です。
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
import struct import json import sys from typing import Dict, Any from malduck import procmempe, rc4, int32, enhex class ConfigParser: def __init__(self, data: bytes): self.data = data self.offset = 0 def unpack32(self) -> int: value = struct.unpack('<I', self.data[self.offset:self.offset + 4])[0] self.offset += 4 return value def unpack16(self) -> int: """Unpack a 16-bit unsigned integer (little-endian)""" value = struct.unpack('<H', self.data[self.offset:self.offset + 2])[0] self.offset += 2 return value def unpack8(self) -> int: """Unpack an 8-bit unsigned integer""" value = self.data[self.offset] self.offset += 1 return value def unpack_string(self) -> str: """Unpack a length-prefixed string""" length = self.unpack32() string_data = self.data[self.offset:self.offset + length] self.offset += length if string_data and string_data[-1] == 0: string_data = string_data[:-1] return string_data.decode('utf-8', errors='replace') def unpack_bytes(self, length: int) -> bytes: """Unpack a fixed number of bytes""" data = self.data[self.offset:self.offset + length] self.offset += length return data def parse_beacon_http_config(data: bytes) -> Dict[str, Any]: """Parse BEACON_HTTP configuration from raw bytes""" parser = ConfigParser(data) config = {} try: # Parse agent type config['agent_type'] = parser.unpack32() # Parse HTTP profile config['use_ssl'] = bool(parser.unpack8()) config['servers_count'] = parser.unpack32() # Parse servers and ports config['servers'] = [] config['ports'] = [] for i in range(config['servers_count']): server = parser.unpack_string() port = parser.unpack32() config['servers'].append(server) config['ports'].append(port) # Parse HTTP settings config['http_method'] = parser.unpack_string() config['uri'] = parser.unpack_string() config['parameter'] = parser.unpack_string() config['user_agent'] = parser.unpack_string() config['http_headers'] = parser.unpack_string() # Parse answer sizes config['ans_pre_size'] = parser.unpack32() ans_size_raw = parser.unpack32() config['ans_size'] = ans_size_raw + config['ans_pre_size'] # Parse timing settings config['kill_date'] = parser.unpack32() config['working_time'] = parser.unpack32() config['sleep_delay'] = parser.unpack32() config['jitter_delay'] = parser.unpack32() # Default values from constructor config['listener_type'] = 0 config['download_chunk_size'] = 0x19000 return config except Exception as e: print(f"Failed to parse configuration: {e}") raise def parse_config(data: bytes, beacon_type: str = "BEACON_HTTP") -> Dict[str, Any]: """Main entry point for parsing beacon configurations""" if beacon_type == "BEACON_HTTP": return parse_beacon_http_config(data) else: raise NotImplementedError(f"Parser for {beacon_type} not implemented") if __name__ == "__main__": if len(sys.argv) < 2: print("Usage: python extractor.py <path_to_config_file>") sys.exit(1) passed_arg = sys.argv[1] try: sample = procmempe.from_file(passed_arg) rdata_section = sample.pe.section(".rdata") config_structure = sample.readp(rdata_section.PointerToRawData, rdata_section.SizeOfRawData) config_size = int32(config_structure) encrypted_config = config_structure[4:config_size+4] rc4_key = config_structure[config_size + 4 : config_size + 4 + 16] except Exception as e: print(f"Error reading file or extracting configuration: {e}") print("Using provided encrypted configuration bytes directly.") try: config_structure = bytes.fromhex(passed_arg) config_size = int32(config_structure) encrypted_config = config_structure[4:config_size+4] rc4_key = config_structure[config_size + 4 : config_size + 4 + 16] except Exception as e: print(f"Failed to process provided argument as configuration bytes: {e}") sys.exit(1) try: decrypted_config = rc4(rc4_key, encrypted_config) print(f"Decrypted configuration size: {len(decrypted_config)} bytes") print(f"Decrypted configuration content: {decrypted_config}") print("Decrypted configuration (hex): %s", enhex(decrypted_config)) config = parse_config(decrypted_config) print("Parsed configuration:") print(json.dumps(config, indent=2)) except Exception as e: print(f"Error parsing configuration: {e}") |
その他の資料
- AdaptixC2- GitHub
- Fogランサムウェア:最近の攻撃で使用された珍しいツールセット- Symantec
- Unit 42インシデント レスポンス レポート(2025年版):ソーシャル エンジニアリング編 - Unit 42
- フィッシングとは - Palo Alto Networks
- RMMとは - ManageEngine
- ファイルレス マルウェア攻撃とは - Palo Alto Networks
- DLLハイジャックのテクニック - Unit 42
- Unit 42がエージェンティックAI攻撃フレームワークを開発 - Palo Alto Networks
- Marshal.GetDelegateForFunctionPointerメソッド - Microsoft Docs
- Invoke-RestMethod (PowerShell) - Microsoft Docs
- VirtualProtect関数 - Microsoft Docs
- メモリ保護定数 - Microsoft Docs
- MITRE ATT&CK T1547.001 - MITRE