赞
踩
本文包括:Java反序列化之CommonsCollections篇(CC1)的一些基础知识概念。
Apache Commons Collections是Java应用开发中一个非常常用的工具库,它添加了许多强大的数据结构,简化了Java应用程序的开发,已经成为Java处理集合数据的公认标准。像许多常见的应用如Weblogic、WebSphere、Jboss、Jenkins等都使用了Apache Commons Collections工具库,当该工具库出现反序列化漏洞时,这些应用也受到了影响,这也是反序列化漏洞如此严重的原因。
Apache Commons Collections 中提供了一个Transformer的类,这个接口的功能就是将一个对象转换为另外一个对象。
然后整个利用链是需要重点关注这个类。
IDEA版本为:2021.1.3
jdk版本为8u65,因为CC1的利用链在8u71的版本就修复了。下载地址:https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html
Maven版本为:3.6.3,下载链接:https://archive.apache.org/dist/maven/maven-3/3.6.3/binaries/
本文CommonsCollections的版本是3.2.1。3.1-3.21之间都可以。
<dependencies>
<!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
</dependencies>
为方便调试需加入java源码,下载地址为:https://hg.openjdk.java.net/jdk8u/jdk8u/jdk/rev/af660750b2f4。
1)下载openjdk对应版本的源码。并解压成文件夹。
2)把jdk1.8.0_65文件夹中的src.zip解压。然后把下载的openjdk中的 jdk-af660750b2f4\src\share\classes的sun文件夹拷贝到解压的 src文件夹中。
3)IDEA创建maven项目,Project SDK选择你下载的jdk8u65的路径。然后下一步写你项目的名字和存放路径创建即可。
4)创建好后,选择ProjectStructure项目结构。
5)选择SDKs点击Sourcepath添加src最后应用保存即可。
6)然后pom.xml文件中添加commons collections 3.2.1版本,直接下载资或者右键重新加载项目下载资源都可以。
1)JAVA中正常的命令执行。
public class CC1 {
public static void main(String[] atgs) throws Exception
{
// 1.先弹个计算器
Runtime.getRuntime().exec("calc");
}
}
2)利用一个普通的反射执行命令。
import java.lang.reflect.Method; public class CC1 { public static void main(String[] atgs) throws Exception { // // 1.先弹个计算器 // Runtime.getRuntime().exec("calc"); // 2.写一个普通的反射 Runtime r = Runtime.getRuntime(); // 获取Runtime的class Class c = Runtime.class; // 获取Runtime的exec方法 Method execMethod = c.getMethod("exec",String.class); // 调用exec方法 execMethod.invoke(r,"calc"); } }
1)Transformer类是Commons Collections中自定义的一组功能类。Transformer类的功能就是接收一个对象然后调用transform方法,对这个对象做一些操作。
public interface Transformer {
public Object transform(Object input);
}
2)InvokerTransformer也是实现了Transformer接口的一个类,它可以执行任意的方法。在创建InvokerTransformer对象时,需要传入三个参数,第一个是想要执行的方法名,第二个是这个方法所需要参数的参数类型,第三个是这个方法中具体的参数;当调用InvokerTransformer类中的transform方法时,将会执行我们想要执行的方法,那具体是哪个对象中的方法呢?是通过transform方法中的参数传入进去的,接下来看看代码,首先是构造方法:
public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
super();
iMethodName = methodName;
iParamTypes = paramTypes;
iArgs = args;
}
就是将三个参数做一个赋值而已, 接下来就来看它的回调transform方法。
public Object transform(Object input) {
if (input == null) {
return null;
}
try {
Class cls = input.getClass();
Method method = cls.getMethod(iMethodName, iParamTypes);
return method.invoke(input, iArgs);}
catch (NoSuchMethodException ex) {
throw new FunctorException("InvokerTransformer: The method '" +iMethodName + "' on '" + input.getClass() + "' does not exist");}
catch (IllegalAccessException ex) {
throw new FunctorException("InvokerTransformer: The method '" +iMethodName + "' on '" + input.getClass() + "' cannot be accessed");}
catch (InvocationTargetException ex) {
throw new FunctorException("InvokerTransformer: The method '" +iMethodName + "' on '" + input.getClass() + "' threw an exception", ex);}
}
这样它就可以执行input对象的iMethodName⽅法了,原理其实也挺简单,就是利用反射先获取这个方法,然后再执行input对象中的这个方法就行了
3)TransformedMap这个类中封装了一个decorate方法,它是用来修饰Java中的标准数据结构Map,当向被修饰过的Map中添加新元素时,它就会执行一个回调函数;这个回调并不是传统意义上的回调函数,而是相当于执行一个对象里面的transform方法,前提是这个对象的类要实现了Transformer接口。参照下面代码可以看出来其中,keyTransformer是处理新元素的Key的回调,valueTransformer是处理新元素的value的回调,当我们向outerMap中添加新元素时,它就会调用keyTransformer或者valueTransformer里面的transform方法。
Map innerMap = new HashMap();
Map outerMap = TransformedMap.decorate(innerMap, keyTransformer, valueTransformer);
4)ConstantTransformer同样是一个实现了Transformer接口的一个类,这个类很简单,它有一个带参的构造函数,而参数类型是对象,当你传入一个对象后,它会在transform方法中再将这个对象返回出来。就是将传入的对象constantToReturn在transform方法中返回
public ConstantTransformer(Object constantToReturn) {
super();
iConstant = constantToReturn;
}
public Object transform(Object input) {
return iConstant;
}
5)前面讲了ConstantTransformer和InvokerTransformer两个类,一个可以返回一个类的对象,另一个可以执行对象中的方法,那么我们是不是就可以尝试执行Runtime类中的exec方法呢?很显然,我们还需要一个类将这两个串起来,让ConstantTransformer类返回的对象,能作为参数,进入到InvokerTransformer类的transform方法中,这样就可以了,这时候就需要拿出我们的ChainedTransformer类了;ChainedTransformer类同样也是实现了Transformer接口的一个类,它就是将内部多个实现了Transformer接口的类串在了一起,并且将前一个回调函数transform返回的结果,作为后一个回调函数transform的参数传入,代码如下,挺简单的一个逻辑,就是不停的调transform
public ChainedTransformer(Transformer[] transformers) {
super();
iTransformers = transformers;
}
public Object transform(Object object) {
for (int i = 0; i < iTransformers.length; i++) {
object = iTransformers[i].transform(object);
}
return object;
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。