
Python api for usage with cobalt strike's External C2 specification
フレームワーク間でデータを転送するためのインターフェースを構築・利用するためのPythonフレームワークです。特に、Command and Control(C2)フレームワークの拡張として機能することに重点を置いています。
現在のところ、これは この仕様書 に記載されている Cobalt Strike の External C2 仕様の実装のみを目的としていますが、プロジェクトの成熟に伴い変更される可能性があります。
このプロジェクトは、xychix の多大なる貢献によるものです。彼らの貴重な貢献なしには、このプロジェクトはまったく実現し得ませんでした。基本的に、このプロジェクトは Outflank の External C2 プロジェクト の再構築と拡張です。
このプロジェクトは、以下の主要な部分で構成されています。
Builder は設定ファイルを読み込み、skeletons 内の markers を置き換えることで、設定されたオプションを使用してビルドを生成します。
Builder は build_files.py で使用できます。サンプルのビルダー設定として sample_builder_config.config.sample が提供されています。
skeletons は、builder が動的に埋め込んで完全に使用可能なビルドを生成する、さまざまなコードの「スケルトン」です。skeletons には、builder によって使用可能な値に置き換えられる markers が含まれています。スケルトンには3つの異なる「タイプ」があります。
マーカーは skeleton 内の任意のファイルに配置でき、ビルダー設定で指定された値に置き換えられます。ベストプラクティスとして、マーカーを変数を直接書き込むために使用すべきではなく、値の設定にのみ使用すべきです。マーカーの値を再利用する必要がある場合は、同じマーカーを再利用するのではなく、値を変数に格納してその変数を参照する方を選ぶべきです。
マーカーの形式は次のとおりです: ```[var:::identifier_for_the_marker]```
文字列は一重引用符で囲まれて skeleton に直接書き込まれ、数値はそのまま書き込まれます。
設定内の文字列が二重引用符で囲まれている場合は、文字列は一重引用符の代わりに二重引用符で囲まれてファイルに直接書き込まれ、周囲の一重引用符は削除されます。
この関係は次のように示せます:
#################
# Skeleton Code #
#################
# Skeleton contains the following line of code:
foo = ```[var:::bar]```
##############
# End Result #
##############
# Stored in config as:
# foo = bar
# Written as:
foo = 'bar'
# Stored in config as:
# foo = "bar"
# Written as:
foo = "bar"
# Stored in config as:
# foo = 2
# Written as:
foo = 2
# Stored in config as:
# foo = "2"
# Written as:
foo = "2"
Frameworks は、transport と encoder によって使用されるデータと、そのデータの使用方法を決定する基本アプリケーションです。特定の framework が実際に何をするかは、encoder と transport をインポートして使用するロジックが存在する限り、あまり重要ではありません。フレームワークの主要部分(主に client ロジック)のほとんどは skeleton として保存され、そのサーバー部分と対話するためのインターフェースは基本 framework オブジェクトとして保存されます。
一般的に、framework には server と client が含まれ、それらの間でデータを中継するために encoders と transports を利用します。
framework を構築する際に考慮すべき基本事項がいくつかあります:
framework は、encoder が transport で使用できるようにする責任があります。framework がクライアント・サーバー関係を使用する場合、それに応じて適切に構成する必要があります。client を直接操作することはないことを理解してください。したがって、client で再設定可能にしたい場合は、直接操作なしで実行時にそれを実行できる必要があります。server を直接操作するため、server の skeleton を作成する必要性はほとんどありません。代わりに、設定からオプションを読み取るとともに、エンドユーザーが実行時にオプション(ブロックタイマーや冗長性など)を変更できるようにすることを選択してください。framework のスケルトンはビルダーによって処理され、その中のすべてのファイルを反復処理するため、特定の引数をビルド時に設定可能にする必要がある場合、簡単に実行できます。framework の server は、共通の framework_manager によってインターフェースできる必要があります。サーバーは、client と c2 server の間の通信を仲介するアプリケーションです。サーバーロジックは主に静的です。cobalt_strike フレームワークのサーバーのロジック(仕様書では third-party Client Controller と呼ばれます)は以下のとおりです:
encoder モジュールでステージャをエンコードするtransport モジュールでステージャを転送するtransport を介して受信したクライアントからのメタデータ応答を待つencoder モジュールでメタデータをデコードするtransport を介して新しいタスクをクライアントへ中継するtransport を介して受信したクライアントからの応答を受け取るencoder モジュールで応答をデコードするserver は複数のクライアントを処理する機能をサポートし(未実装)、framework_manager によってインターフェースされる必要があります。
クライアントは、基本的にはエンドポイント上で実行されるペイロードです。cobalt_strike フレームワークのクライアントのロジックは主に静的で、以下のとおりです:
transport を利用するために必要な準備を実行するtransport を介してビーコンから C2 サーバーへメタデータを中継するtransport を監視するtransport を介してビーコンからの応答を中継するクライアントは、指定された encoder と transport を使用して、自身と対応する server との間でデータを中継します。
Encoders はデータを受け取り、そのデータをトランスポートを介して送信するために準備するか、トランスポートを介して受信したデータを、それを利用している framework コンポーネントが解釈できる生の形式にデコードするために変更します。
Encoders は、トランスポートによって直接インターフェースされることを想定し、フレームワークやコンポーネントに依存しない方法でデータを処理する必要があります。
Transports は、通信チャネルを介してデータを送受信し、データが必要な形式に変換されるように encoder とインターフェースする役割を担います。Transports は、フレームワークコンポーネントから、または通信チャネルを介してデータを受け取り、通信チャネルを介してデータを中継する機能を持つことを想定しています。Transports は、必要に応じて encoder を呼び出してデータをエンコードまたはデコードする責任があります。
Transports は、framework コンポーネントによって直接インターフェースされることを想定し、フレームワークやコンポーネントに依存しない方法でデータを処理する必要があります。
まず、使用するトランスポートモジュールとエンコードモジュールを決定します。以下の例では、transport_imgur と encoder_lsbjpg を使用します。
次に、ニーズに合わせて builder_config.config を作成します。その方法については、提供されているサンプル設定とテンプレートを参照してください。
build_files.py でビルドを生成します。例として、Cobalt Strike 向けに encoder_lsbjpg と transport_imgur を使用して、builds ディレクトリにビルドを冗長モードで生成するには、次のコマンドを使用します:
python build_files.py -b builds -f cobalt_strike -c sample_builder_config.config.sample -e encoder_lsbjpg -t transport_imgur -v
サーバーを実行しているマシン上で、次を実行します:
python server.py
より詳細な出力を得るには、次を実行できます:
python server.py -v
さらに詳細な出力とデバッグに役立つ追加出力を得るには、次を実行できます:
python server.py -d
次に、対象のエンドポイント上でクライアントを実行します。
すべてが機能した場合、Cobalt Strike コンソール内に新しいビーコンが登録され、操作できるようになります。
なぜこれを書いたのか?: Cobalt Strike 仕様の実装はあまり公開されておらず、公開されているものも、私が使い慣れた言語ではないか、私が求めていたモジュール性と抽象化を備えていないかのどちらかでした。
なぜ Python 2 なのか?: 私が怠け者で、新しいトランスポートやエンコーディングチャネルを実装するのが簡単だからです。
あなたのコードはひどい: それは質問ではありません。
新しいトランスポートやエンコーダーモジュールを提出できますか?: ぜひお願いします! プルリクエストを送っていただければ、喜んでレビューします。
クライアントを配布可能な実行ファイルにコンパイルするにはどうすればよいですか?:
私は Kali でこれを正常にテストしました。私の環境を再現するには、veil-evasion がインストールされ、そのセットアップを完了していることを確認してください。必要な依存関係をすべて備えた Python がインストールされた wine 環境がセットアップされているはずです。この環境に pefile モジュールもインストールする必要があるかもしれません。
次に、実行ファイルを生成したいクライアントのディレクトリに移動して、次を実行します:
chmod +x compile_dll.sh
./compile_dll.sh
wine "C:\\Python27\\python.exe" /usr/share/veil/pyinstaller/pyinstaller.py -F -r c2file.dll -w --key "ayyyyyyylmao" client.py
key の値は任意のものに置き換えてください。dist/ ディレクトリにクライアントの実行ファイルが表示されるはずです。デバッグに使用できるコンソールを提供する実行ファイルを生成したい場合は、次のコマンドでコンパイルしてください: wine "C:\\Python27\\python.exe" /usr/share/veil/pyinstaller/pyinstaller.py -F -r c2file.dll -c client.py