JDK版本:jdk8u65
commons-collections 3.2.1
Maven依赖:
<dependencies>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
</dependencies>
InvokerTransformer
InvokerTransformer
作为 valueTransformer 装进去。AnnotationInvocationHandler
这个类在反序列化时会遍历 Map 并 setValue,从而触发整个链条。cc1链起点是commons-collections包的Transformer接口,这个接口的transform方法接收一个对象作为参数
InvokerTransformer 是 commons-collections 3.2.1 包中的一个类,也是我们的入口类,其全名是:
org.apache.commons.collections.functors.InvokerTransformer
它可以让你通过 transform
方法,反射调用任何你想要的方法
在 CC1 链中,它就是“遥控器”,用来执行恶意命令的关键
// 创建一个 InvokerTransformer,指定调用 exec 方法,参数是 "calc"
InvokerTransformer transformer = new InvokerTransformer(
"exec", new Class[]{String.class}, new Object[]{"calc"}
);
当你调用 transformer.transform(Runtime.getRuntime())
时,它就会执行:Runtime.getRuntime().exec("calc");
触发计算器
它是一个可以在存取数据时自动对 key 或 value 进行“变换处理”的 Map。
这个 Map 可以在你往里面放数据或者修改数据时,自动调用你指定的 transform 方法。
当你调用 put(key, value) 或 setValue(value) 时,TransformedMap 会自动调用你传进去的 valueTransformer 的 transform(value) 方法,把 value 先“加工”一下,再存进去。
如果你传进去的 valueTransformer 是一个恶意的 InvokerTransformer,那么 transform 方法里就会执行你想要的恶意操作。
你可以把 TransformedMap 想象成一个“智能快递柜”:
你往柜子里放快递(put/setValue),柜子会自动帮你消毒(transform)。
你指定的消毒方式(Transformer)是什么,柜子就怎么处理。
org.apache.commons.collections.functors.InvokerTransformer
可以看到我们这个payload就是先new了一个 InvokerTransformer
。
小框框中的是他的三个参数:iMethodName,iParamTypes,iArgs都是可控的
然后通过它的transform
方法使用了反射来调用input的方法,
且传入的这个input对象也是可控的
我们可以通过直接利用invoketransformer的代码,执行过后就会触发计算器
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.InvokerTransformer;
public class CC1 {
public static void main(String[] args) {
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}).transform(Runtime.getRuntime());
}
}
然后我们去找一个其它的类有transform方法,并且传入的Object是可控的,然后我们只要把这个Object设为InvokeTransformer即可,我们全局搜索transform方法,能够发现很多类都是有transform方法的,我们这里先研究的是CC1,所以我们直接看 TransformerMap
类
然后我们查找用法,看有那些类也用了这个 transform(object)
在 TransformedMap
中的checkSetValue方法中调用了transform,valueTransformer是构造的时候赋的值,再看构造函数
构造函数是一个protected,所以不能让我们直接实例赋值,只能是类内部构造赋值,找哪里调用了构造函数
这里找到了一个静态方法,这里我们就能控制参数了