Protect Against Russia-Ukraine Cyber Activity

Cobalt Strike解析&チュートリアル: Cobalt Strikeによるメタデータの暗号化と復号

A conceptual image representing malware and its evasions.

This post is also available in: English (英語)

概要

Cobalt Strikeは商用の脅威エミュレーションソフトウェアで、ネットワークに長期的にひそむアクターをエミュレートします。Beaconと呼ばれるこのアクターは外部TeamServerと通信してコマンド&コントロール(C2)トラフィックを模倣します。汎用性が高く、レッドチームの正規ツールとしてよく利用されますが、脅威アクターの実際の攻撃でも広く使用されています。この汎用性の高さはCobalt Strike にそなわる多くの機能に起因しています。たとえばC2サーバーへ送信するメタデータを暗号化・復号するプロセスなどがその例です。

以前のブログ「Cobalt Strike解析&チュートリアル: Cobalt Strikeによるメタデータのエンコードとデコード」では、暗号化されたメタデータがHTTPトランザクション用にエンコードされることを学びました。

Cobalt Strike Beaconは、Phone Home通信 (C2サーバーへの連絡通信)時に、RSAアルゴリズムの公開鍵でメタデータ(侵害システムに関する情報)を暗号化し、Cobalt Strike TeamServerに送信します。TeamServerは秘密鍵を使ってBeaconの平文メタデータを復元し、Beaconクライアントを識別します。また復号されたメタデータからはAESの共通鍵を抽出可能です。クライアントとサーバーはこのAES鍵を使ってその後のリクエストデータやレスポンスデータの暗号化と復号を行い、C2トラフィック通信を終了します。

本稿では、データの暗号化・復号アルゴリズム、鍵の生成・抽出、メタデータの暗号化・復号、メタデータのスキーマ定義の詳細説明とデモを行います。また、C2トラフィック通信で暗号化・復号アルゴリズムがどのように機能するかを示し、なぜ汎用性が高いとCobalt Strikeがエミュレータとして有効で、防御が難しくなってしまうのかについても示します。ここが本稿でもとりわけ興味深い部分のひとつでしょう。

Unit 42の関連トピック Cobalt Strike, C2, Tutorials

目次

データ暗号化・復号アルゴリズム
メタデータのスキーマ定義
公開鍵/秘密鍵の生成・抽出
RSAとAESによるC2メタデータの暗号化/復号の一例
結論
IoC
追加リソース

データ暗号化・復号アルゴリズム

Cobalt Strike Beaconは、TeamServerと通信するさい、共通鍵暗号(AES)と公開鍵暗号(RSA)の暗号アルゴリズムを組み合わせて使用します。その後、TeamServerが新たな公開鍵と秘密鍵のペアを生成し、この鍵ペアを.cobaltstrike.beacon_keysファイルに格納します。このファイルはCobalt Strikeのsetupの解凍先ディレクトリと同じディレクトリに格納されます。ファイルがすでに存在する場合は同じキーペアが使われます。

公開鍵暗号アルゴリズムはRSA/ECB/PKCS1Padding方式、共通鍵アルゴリズムはAES/CBC/NoPadding方式でデータの暗号化/復号を行います。AESアルゴリズムは、ハードコードされた初期化ベクトル(IV)で初期化されます。この静的IVはabcdefghijklmnopです。

図1はCobalt Strike BeaconとTeamServerとの間のC2トラフィックを示しています。

この図は、Beaconプロセス(左)とTeamServer(右)の間の通信の流れの詳細を示しています。この通信では、BeaconプロセスがGETトランザクション経由でRSAで暗号化したメタデータを送信し、AESで暗号化されたタスクを受信する様子が確認できます。また、BeaconプロセスがTeamServerにAESで暗号化されたタスクの結果を送信し、その応答を受信して破棄する様子も確認できます。
図1. C2 BeaconプロセスとTeamServerの間の通信

メタデータのスキーマ定義

メタデータはその名が示す通り標的に関する情報を含んでいます。メタデータは先頭に4バイトのマジックナンバー(0xBEEF)をもつ構造化されたフォーマットになっています。図2にメタデータの構造を示します。

Beaconのメタデータ構造には、図のようなヘッダ、データフィールドのサイズを示すひと続きのバイト、最後に復号されたデータそのものが含まれています。
図2. Beaconのメタデータ構造

復号されたデータはさまざまな情報のかたまり(Blob)になっています。復号されたBlobの構造はCobalt Strikeのバージョン4.0で更新されており、Beaconはメタデータにさらに多くの情報を追加しています。データフィールドのサイズは4バイトで、これは作者が将来的にメタデータの構造を更新する可能性を示唆しています。図3は、メタデータに詰め込まれているさまざまな情報の種類を示したものです。この構成は現在の実装に準じています。

Cobalt Strikeのメタデータスキーマをマッピングした図。ヘッダ、データサイズフィールド、ANSI文字セット、OEM文字セット、BeaconID、プロセスID、ポート、フラグ、バージョン番号、ビルドバージョン、4バイトのプレフィックス、標的のIPアドレス、 \t (タブ)で区切られたデータ、 GetModuleHandleA や GetProcAddress へのポインタなどが含まれている。
図3. メタデータのスキーマ

以下、復号されたデータの各データフィールドの内訳を順に説明します。

  • 最初の16バイトはBeaconが生成するランダムバイトで、各実行プロセスに固有です。BeaconとTeamServerはこの16バイトからAES鍵とHMAC鍵を生成します。プロセスはこれら16バイトのSHA256ハッシュを計算します。SHA256ハッシュの最初の16バイトが共通暗号のAES鍵として割り当てられ、残りの16バイトがメッセージ認証コード用のHMAC鍵になります。
  • 次のリトルエンディアンの2バイトはANSI文字セットとしてデコードされます。文字セットの全リストについてはコードページ識別子に関するドキュメントを参照してください。
  • その次のリトルエンディアン2バイトはOEM文字セットに割り当てられています。
  • 4バイトのビッグエンディアンはBeacon IDで、各Beaconには一意なIDが与えられます。
  • 4バイトのビッグエンディアンは被害マシン上で稼働するBeaconのプロセスIDです。
  • 2バイトはポートとしてデコードされます。
  • 1バイトはフラグとしてデコードされます。現在のCobalt Strikeの実装では、このフラグの値でBeaconのアーキテクチャ(32ビット/64ビット)を設定しています。
  • 2バイトがBeaconのバージョン番号です。これらのバイトは間に「.」を挿入した文字列に変換されます。例: A.B
  • 2バイトはBeaconのビルドバージョンとしてデコードされます。
  • 次の4バイトのビッグエンディアンの値は関数へのポインタをプレフィクスするのに使用されます(Beaconのアーキテクチャが64ビットの場合)。これら4バイトは32ビットアーキテクチャの場合は破棄されます。
  • 続く2つの4バイト値はGetModuleHandleAGetProcAddressへのポインタです。これらの値を使うことでシェルコードは明示的にインポートされていない関数を解決できるようになります。Beaconが64ビットの場合は先の値にプレフィクスを付けた結果の値全体が変数に格納されます。
  • 次の4バイトは標的のIPアドレスです。これらのバイトは後でIPv4として読み取り可能なアドレスに変換されます。
  • 最後のバイト列はUTF-8で、この値は「\t」で区切られます。現バージョンではこのデータは「ComputerName\tUserName\tBeaconProcessName」という構造になっています。

公開鍵/秘密鍵の生成・抽出

Beaconはチェックインするさい、RSA公開鍵で暗号化したメタデータのBlobをTeamServerに送信します。TeamServerはこれを秘密鍵で復号して平文のメタデータを復元し、この後の通信で使うほかのメタデータとAES鍵とを抽出します。AES鍵は解読が極めて困難な公開鍵暗号で暗号化されているので、これでMitM攻撃(中間者攻撃)や検出を回避できます。さらに、C2通信は共通鍵で暗号化されるのでマーカーに使えるフィンガープリントを見つけるのが難しくなります。

プロファイルをロードして起動したTeamServerは、公開鍵と秘密鍵の鍵ペアを生成し、それらをTeamServerのルートディレクトリの.cobaltstrike.beacon_keysファイルに格納します(ファイルが存在しない場合)。

この公開鍵/秘密鍵は、GitHubで共有されている鍵をダンプするJavaプログラムを使うと抽出できます。その方法を以下に示します。

1. 公開鍵/秘密鍵ペアは.cobaltstrike.beacon_keysjava.security.KeyPairオブジェクトとして格納されています(図4参照)。

公開鍵/秘密鍵ペアは.cobaltstrike.beacon_keysにjava.security.KeyPairオブジェクトとして格納されています。
図4. 公開鍵/秘密鍵ペアのJavaオブジェクト

2. TeamServerのルートディレクトリで図5のJavaプログラムをコンパイルして実行すると、公開鍵/秘密鍵のペアがbase64でエンコードされます。

TeamServerのルートディレクトリでこの図のJavaプログラムをコンパイルして実行すると、公開鍵/秘密鍵のペアがbase64でエンコードされます。
図5. 公開鍵/秘密鍵

RSAとAESによるC2メタデータの暗号化/復号の一例

以下に例をあげ、Cobalt Strike BeaconのメタデータやC2のHTTPトラフィック通信のコンテキストでの暗号化・復号がどのように機能するかを説明します。

この分析ではVirusTotalから直接ダウンロード可能な実サンプル(SHA256:50ea11254f184450a7351d407fbb53c54686ce1e62e99c0a41e7e3e505d60c)を使います。

このサンプルのC2トラフィック分析は次の3つのセクションに分かれます。

  1. Cobalt Strike Beaconのダウンロード
  2. C2 Beaconハートビート
  3. C2のタスクリクエストとレスポンス(コールバック)

これら3つのセクションでは暗号化/復号の分析により次のプロセスを説明しています。

  1. RSA公開鍵と漏えいした秘密鍵を使ってメタデータを復号し、AES鍵とHMAC鍵を取得する
  2. AES鍵を使ってHTTP GETレスポンス内の暗号化されたタスクデータを復号する
  3. AES鍵を使ってHTTP POSTリクエストボディ内のタスク実行結果を復号する

Cobalt Strike Beaconのダウンロード

このスクリーンショットはBeaconのダウンロードのWireshark pcapです。
図6. Beaconのダウンロード

1768.pyというスクリプトで設定をパースすると、このBeaconはRSA秘密鍵が漏えいしたバージョンのCobalt Strikeソフトウェアで生成されていることがわかります。

このスクリーンショットはこのBeaconがあるバージョンのCobalt Strikeで生成されたことを示しています。
図7 Beaconのパースと秘密鍵の検索

C2 Beaconハートビート

Beaconのダウンロードと実行後はTeamServerへのC2チェックインが行われ、HTTPリクエストのCookieに感染マシンに関する暗号化されたメタデータ情報が漏出されます。

このスクリーンショットはWiresharkのpcapです。Beaconのダウンロードと実行後はTeamServerへのC2チェックインが行われ、HTTPリクエストのCookieに感染マシンに関する暗号化されたメタデータ情報が漏出されます。
図8 C2 ハートビート

cs-crypto-parser.pyスクリプト(cs-mitm.pyスクリプトを若干修正したバージョン)を実行してメタデータ情報を復号します。このさいCookieからの値(XjaoBxbLchqKBL/s/m8Pgz/wHRbx660/2Aa8Toa9T/AJ0Ns8mgjPBWdYIL9mEFM1DE/5GXGCSURf6RP+wxo5Zx0G/yENlMTuzPaCO11/XPNxRj69Nf6++05qe7iMKfg8D4ZFGiEQAVo6UXqUteZlAqubJ+uNZBglsyioa+aSQw=)を第一引数として渡す必要があります。

RSAの復号

このスクリプトが実行する最初のタスクはパラメータを2つ受け取るRSADecrypt()関数の呼び出しです。1つめのパラメータは秘密鍵、2つめのパラメータは暗号化されたCookieの値です。このタスクが完了するとRSA秘密鍵をデコードしてインポートし、新たなPKCS1オブジェクトをインスタンス化します。最後にこのスクリプトはdecrypt関数を呼び出し、暗号化されたデータ変数を引数としてこの関数に渡し、暗号文の復号を実行します。

2 つのパラメータを受け取るRSADecrypt()関数のスクリーンショット。1つめのパラメータは秘密鍵、2つめのパラメータは暗号化されたCookieの値。
図9 RSADecrypt()関数

出力結果としてメタデータの詳細な内訳が16進数値とともに表示されます。

出力結果としてメタデータの詳細な内訳が16進数値とともに表示されます。
図10 C2の復号したメタデータ

復号されたメタデータの構造については本稿の「メタデータのスキーマ定義」セクションを参考にしてください。

C2のタスクリクエストとレスポンス(コールバック)

AES鍵とHMAC鍵

ペイロードはCBCモードのAES-256暗号にHMAC-SHA-256鍵付きハッシュアルゴリズムを指定して暗号化されます。RSA秘密鍵や復号されたデータへのアクセスがあるのでこれには生の鍵も含まれます。この鍵は16バイトで、復号されたペイロードの8バイト目に位置しています。このマルウェアサンプルの場合、鍵は1a 13 7e 76 f9 15 6a 67 f9 99 af d6 57 64 75 bdです(16進数表記)。AES鍵とHMAC鍵を生成するため生の鍵からSHA256ハッシュが計算されますが、計算された結果は、前半(16バイト)が実際のAES鍵で後半(16バイト)がHMAC鍵になります。下の図11はcrypto-parserスクリプトを実行したさいの計算の様子を示したものです。

黄色の矩形でこのマルウェアサンプルに含まれるSHA-256ダイジェストをハイライト表示しています。赤で囲った部分がAES鍵で青で囲った部分がHMAC鍵です。これら2つを合わせてメタデータの暗号化・復号のハッシュと鍵を構成しています。
図11 暗号化/復号のハッシュと鍵

C2タスクリクエスト

C2チャンネルが確立されてチェックインが行われると、Beaconはチェックや新しいタスクの実行を行います。図12は、タスクリクエストがTeamServerからのレスポンスペイロードを受信した様子を示しています。

このWiresharkのスクリーンショットは、HTTP GETのレスポンスを示しています。
図12. C2のタスクリクエスト(取得)

ここで48バイトのペイロードデータをスクリプトに渡して復号します。暗号化されたBlobの最後の16バイトはHMAC Signatureで、これがリクエストの完全性の基準として用いられます。図13は、タスクペイロードのデータをパースして復号したものです。

タスクペイロードのデータをパースして復号したものを表示HMAC Signatureは黄色の枠で囲われた部分
図13. Cobalt Strikeのタスク リクエスト ペイロードの復号

復号処理を担っているのがDecrypt()関数で、この関数が以下の処理を行います。

  1. 暗号化されたデータをパラメータとして受け取る
  2. 暗号化されたペイロードからHMAC Signatureを抽出する
  3. 暗号化されたペイロードのHMAC鍵を使ってHMAC Signatureを計算・検証する
  4. AES鍵をロードしてモード(CBC)と初期化ベクトル(IV)を設定する
  5. 暗号化されたペイロードを復号する
Decrypt()関数の内容。この関数は暗号化されたデータをパラメータとして受け取り、暗号化されたペイロードからHMAC Signatureを抽出し、暗号化されたペイロードにHMAC鍵を用いてHMAC Signatureを計算・検証し、AES鍵をロードしてモードとその初期化ベクトルを設定し、暗号化ペイロードを復号する。
図14 AES/HMAC復号関数

C2タスクレスポンス

BeaconがC2サーバーからのタスクを受けとって実行すると、その結果が収集されてTeamServerに返されます。

HTTP POSTリクエストのWiresharkスクリーンショット
図15. Cobalt Strikeのタスクレスポンス(データの漏出)

上記と同じDecrypt()関数を使って暗号化されたペイロードが提供されます。ただし、Cobalt Strikeのタスクレスポンスでは最初の4バイトが復号対象にならず、関数に渡されるデータからはこれら4バイトが除外されます。

Cobalt Strikeのタスクレスポンス。カウンタを青、データサイズを黄、タイプを赤、タスクデータをオレンジで囲って示す。
図16. Cobalt Strikeのタスクレスポンスの復号

このリクエストに含まれるタスクデータのレスポンスは、ASCII文字列BOBSPC\\Administratorで、感染したコンピュータのマシン名とユーザー名を表しています。

結論

Cobalt Strikeは侵害後のアクターをエミュレートする強力なツールです。先に説明したメタデータの暗号化・復号は巧妙で、セキュリティ検出回避をねらって設計されています。セキュリティアプライアンス単体ではCobalt Strikeの攻撃を防げないので、ファイアウォール、サンドボックス、エンドポイント、さらにこれらすべての要素を統合してくれるソフトウェアのセキュリティソリューションを組み合わせて使うことが必要になります。

パロアルトネットワークスのお客様は、本稿で説明したCobalt Strikeの攻撃同様の攻撃から次の方法で保護されています。

  1. 脅威防御シグネチャ86445と86446を含む次世代ファイアウォール(NGFW)は、デフォルトプロファイルのBase64メタデータエンコードを行うHTTP C2リクエストを識別します。Advanced Threat Preventionには、シグネチャに頼らずにこれらの攻撃を検知する新機能があります。
  2. NGFW用セキュリティサブスクリプションWildFireCortex XDRはCobalt Strike Beaconを識別・ブロックします。
  3. AutoFocusをお使いのお客様は次のタグを使用してこれらのアクティビティを追跡できます: CobaltStrike

IoC

Cobalt Strikeのサンプル

  • 50ea11254f184450a7351d407fbb53c54686ce1e62e99c0a41ee7ee3e505d60c

Cobalt Strike Beaconのサンプル

  • /lNj8
    • SHA256ハッシュ:
      • e712d670382ad6f837feeb5a66adb2d0f133481b5db854de0dd4636d7e906a8e

Cobalt Strike TeamServerのIPアドレス

  • 92.255.85[.]93

追加リソース

Cobalt Strike Training (Cobalt Strikeトレーニング)
Cobalt Strike Malleable C2 Profile (Cobalt Strike Malleable C2プロファイル)
Cobalt Strike Decryption with Known Private Key (Cobalt Strikeを既知の秘密鍵で復号する)
Cobalt Strike解析&チュートリアル: Malleable C2プロファイルでCobalt Strike検出が難しくなる理由
Cobalt Strike解析&チュートリアル: Cobalt Strikeによるメタデータのエンコードとデコード