
ActiveMQは、JMSをサポートするクライアントを含むブローカーであり、Javaだけでなく多様な言語を使用するシステム間の通信を可能にします。また、クラスタリング機能やDB、ファイルシステムを通じて各システム間の一貫性と永続性を維持するオープンソースのメッセージングおよび統合パターンサーバーです。
OpenWireは、Apache ActiveMQで使用されるバイナリメッセージングプロトコルです。ブローカー(ActiveMQ)とクライアント間の効率的なデータ転送のために設計されています。
CVE-2023-46604は、ActiveMQのOpenWireプロトコル(Marshalプロセスにおける)の脆弱性であり、JavaベースのOpenWireブローカーまたはクライアントへのネットワークアクセス権限を持つリモート攻撃者が、OpenWireプロトコルでシリアル化されたクラスタイプを操作して任意のシェルコマンドを実行し、クライアントまたはブローカー(それぞれ)にクラスパス上の任意のクラスをインスタンス化させることができます。これはAPTグループAndarielが代表的に使用した攻撃手法の1つです。
CVE-2023-46604は、OpenWireプロトコルを介してデータを送受信する過程でXML呼び出しを操作したり、悪意のあるデータを挿入してリモートコマンドを実行する形で進行します。OpenWireプロトコルは基本的にデータのシリアル化と転送を処理しますが、脆弱性はこのシリアル化プロセスで悪意のあるクラスタイプが許可される点を悪用します。
[図] POC
[図] XML
ActiveMQ 5.17.3でOpenWireプロトコルに送信するパケットの分析を通じて見ていきます。まず、パケット分析の前にパケットの形式を認識しておく必要があります。パケット Header
+----------------------------------------------------------------------------------+
| Packet Length | Command | Command Id | Command response required | CorrelationId |
|---------------|---------|------------|---------------------------|---------------|
| 00000066 | 1f | 00000000 | 00 | 00000000 |
+----------------------------------------------------------------------------------+
パケット Body
+--------------------------------------------------------------------------------------+
| not-null | not-null | classname-size | classname | not-null | message-size | message |
|----------|----------|----------------|-----------|----------|--------------|---------|
| 01 | 01 | 0043 | ..... | 01 | 0012 | ..... |
+--------------------------------------------------------------------------------------+
OpenWire 패킷 Body 형식
[=If not-null is 1===========]
+----------+ [ +-------+----------------+ ]
| not-null | [ | size | encoded-string | ]
+----------+ [ +-------+----------------+ ]
| byte | [ | short | size octects | ]
+----------+ [ +-------+----------------+ ]
[============================]
[図1] WireShark OpenWireパケット確認
[図1]を見ると、上で説明したパケットのHeader、Body形式が含まれている実際のペイロードです(便宜上、従来のPOC方式のClassPathを介した呼び出しではなく、FileSystemを介した呼び出し)。このパケット内容がどのような作用をし、なぜこのように送信する必要があるのかをコード内でより詳細に見ていきます。
[図2] パケットHeaderの意味
パケット Header 分析
+----------------------------------------------------------------------------------+
| Packet Length | Command | Command Id | Command response required | CorrelationId |
|---------------|---------|------------|---------------------------|---------------|
| 00000066 | 1f | 00000000 | 00 | 00000000 |
+----------------------------------------------------------------------------------+
Packet Length : 00000066 / OpenWire のようなプロトコルは基本的にパケット長を指定。
Command : 1f / は ExceptionResponse(31) を指定するための設定。31は16進数で1f。
Command Id : 00000000 / はint型4バイト形式のため、16進数表現で 00 00 00 00。
Command response required : 00 / はboolean型で True(01)、False(00) から False。
CorrelationId : Command Id と同様の型
[図2]は上記のパケットヘッダーの理解を助けるために、各ヘッダー項目の形式と指定されたコードについての説明を追加した内容です。これでHeaderを見たので、Bodyの内容を通じてどのようにコードを通過するのか見ていきます。
[図3] パケットBodyの意味
パケット Body 内容分析
+--------------------------------------------------------------------------------------+
| not-null | not-null | classname-size | classname | not-null | message-size | message |
|----------|----------|----------------|-----------|----------|--------------|---------|
| 01 | 01 | 0043 | ..... | 01 | 0012 | ..... |
+--------------------------------------------------------------------------------------+
not-null (01) | [図3] の最初の関数で not-null 通過
not-null (01) | classname-size (0043) | classname / [図3] の2番目の関数で not-null 通過、3番目の関数でサイズ確認用
not-null (01) | message-size (0012) | message / [図3] の2番目の関数で not-null 通過、3番目の関数でサイズ確認用
[図3]はパケットのBodyで設定した値がどのように作用するかを示しています。最終的に[図4]を介してシリアル化したデータからクラスをロードしてインスタンス化します。
[図4] createThrowable によるRCE実行
[図5] RCE計算機実行例
[図5] Git Diff (5.17.2 -> 5.17.6)
[図5] validate Function
他の分析とは異なり、本脆弱性において攻撃パケットを分析した理由は、攻撃が実際にどのように実行されるのかを理解し学習するためでした。パケットの構造と流れを綿密に調べることで、攻撃者がシステムを侵害するために使用する具体的な方法とその動作メカニズムを明確に把握することができました。
(nist) https://nvd.nist.gov/vuln/detail/cve-2023-46604
(POC) https://github.com/X1r0z/ActiveMQ-RCE/tree/main
(blog) https://attackerkb.com/topics/IHsgZDE3tS/cve-2023-46604/rapid7-analysis