ActiveMQ(<5.18.3)RCE
ActiveMQ(<5.18.3)RCE
背景信息
影响版本:
- Apache ActiveMQ < 5.18.3
- Apache ActiveMQ < 5.17.6
- Apache ActiveMQ < 5.16.7
- Apache ActiveMQ < 5.15.16
参考:
[Apache ActiveMQ CVE-2023-46604 RCE 分析 - Boogiepop Doesn't Laugh (boogipop.com)](https://boogipop.com/2023/11/03/Apache ActiveMQ CVE-2023-46604 RCE 分析/)
其实有个疑问,该漏洞的source点看了很多一直不是很清楚具体是哪些点?MQ的通信是只要和服务端通信就会触发还是有相关的逻辑?
漏洞分析
通过之前版本差异可看出问题出在下面这里(V12只是其中一个版本,还有另外三个)
org.apache.activemq.openwire.v12.BaseDataStreamMarshaller#createThrowable
private Throwable createThrowable(String className, String message) {
try {
Class clazz = Class.forName(className, false, BaseDataStreamMarshaller.class.getClassLoader());
Constructor constructor = clazz.getConstructor(new Class[] {String.class});
return (Throwable)constructor.newInstance(new Object[] {message});
} catch (Throwable e) {
return new Throwable(className + ": " + message);
}
}
从中可以看到className和message若是可控则会任意类构造方法调用,而其中spring自带的org.springframework.context.support.ClassPathXmlApplicationContext则是符合这样的利用链CPX;因此问题则是找到对应的触发点;
选取tightUnmarsalThrowable方法跟踪:
org.apache.activemq.openwire.v12.BaseDataStreamMarshaller#tightUnmarsalThrowable

发现ExceptionResponseMarshaller等四个存在调用,网上基本利用的是ExceptionResponseMarshaller,其他的类应该也可以利用,比如ConnectionErrorMarshaller、MessageAckMarshaller等。出漏洞的createThrowable方法实际在这些Marshallers的父类BaseDataStreamMarshaller中,只要调用了这个函数来反序列化数据流就会导致漏洞。

选择常用的ExceptionResponseMarshaller这个跟踪;
org.apache.activemq.openwire.v12.ExceptionResponseMarshaller#tightUnmarshal
会发现OpenWireFormat文件中存在两处方法调用了,而openwire就是ActiveMQ内置默认协议,61616端口,生产者和消费者交互的端口;

而其中doUnmarshal方法则是
org.apache.activemq.openwire.OpenWireFormat#doUnmarshal
public Object doUnmarshal(DataInput dis) throws IOException {
byte dataType = dis.readByte();
if (dataType != NULL_TYPE) {
DataStreamMarshaller dsm = dataMarshallers[dataType & 0xFF];
if (dsm == null) {
throw new IOException("Unknown data type: " + dataType);
}
Object data = dsm.createObject();
if (this.tightEncodingEnabled) {
BooleanStream bs = new BooleanStream();
bs.unmarshal(dis);
dsm.tightUnmarshal(this, data, dis, bs);
} else {
dsm.looseUnmarshal(this, data, dis);
}
return data;
} else {
return null;
}
}
因此问题关键则是发送一个ExceptionResponse对象,之后调用其unmarshal方法,最后触发createThrowable;
环境调试准备
测试程序demo:
package com.yglearnsec.javasec.activemq;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQObjectMessage;
import javax.jms.*;
public class ActiveMQOpenWrite {
public static void main(String[] args) throws JMSException {
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://127.0.0.1:61616");
Connection connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession();
Destination destination = session.createQueue("testQueus");
MessageProducer producer = session.createProducer(destination);
//ActiveMQObjectMessage message001= session.createMessage();
Message message = session.createObjectMessage("123");
producer.send(message);
//producer.send(message001);
connection.close();
}
}
往上基本都是根据此模拟序列化过程将序列化(客户端的过程还是不太一样)过程中的对象进行替换成对应的恶意类;
apachemq5.18.2的代码下载后基于wapper tomcat,修改添加debug参数
wrapper.java.additional.8=-Xdebug
wrapper.java.additional.9=-Xnoagent
wrapper.java.additional.10=-Djava.compiler=NONE
wrapper.java.additional.11=-Xrunjdwp:transport=dt_socket,server=y,address=2999,suspend=n
之后在IDEA中添加java remote debug配置

之后通过相关方法发送恶意数据触发,在org.apache.activemq.openwire.OpenWireFormat#doUnmarshal中设置断点即可查看相关利用链;


浙公网安备 33010602011771号