
Cobalt Strike用のカスタムC2チャンネルを、リフレクティブローダーによって適用されるIATフックを使用して開発するためのテンプレート。
これは、リフレクティブローダーによって適用されるIATフックを使用して、Cobalt Strike用のカスタムC2チャネルを開発するためのシンプルなPoCおよびテンプレートです。
ブログ記事: https://codex-7.gitbook.io/codexs-terminal-window/red-team/cobalt-strike/building-custom-c2-channels-by-hooking-wininet
TCPチャネルのデモGIF

customCallback.h、hook.c、hash.h および hook.h ファイルは大まかなテンプレートですが、PoCとしてそのまま Crystal kit にドロップして使用できます。それらを udrl/src フォルダに配置し、既存のコピーを置き換えてください。tcg.h は変更されていません(Raphael Mudge の tradecraft garden 由来)。
examples/ フォルダ内の例はそのまま使用できますが、これらは例であり、作成時に運用上の考慮は行われていません。注意して使用してください。
現在の例は次のとおりです:
Crystal kit のオリジナルの回避機能(Draugr 実装やスリープマスキングなど)は、このコードベースをクリーンで移植可能に保つために hook.c から削除されていることに注意してください。それらの機能を維持したい場合は、Crystal kit のオリジナルコピーから戻すことができます。
beacon DLL を生成する際には、使用する http ライブラリとして適切な http ライブラリ winhttp/wininet を選択する必要があります。
このテンプレートのテストに使用された Malleable C2 プロファイルはリポジトリに提供されています。理論上、(ほとんどの)他の Malleable C2 プロファイルでも動作するはずですが、このテンプレートはこのプロファイル(GraphStrike から取得)を使用してテストされました。
公式の ExternalC2 インターフェースは使い勝手が悪いものです。ExternalC2 チャネル経由で SMB beacon のステージングが必要であり、(4.10 までは)先に ExternalC2 エージェントを介してステージングを行わないと、既製の SMB beacon との通信をサポートしていませんでした。現在の状態でも、依然として次のアーキテクチャに縛られています:
smb beacon --named pipe--> externalc2 agent --custom channel--> externalc2 handler --> teamserver
はい、Cobalt Strike 4.12 で UDC2 が追加されたことは認識しています。これは、その機能を UDRL で再現するための単なる楽しい実験です。
コンセプトは単純です。コールバックに使用される WinAPI をフックできれば、コールバックに必要なすべてのデータをすでに持っていることになります。カスタム C2 チャネルを実装するこの方法は、GraphStrike に見られるように、すでに過去に行われています。
ただし、GraphStrike の実装は依然として HTTP プロトコル自体にかなり依存しています。このリポジトリの目的は、周囲のコードをほとんど変更せずに、HTTP またはその他の任意のカスタムチャネルを実装するための、使いやすく修正・拡張が容易なテンプレートを提供することです。
このテンプレートは明らかにデフォルト状態での使用を意図していないため、選択した C2 チャネルを実装するには、以下を変更する必要があります:
customCallback 関数が次のことを行うように変更します:
引数を使用して、http リクエストの元のホストとポート(Cobalt から設定したもの)を利用できます:
const char *host
INTERNET_PORT port
そして、broker.py の handleCallback() 関数を次のことを行うように変更します:
これだけです。
例として、customCallback.h 内の customCallback() 関数にある PoC は現在次のことを行います:
broker.py の handleCallback 関数にある PoC は現在次のことを行います:
process_encoded_request(encoded_request) を呼び出すusage: broker.py [-h] --host HOST --port PORT
ここで、host と port はチームサーバー上の http リスナーを指します。ブローカーは http リクエストを解析し、実際のリスナーに送信します。
これはおそらく私がやった中で最も「怠惰な」方法ですが、最も安定した方法の1つでもあります。基本的には、HTTP リクエスト全体をラップして、どのような方法でもブローカーに送るだけです。ブローカーはそれを実際にチームサーバーに送信し、HTTP beacon として実行します。これはチームサーバーからは完全に透過的です。
(技術的には)よりクリーンな実装も試しました。それは、最低限の Malleable C2 プロファイル(実際には graphstrike のものを使いました)を使用し、wininet フック自体の中で malleable 仕様に従って異なる beacon データコンポーネント(id、metadata、output など)を解析するというものでした。これによりコールバックブロブのサイズはわずかに小さくなっていたでしょう。しかし、この実装は、リクエスト解析によってコードベースが不必要に複雑になり、またその特定のプロファイルの使用(それほど大した問題ではないですが、かなりハッキーです)が必要だったため、断念されました。
この実装の方が優れていると感じました。ハッキーな malleable プロファイルへの依存が少なく(技術的には、beacon のレスポンス出力をレスポンスボディで送信する必要はまだありますが、それが唯一の要件です)、コードが10倍読みやすかったからです。
また、http リクエスト JSON には base64 エンコーディング以外の難読化や暗号化はないことも注目に値します。独自のものを追加してもかまいませんが、Beacon のコールバックはすでに暗号化されているため、技術的にはデータが復号される危険性はありません。最悪の場合、取得された base64 ブロブが HTTP リクエストとして識別される可能性があるだけです。その情報をどう使うかはあなた次第です。
はい、コードとコメントの一部を書くのに LLM を使用しました。誰もドキュメントを書いたり、C でボイラープレートの JSON パーサーをゼロから書いたりするのは好きではありません。訴えてください。
通常の免責事項です。この出来の悪いコードを使用して引き起こす可能性のある、人道に対する罪や核戦争について、私は一切の責任を負いません。