Java安全之CC1-7

约 24 分钟读完

Java反序列化漏洞CC1-CC7链的利用流程分析

Apache Commons Collections(CC链)是Java反序列化漏洞中最具代表性的利用链之一,从CC1到CC7链展示了攻击者如何通过精心构造的序列化对象绕过安全防护机制,实现远程代码执行(RCE)。每条CC链都有其特定的入口点、触发链和执行点,这些链利用了Transformer接口及其子类的反射或类加载机制 。本文将详细解析CC1-CC7链的利用流程,帮助安全研究人员和开发人员更好地理解和防御这类漏洞。

一、Transformer接口及其实现类的作用

Transformer接口是Apache Commons Collections中的核心组件,其transform()方法被多个实现类重写,用于在反序列化过程中触发恶意代码执行 :

public interface Transformer {
    public Object transform(Object input);
}

Transformer接口的主要实现类及其功能如下:

Transformer类 功能描述 在CC链中的作用
InvokerTransformer 通过反射动态调用对象的方法 执行Runtime.exec()或触发TemplatesImpl类加载
ChainedTransformer 串联多个Transformer,按顺序执行transform()方法 构造Transformer链,传递控制流
ConstantTransformer 返回固定值,无论输入参数是什么 提供Transformer链的初始值,如Runtime.class或TemplatesImpl实例
TiedMapEntry 包装Map对象,提供get和put方法 通过toString()或hashCode()方法触发LazyMap的get()方法
TransformingComparator 基于Transformer的比较器 通过compare()方法触发Transformer链

Transformer接口的transform()方法是CC链的核心执行点,攻击者通过构造特定的Transformer链,在反序列化过程中触发恶意代码执行 。不同版本的CC链利用了不同Transformer类的组合,以及不同的触发机制。

二、CC1链的利用流程

CC1链是最早被发现的Commons Collections反序列化漏洞,主要利用了AnnotationInvocationHandler类的反序列化逻辑 :

入口点AnnotationInvocationHandler.readObject()

触发链

AnnotationInvocationHandler.readObject()  // 反序列化入口
    -> map.entrySet()  // 触发Map的entrySet方法
        -> MapEntry.setValue()  // 触发MapEntry的setValue方法
            -> parent.checkSetValue(value)  // 调用TransformedMap的checkSetValue方法
                -> valueTransformer.transform(value)  // 触发Transformer链
                    -> ChainedTransformer.transform()  // 串联多个Transformer
                        -> ConstantTransformer.transform()  // 返回固定值Runtime.class
                            -> InvokerTransformer.transform()  // 反射调用Runtime exec方法

执行点InvokerTransformer.transform()Runtime.exec()

CC1链的构造过程主要包含以下几个关键步骤:

  1. 创建Transformer链:首先使用ConstantTransformer返回Runtime.class,然后使用两个InvokerTransformer分别获取Runtime的getRuntime()方法和执行exec()方法
  2. 创建TransformedMap:将Transformer链绑定到Map上,当访问Map的value时会触发Transformer链
  3. 创建AnnotationInvocationHandler:通过反射构造AnnotationInvocationHandler实例,将其map属性设置为TransformedMap
  4. 序列化对象:将构造好的AnnotationInvocationHandler对象序列化为字节流
  5. 触发反序列化:当目标系统反序列化该字节流时,会自动执行Transformer链,最终调用Runtime.exec()执行恶意命令

CC1链的漏洞利用条件包括:使用JDK7或JDK8u65之前的版本,以及存在Apache Commons Collections 3.2.1或更早版本 。

三、CC2链的利用流程

CC2链是针对Commons Collections 4.0版本的漏洞利用链,主要利用了PriorityQueue类的反序列化逻辑和TransformingComparator类 :

入口点PriorityQueue.readObject()

触发链

PriorityQueue.readObject()  // 反序列化入口
    -> heapify()  // 堆化操作
        -> siftDownUsingComparator()  // 堆排序操作
            -> comparator.compare()  // 调用TransformingComparator的compare方法
                -> ChainedTransformer.transform()  // 串联多个Transformer
                    -> ConstantTransformer.transform()  // 返回固定值TemplatesImpl实例
                        -> InvokerTransformer.transform()  // 反射调用TemplatesImpl newTransformer方法
                            -> defineTransletClasses()  // 加载恶意类字节码

执行点TemplatesImpl#defineTransletClasses()defineClass()加载恶意类字节码并执行静态代码块

CC2链的构造过程与CC1链有所不同,主要区别在于触发机制:

  1. 创建恶意类字节码:编写一个包含恶意代码的Java类,将其编译为字节码
  2. 创建TemplatesImpl实例:通过反射设置TemplatesImpl的_bytecodes、_name等属性,使其指向恶意类字节码
  3. 创建TransformingComparator:将InvokerTransformer绑定到TransformingComparator上
  4. 创建PriorityQueue:使用PriorityQueue作为反序列化入口,设置其comparator为TransformingComparator
  5. 序列化对象:将构造好的PriorityQueue对象序列化为字节流
  6. 触发反序列化:当目标系统反序列化该字节流时,会自动执行Transformer链,最终通过defineTransletClasses()加载恶意类并执行静态代码块

CC2链的漏洞利用条件包括:使用JDK8u71或更高版本,以及存在Apache Commons Collections 4.0版本 。

四、CC3链的利用流程

CC3链可以视为CC1链的扩展,主要利用了LazyMap类的反序列化逻辑 :

入口点AnnotationInvocationHandler.readObject()

触发链

AnnotationInvocationHandler.readObject()  // 反序列化入口
    -> map.entrySet()  // 触发Map的entrySet方法
        -> LazyMap.get()  // 触发LazyMap的get方法
            -> factory.transform()  // 调用Transformer链
                -> ChainedTransformer.transform()  // 串联多个Transformer
                    -> ConstantTransformer.transform()  // 返回固定值TemplatesImpl实例
                        -> InvokerTransformer.transform()  // 反射调用TemplatesImpl newTransformer方法
                            -> defineTransletClasses()  // 加载恶意类字节码

执行点TemplatesImpl#defineTransletClasses()defineClass()加载恶意类字节码并执行静态代码块

CC3链的构造过程与CC1链相似,但触发机制不同:

  1. 创建Transformer链:首先使用ConstantTransformer返回TemplatesImpl实例,然后使用InvokerTransformer反射调用newTransformer()方法
  2. 创建LazyMap:将Transformer链绑定到LazyMap上,当访问不存在的key时会触发Transformer链
  3. 创建AnnotationInvocationHandler:通过反射构造AnnotationInvocationHandler实例,将其map属性设置为LazyMap
  4. 序列化对象:将构造好的AnnotationInvocationHandler对象序列化为字节流
  5. 触发反序列化:当目标系统反序列化该字节流时,会自动执行Transformer链,最终通过defineTransletClasses()加载恶意类并执行静态代码块

CC3链的漏洞利用条件与CC1链类似,但需要确保LazyMap的触发机制能够正常工作,例如确保访问不存在的key。

五、CC4链的利用流程

CC4链是CC2链的扩展,主要利用了InstanciateTransformer类和TrAXFilter类的构造方法 :

入口点PriorityQueue.readObject()

触发链

PriorityQueue.readObject()  // 反序列化入口
    -> heapify()  // 堆化操作
        -> siftDownUsingComparator()  // 堆排序操作
            -> comparator.compare()  // 调用TransformingComparator的compare方法
                -> ChainedTransformer.transform()  // 串联多个Transformer
                    -> ConstantTransformer.transform()  // 返回固定值TrAXFilter.class
                        -> InstanciateTransformer.transform()  // 实例化TrAXFilter对象
                            -> TrAXFilter.Templates()  // 调用Templates构造方法
                                -> Templates.newTransformer()  // 调用newTransformer方法
                                    -> defineTransletClasses()  // 加载恶意类字节码

执行点TemplatesImpl#defineTransletClasses()defineClass()加载恶意类字节码并执行静态代码块

CC4链的构造过程比CC2链更复杂,主要增加了InstanciateTransformer的使用:

  1. 创建恶意类字节码:编写一个包含恶意代码的Java类,将其编译为字节码
  2. 创建TemplatesImpl实例:通过反射设置TemplatesImpl的_bytecodes、_name等属性,使其指向恶意类字节码
  3. 创建InstanciateTransformer:指定目标类为TrAXFilter,并传递TemplatesImpl实例作为参数
  4. 创建TransformingComparator:将InstanciateTransformer绑定到TransformingComparator上
  5. 创建PriorityQueue:使用PriorityQueue作为反序列化入口,设置其comparator为TransformingComparator
  6. 序列化对象:将构造好的PriorityQueue对象序列化为字节流
  7. 触发反序列化:当目标系统反序列化该字节流时,会自动执行Transformer链,最终通过defineTransletClasses()加载恶意类并执行静态代码块

CC4链的漏洞利用条件与CC2链类似,但需要确保InstanciateTransformer能够正确实例化TrAXFilter对象。

六、CC5链的利用流程

CC5链是针对JDK8u71修复后的漏洞利用链,主要利用了BadAttributeValueExpException类的反序列化逻辑 :

入口点BadAttributeValueExpException.readObject()

触发链

BadAttributeValueExpException.readObject()  // 反序列化入口
    -> ois.readFields()  // 读取对象字段
        -> valObj.toString()  // 调用val对象的toString方法
            -> TiedMapEntry.toString()  // 触发TiedMapEntry的toString方法
                -> TiedMapEntry.getValue()  // 触发TiedMapEntry的getValue方法
                    -> LazyMap.get()  // 触发LazyMap的get方法
                        -> factory.transform()  // 调用Transformer链
                            -> ChainedTransformer.transform()  // 串联多个Transformer
                                -> ConstantTransformer.transform()  // 返回固定值Runtime.class
                                    -> InvokerTransformer.transform()  // 反射调用Runtime exec方法

执行点InvokerTransformer.transform()Runtime.exec()

CC5链的构造过程与CC1链相似,但入口点和触发机制不同:

  1. 创建Transformer链:与CC1链相同,使用ConstantTransformer和两个InvokerTransformer
  2. 创建LazyMap:将Transformer链绑定到LazyMap上,当访问不存在的key时会触发Transformer链
  3. 创建TiedMapEntry:将LazyMap和特定key绑定到TiedMapEntry对象上
  4. 创建BadAttributeValueExpException:通过反射构造BadAttributeValueExpException实例,将其val属性设置为TiedMapEntry对象
  5. 序列化对象:将构造好的BadAttributeValueExpException对象序列化为字节流
  6. 触发反序列化:当目标系统反序列化该字节流时,会自动执行Transformer链,最终调用Runtime.exec()执行恶意命令

CC5链的漏洞利用条件包括:使用JDK8u71或更高版本,以及存在Apache Commons Collections 3.2.1或更早版本 。

七、CC6链的利用流程

CC6链是CC5链的变种,主要利用了HashSet类的反序列化逻辑和TiedMapEntry类的hashCode()方法 :

入口点HashSet.readObject()

触发链

HashSet.readObject()  // 反序列化入口
    -> HashMap.put()  // 添加元素到HashMap
        -> TiedMapEntry.getValue()  // 触发TiedMapEntry的getValue方法
            -> LazyMap.get()  // 触发LazyMap的get方法
                -> factory.transform()  // 调用Transformer链
                    -> ChainedTransformer.transform()  // 串联多个Transformer
                        -> ConstantTransformer.transform()  // 返回固定值Runtime.class
                            -> InvokerTransformer.transform()  // 反射调用Runtime exec方法

执行点InvokerTransformer.transform()Runtime.exec()

CC6链的构造过程与CC5链类似,但触发机制不同:

  1. 创建Transformer链:与CC1链相同,使用ConstantTransformer和两个InvokerTransformer
  2. 创建LazyMap:将Transformer链绑定到LazyMap上,当访问不存在的key时会触发Transformer链
  3. 创建TiedMapEntry:将LazyMap和特定key绑定到TiedMapEntry对象上
  4. 创建HashSet:通过反射构造HashSet实例,将其内部的HashMap设置为包含TiedMapEntry对象
  5. 序列化对象:将构造好的HashSet对象序列化为字节流
  6. 触发反序列化:当目标系统反序列化该字节流时,会自动执行Transformer链,最终调用Runtime.exec()执行恶意命令

CC6链的漏洞利用条件与CC5链类似,但需要确保HashSet的反序列化逻辑能够正确触发TiedMapEntry的hashCode()方法。

八、CC7链的利用流程

CC7链是CC6链的变种,主要利用了Hashtable类的反序列化逻辑和AbstractMap的equals()方法 :

入口点Hashtable.readObject()

触发链

Hashtable.readObject()  // 反序列化入口
    -> restitutionPut()  // 重建hashtable
        -> AbstractMap.equals()  // 比较Map对象
            -> TiedMapEntry.getValue()  // 触发TiedMapEntry的getValue方法
                -> LazyMap.get()  // 触发LazyMap的get方法
                    -> factory.transform()  // 调用Transformer链
                        -> ChainedTransformer.transform()  // 串联多个Transformer
                            -> ConstantTransformer.transform()  // 返回固定值Runtime.class
                                -> InvokerTransformer.transform()  // 反射调用Runtime exec方法

执行点InvokerTransformer.transform()Runtime.exec()

CC7链的构造过程与CC6链类似,但触发机制不同:

  1. 创建Transformer链:与CC1链相同,使用ConstantTransformer和两个InvokerTransformer
  2. 创建LazyMap:将Transformer链绑定到LazyMap上,当访问不存在的key时会触发Transformer链
  3. 创建TiedMapEntry:将LazyMap和特定key绑定到TiedMapEntry对象上
  4. 创建Hashtable:通过反射构造Hashtable实例,将其内部的AbstractMap设置为包含TiedMapEntry对象
  5. 序列化对象:将构造好的Hashtable对象序列化为字节流
  6. 触发反序列化:当目标系统反序列化该字节流时,会自动执行Transformer链,最终调用Runtime.exec()执行恶意命令

CC7链的漏洞利用条件与CC6链类似,但需要确保Hashtable的反序列化逻辑能够正确触发AbstractMap的equals()方法。

九、CC链的共同特点和防御建议

尽管CC1-CC7链的利用流程各不相同,但它们都共享一些共同特点:

  1. 依赖Transformer接口:所有CC链都利用了Transformer接口的transform()方法,通过精心构造的Transformer链实现恶意代码执行
  2. 利用反射机制:CC链中的InvokerTransformer和InstanciateTransformer都利用了Java反射机制,绕过安全检查
  3. 利用类加载机制:CC2-CC4链利用了TemplatesImpl类的defineTransletClasses()方法,通过动态加载恶意类字节码实现命令执行
  4. 利用集合类的反序列化逻辑:CC链的入口点多为集合类(如PriorityQueue、HashSet、Hashtable)的readObject()方法,通过集合类的特定操作触发Transformer链

针对CC链的防御,建议采取以下措施:

  1. 升级Apache Commons Collections版本:使用4.4或更高版本,这些版本已经修复了CC链相关漏洞
  2. 限制反序列化入口:避免直接反序列化来自不可信来源的数据,如网络请求、用户输入等
  3. 使用白名单机制:在反序列化过程中,只允许特定的类和方法被调用,阻止恶意Transformer链的执行
  4. 使用安全的序列化框架:考虑使用Gson、Jackson等更安全的序列化框架,替代Java原生序列化
  5. 监控和审计序列化数据:对序列化数据进行监控和审计,及时发现异常的序列化对象

随着Java安全机制的不断改进,CC链的利用难度也在不断增加,但其核心思想——利用Transformer接口的transform()方法触发恶意代码执行——仍然值得安全研究人员深入理解和研究

说明:报告内容由通义AI生成,仅供参考。

← Java安全之CC3链分析 Fastjson漏洞汇总 →