ラック・セキュリティごった煮ブログ

セキュリティエンジニアがエンジニアの方に向けて、 セキュリティやIT技術に関する情報を発信していくアカウントです。

【お知らせ】2021年5月10日~リニューアルオープン!今後はこちらで新しい記事を公開します。

株式会社ラックのセキュリティエンジニアが、 エンジニアの方向けにセキュリティやIT技術に関する情報を発信するブログです。
(編集:株式会社ラック・デジタルペンテスト部)

Covenant と C3 を連携して、Slackを使ったC2通信を行う

※こちらの記事は2020年9月28日公開note版「ラック・セキュリティごった煮ブログ」と同じ内容です

デジタルペンテストサービス部のしゅーとです。

前回は Covenant を紹介しました。今回は Covenant の C2 チャンネルを増やすために C3 を連携し、Slack を使った C2 通信を試してみます。

※この記事は、「次世代C2フレームワーク、Covenantをはじめよう」の記事の続きです。前回記事をまだ読んでいない方はそちらを先にどうぞ。
devblog.lac.co.jp
※検証したC3のバージョンは 1.2.0、Covenantのバージョンは 0.6 です。

注意:本投稿で記述した手法を用いてトラブルなどが発生した場合、当社は一切の責任を負いかねます。本情報の悪用はしないでください。

・・・

本記事ではまず C2 チャンネルについておさらいしたあと、C3 の基本的な使い方を説明します。そのあとに Covenant との連携方法を紹介します。

C2 チャンネルについて

Red Teaming にとって、外部からエージェントを遠隔操作するため、いかにファイアウォールや IDS を回避するかが重要です。ネットワークによっては URL フィルタリングでカテゴライズされていないサイトへの通信を弾く場合もあるので大変です。

URL フィルタリングの回避には、CDN を用いたドメインフロンティング手法が有名ですが、中でも特定のクラウドサービスをC2チャンネルとして利用する方法は原理上、通常の通信と見分けがつきません。そのためネットワークセキュリティ製品では非常に検知が難しいです。

C3 とは


C3 は、C2 チャンネルに特化したオープンソースの C2 フレームワークで、主に F-Secure のメンバーがメンテナンスしています。最近の攻撃者がクラウドサービスを用いた C2 通信をするようになっていることを受けて、Red Teaming でリアルな攻撃者を模倣できるように開発されました。各機能がモジュールとして分割され、新しく C2 チャンネルを実装しやすい設計になっています。

現時点の C3 では以下の C2 チャンネルが利用できます。

クラウドサービス
- Slack
- OneDrive
- Outlook
- Asana
- Dropbox
- Github

P2P (横展開用途)
- MSSQL
- UncShareFile

基本的に外部サーバとのやりとりは HTTP(s) を使ったクラウドサービスを利用することになります。このうち Slack は無料でワークスペースが作ることが可能で、誰でも簡単に試すことができます。

他にも C3 には複数ノード間でC2通信の経路を柔軟に決められたりするなどユニークな特徴を持っています。

上記2点の画像は C3 公式のチュートリアル記事から引用しました。F-Secure Labs にはクラウドサービスを利用した通信をどう見つけるかを C3 を使って学べるBlue Team向け記事もあるので要チェック。

ただ C3 にはいわゆる RAT の機能はなく、そういった機能は C3 の連携先である Cobalt Strike や Covenant を利用して実現します。

・・・

C3 のセットアップ

前置きはこのくらいにして、実際に C3 を試してみましょう。

C3 の Webサーバ・Web APIC# .NET Core を利用しているため、Linux 上でネイティブ動作します。ただ、C3のコア部を担当するGateway と、標的PCでエージェントとして実行される Relay は、C++ で記述された Windows バイナリです。 これらは Linux 環境でも wine64 を利用することで動作しますが、コンパイルには Visual Studio が必要です。

ダウンロード

gitコマンドでC3のソースコードを取得しましょう。

>git clone https://github.com/FSecureLABS/C3
Cloning into 'C3'...
remote: Enumerating objects: 935, done.
remote: Counting objects: 100% (935/935), done.
remote: Compressing objects: 100% (393/393), done.
remote: Total 4636 (delta 586), reused 827 (delta 533), pack-reused 3701Receiving objects:  99% (4590/4636), 35.
Receiving objects: 100% (4636/4636), 37.10 MiB | 5.95 MiB/s, done.
Resolving deltas: 100% (3044/3044), done.
Updating files: 100% (633/633), done.
Covenant連携のためのコード修正

2020年9月現在、Covenant の API が大幅にアップデートされた関係で、残念ながらオリジナルのコードでは動きません。C3、Covenant ともにコードの修正が必要です。

◆C3の修正
Src/Common/FSecure/C3/Interfaces/Connectors/Covenant.cpp を下記 URL を参考に修正します。
https://github.com/FSecureLABS/C3/pull/20/files

◆Covenantの修正
Covenant/Models/Launchers/Launcher.cs を修正します。 ファイルの Base64ILByteString プロパティの JsonIgnore 属性を削除すればOKです。

[NotMapped]
public string Base64ILByteString
{
(..snip..)

[NotMapped, JsonIgnore, System.Text.Json.Serialization.JsonIgnore]

[NotMapped]

※既に Covenant をセットアップしている場合は改めて dotnet build を実行してください。

コンパイル

MSBuild コマンドのパスが通っている 「Developer Command Prompt for VS 2019」 を実行してください。C3 のフォルダに移動し、CreateBuild.cmd を実行します。

>cd C:\Users\user\Documents\sec\pentest\c2framework\C3
>CreateBuild.cmd
Cleaning from temporary files...
(省略)
Done. Build C3-1.2.0 successfully created.

Done.
Press any button to continue...

コンパイルが完了すると、Buildsフォルダに実行ファイルが生成されます。

Webサーバの起動

Windows/Linux どちらも実行するコマンドは一緒です。Builds以下のC3フォルダにある WebController フォルダに移動し、以下のコマンドで起動します。

$ dotnet C3WebController.dll --urls http://localhost:52935/

※デフォルトURLが http://localhost:52935/ です。

WebUIのアクセス

Webブラウザにて、http://localhost:52935 にアクセスします。

Gateway のセットアップを促されます。好きな名前を入力して、「CREATE AND DOWNLOAD GATEWAY」をクリックし Gateway をダウンロード。ダウンロードされるzipファイルには、Gateway の実行ファイルと構成ファイルが含まれます。展開し、exeファイルを実行しましょう。

# Windows
> GatewayX64_kali.exe 

# Linux (wine)
$ wine64 GatewayX64_kali.exe 

実行すると、WebUI に Gateway のアイコンが表示されます。

Channelの作成

Gateway ができたら、次は Relay との橋渡し役となる C2チャンネル機能、 Channel の作成をしましょう。今回は Slack を Channel として設定します。

Slack Appの設定

下記の Qiita の記事を参考に App を作っておきましょう。
Slack Appの作り方について

権限は以下があれば大丈夫でした。(できなかったら権限を増やそう)

  • channels:history
  • channels:join
  • channels:manage
  • channels:read
  • chat:write
  • chat:write.public
  • files:read
  • files:write

App 作成後、ワークスペースに追加します。

追加後、App のアクセストークン情報を控えておきましょう。C3 の Gateway、Relay が Slack にアクセスするために必要です。

C3 のChannel設定

Gateway のアイコンをクリックし、「COMMAND CENTER」を選択します。次に Select Command から、AddNegotiationChannelSlack を選択します。

Channel 設定には Negotiation がついているものとついていないものがあります。 これらの違いは、1つの Channel で複数の Relay を接続可能か否かです。 Negotiation のものは一対多で接続可能です。非Negotiation は一対一でしか接続できません。通常は Negotiation のものを選んでおけば問題ないですが、Channel のレート制限などの関係で、非Negotiation のほうが都合がよいときがあるようです。

Identifier は適当でいいです。Slack tokenにアクセストークンを、Channel name にやりとりするための Slack チャンネル名を入れてください。指定したSlackチャンネルが存在しない場合は、 Channel によって自動的に作成されます。

SEND COMMAND を押すと、該当のSlackチャネルにAppが参加します。


Relayのセットアップ

いよいよ Relay のセットアップです。Relay は C3 のクライアントエージェントで、標的PCで実行させるものです。

前項で作成した Channel アイコンをクリックし、INTERFACE OPTIONS から「New Relay」を選択します。

Channel アイコンから New Relay を選択すれば、画面下部の Channel 設定欄は全て自動的に埋められているため特に入力することはありません。Relay の名前はお好みで。何も入力しなければ自動でつけられます。

「CREATE AND DOWNLOAD RELAY」をクリックすると、Relay の実行ファイルがダウンロードされます。これを標的PCへ転送し、実行してください。Relay が実行されると、Slack の当該チャンネルで何やら怪しい動きが起きます。(gif)

これは、Slack(Channel) を通して Gateway とやりとりを行っているのです。タスクごとにメッセージスレッドが建てられ、リクエスト・レスポンスがツリーの返信の形で行われます。 やりとりが完了するとログが自動的に消える仕組みになっています。

以下が接続完了後のC3の WebUI です。Gateway(kali) と Relay(alice) が Channel(Slack) を通して接続ができています。

Relay のアイコンをクリックすると、コンピュータ名や実行ユーザ、実行権限などが表示されています。

Relay の COMMAND CENTER にて Ping コマンドを実行することで、疎通確認ができます。ただ、最初に記載したとおり、C3 だけでは C2 接続のみが可能で、RAT 機能はありません。 Covenant を接続することでリモート操作ができるようになりますが、それはひとまず置いておき、次は P2P 通信をしてみましょう。

Advanced: 横展開先の別ホストとP2P接続する

侵害先で横展開を行い侵害ホストを拡大していくとき、侵害先ホストがインターネットに接続できなかったり、インターネットへの通信が Blue Team によって検知される可能性が高い場合があります。そういったときはホスト間での P2P を使うことで対処します。

C3 には UncShareFile という Channel があり、Relay でこの Channel を作成することで、別ホストからファイル共有を通じて通信をクラウドの Channel に転送することができます。

今回の登場人物は alice と bob です。どちらも攻撃者は何らかの方法でアクセス可能になっているとします。

Note: 標的PCについては実際は以下のコンピュータ名。

  • alice: tcorp-student
  • bob: tcorp-sqlclient

(名前に深い意味はありません)

まずは、既に Slack 経由で C3 と接続している alice にて、ファイル共有を有効にします。ファイル共有を行うUNCパスは好きに選べますが、今回はパブリックフォルダを使ってP2P通信をしてみましょう。

共有オプションでパブリックフォルダの共有のゲストアクセスを有効にすることで、Public フォルダが他ホストからアクセスできるようになります。(要管理者権限)

設定後、bob のマシンから alice の Public Documents フォルダにアクセスできることを確認しましょう。

alice でUncShareFile Channelを作成

C3 の WebUI にて alice の Relay アイコンをクリックし、COMMAND CENTER をクリックします。

以下の情報を入力します。

・ Select Command: AddNegotiationChannelUncShareFile
・ Negotiation Identifier: デフォルトでOK
・ Filesystem path: 共有フォルダのUNCパス

SEND COMMAND を入力すると Relay にコマンドが送られ、Channel が作成されます。

UncShareFile の Relay を作成し配置

作成された UncShareFile Channel のアイコンをクリックし、INTERFACE OPTIONS から New Relay を選択します。以前行った Relay と同じ要領で Name を好きにつけて、CREATE AND DOWNLOAD RELAY をクリックし Relay をダウンロード。ダウンロードした Relay を bob に配置し、実行しましょう。

以下は実行時の画面です。(gif)

動画左上はSlack、左下はC3のWebUI、右はbobでRelayを実行したときのパケットキャプチャです。bobが alice に SMB で通信を発生させ、alice はそれをトリガーに Slack にメッセージを投稿し、Gateway は Slack のメッセージを受け取ることで間接的に bob と接続することができました。

・・・

Covenantと連携してRAT機能を使おう

お待たせしました。C3 について説明したので、やっと Covenant との連携の話ができます。

C3 と Covenant 連携の仕組み

C3 は概念や用語が多くわかりにくいので、連携の様子を図にしてみました。

C3 は Connector という機能を用いて、Covenant と連携をします。

連携操作を開始すると、Gatewayは Covenant API に接続し、C3 用の BridgeListener を作成します。この BridgeListener はデフォルトでは 8000/tcp でリッスンします。BridgeListener は HTTPListener とは異なり、シンプルな TCP を通して Grunt とやりとりを行うことができます。 ここで Gateway は Grunt と Covenant サーバを仲介する、いわば C2Bridge の役割をします。

画像でいうと、C2Bridge が C3 Gatewayで、C2Bridge Protocol は今回でいうと Slack ということになります。 Grunt が Covenant と C2 通信をできるようになるまでの処理については以下のようになっています。

1. C3 の WebUI にて Relay に Grunt の追加操作をするとき、Gateway は Covenant APIに接続し、ImplantTemplete を GruntSMB に設定した Launcher をシェルコードの形で取得

2. Gateway は Launcher を Relay に送信。Relay が Launcher をメモリ上に読み込み実行。

3. Launcher は GruntSMB (Stager) を呼び出す。Named Pipe (名前付きパイプ) を作成し、P2P 接続を待ち受ける。Relay は作成された Named Pipe を通して GruntSMB と Gateway の仲介役をし、Gateway は Covenant API とやりとりする。

4. GruntSMB (Stager) が Covenant から本体ペイロードをダウンロードし最終的に Relay プロセス内で Grunt が起動する

なお Grunt で Task を実行するときも同じように Named Pipe を通します。
これが C3 と Covenant の連携の仕組みです。

前回の Covenant の P2P 接続ではリモートホスト間を接続するために GruntSMB で Named Pipe 接続をしましたが、今回はローカルホスト内で Relay プロセスとやりとりするために利用しています。
C3 は複数チャンネルに対応しており、Implant 開発の手間を省くためにGruntSMBを流用していますが、本来は Covenant で C2 チャンネルを開発するときは、その C2 チャンネルに対応した Grunt の Implant を個別に実装したほうがいいです。

Covenant 連携の初期セットアップ

実際に試してみましょう。予め Gateway は Covenant の WebUI に接続できる状態にしておいてください。(同一ホストがベスト)

Gateway のアイコンをクリックし、COMMAND CENTER をクリックします。

以下の情報を入力します。

・ Select Command: TurnOnConnectorCovenant
・ C2BridgePort: 8000
・ Covenant Web Host: Gateway から疎通可能な Covenant の URL
・ Username / Password: Covenant のユーザパスワード

「SEND COMMAND」 をクリックします。Covenant とのセッションが正常に確立できると、C3 の WebUI に雲のアイコンが出現します。

Covenant の Listeners ページを確認すると C3Bridge という名前の BridgeListener ができていることがわかります。

Relay で Grunt を追加して動かす

RAT 機能を持つ CobaltStrike Beacon や Covenant Grunt は、C3 用語で Peripheral と呼びます。Gateway と Covenant が接続できたら、Covenant 用Peripheral である PeripheralGrunt を追加します。

C3 の WebUI で Relay のアイコンをクリックし、COMMAND CENTER をクリックします。

以下の情報を入力します。

・ Select Command: AddPeripheralGrunt
・ Pipe name: デフォルトでOK。今回はあえて「gruntpipe1」に。
・ Delay/Jitter/Connect Attempts: デフォルトでOK。

SEND COMMAND をクリックします。クリック後に Slack 上で慌ただしくメッセージが飛び交い、しばらく待つとC3上で PC のアイコンが出現します。

Covenant の Grunts ページを確認すると、Grunt が登録されていることがわかります。WhoAmI タスクも正常に動きます。

ScreenShotsタスク実行時のSlack画面

C3連携時の ScreenShots タスク実行時の挙動を動画でどうぞ(gif)。

全てのやりとりが Slack を経由しています。

挙動の不安定さについて

C3 連携時の Grunt は、タスクの実行結果によって突然レスポンスを返さずに、Relay ごと反応がなくなる場合があります。

もともと Grunt は Task ごとに独立してジョブを実行可能ですが、C3との連携時は Task が終了するときに1文字以上の文字列をリターンしないと次の Task を実行できないようです。 (間違っているかも)

そのため、Taskにより生成されたプロセスが終了しない場合や返り値が空 ("") のとき、それ以降 Grunt の応答が返りません。

生成されたプロセスが終了しない場合: 例えば Shell Task および ShellCmd Taskは SharpSploit の CreateProcess を利用します。そして CreateProcess は System.Diagnostics.Process クラスの WaitForExit() を必ず呼びます。
このままだと常駐プログラムを起動する場合は必ず応答が返ってこなくなります。これは WaitForExit() を呼ばないカスタム Task を作成することで問題を回避できました。

返り値が空の場合: KeyLoggerタスクは OutputStream を用いていて、キーロガーの情報はストリームデータで渡すようになっているので返り値自体は空になります。よって KeyLogger タスクを実行するとそれ以降 Grunt の応答が返らなくなります。また、他のタスクでもたまたま実行結果が空になるときでも同様の事象が発生します。これは C3 のバグだと思います・・・。

以上から、現状では Grunt を完全に C3 + Covenant に置き換えるのは厳しいかもしれません。ただ治るはずなので、今後に期待です。(原因突き止めたら PullRequest を送ろうと思います)。

おまけ: Relay プロセスの状態

C3 の Relay プロセスを Process Hacker で確認するといくつかの特徴がみられました。Grunt とやりとりするため、Relay プロセスが Named Pipe に接続していることがわかります。

また、Relay は .NET を利用しませんが、Gruntは .NET アセンブリであるため、In-Memory .NET Tradecraft 手法を用いてメモリ内に .NET アセンブリを読み込みます。そうすると ProcessHacker の画面に .NET assemblies のタブが現れるようになります。

このようなプロセスは悪目立ちしそうです。

・・・

まとめ

Covenant と C3 を連携して Grunt とのやりとりを Slack チャンネル上で行うことができました。このように近年はもう通信だけみてもマルウェア通信とわからないようになっているので、EDR製品などのエンドポイントセキュリティが必須だと感じます。

C3 の 連携先には Cobalt Strike もあるので、機会があれば試してみたいです。

リファレンス

・C3
- https://github.com/FSecureLABS/C3

・Making Donuts Explode – Updates to the C3 Framework
- https://labs.f-secure.com/blog/making-donuts-explode-updates-to-the-c3-framework/

・Covenant: Developing Custom C2 Communication Protocols
- https://posts.specterops.io/covenant-developing-custom-c2-communication-protocols-895587e7f325

・Flying A False Flag
- https://i.blackhat.com/USA-19/Wednesday/us-19-Landers-Flying-A-False-Flag-Advanced-C2-Trust-Conflicts-And-Domain-Takeover.pdf
- Blue Team の検知を逃れる強力な C2 チャンネルを構築するためのよい教科書です。