通过Apaache Common-collections分析Java反序列化

本文深入分析Apache Commons-collections库中的Java反序列化漏洞,讲解Transformer类如ConstantTransformer、InvokerTransformer和ChainedTransformer的工作原理,以及如何通过它们实现命令执行。文章还探讨了如何利用TransformedMap和AnnotationInvocationHandlerMap类完成攻击调用链,并提供漏洞利用的思路和总结。
摘要由CSDN通过智能技术生成

通过Apaache Common-collections分析Java反序列化

前言

本文将通过 Apache Commons-collections爆出的反序列化漏洞来作为例子进行原理分析。

漏洞成因

在这个Java反序列化漏洞的利用链主要由三个部分组成

1、可以执行恶意代码的对象(在这个例子中即为Commons-collection中的Transformer类)

2、一个被恶意对象“寄生的宿主”,通俗的来说就是,宿主对象反序列化的时候因为需要执行readObject方法,而readObject方法在可以被序列化的类中需要被重写,重写后的方法可能存在某些能够触发恶意对象执行的操作。

3、需要一个能够将恶意对象进行包装的类。在有的情况下恶意对象没有办法直接‘寄生“在宿主上,这时候就需要一个类能够将恶意对象进行包装

在这个例子中恶意代码对象为Commons-collection中的Transformer类,这个类原本的设计是用来对类进行转换,而通过精心设计(后文会详细讲解)后能够通过这个类的transform方法实现命令执行。而被寄生的宿主为AnnotationInvocationHandlerMap类,通过其readObject方法能够触发漏洞。而AnnotationInvocationHandlerMap类中有一个Map类型的成员变量memberValuesTransformer类可以通过用Map类包装寄生在AnnotationInvocationHandlerMap

接下来会分为两个部分解释,即1如何通过transfomer进行命令执行,2是如何利用反序列化完成一个调用链

Transformer类的作用

首先我们先看一下导致这个问题的核心类Transformer

public interface Transformer {
   
    public Object transform(Object input);
}

这是一个接口类,需要实现一个transform方法,而transform方法的目的是将input object转换为一个output object 从而完成类型的转换

在整个调用过程中用到了三个实现Transformer的实现类,ConstantTransformer,InvokerTransformer,ChainedTransformer.

ConstantTransformer

//以下省去了部分代码
public class ConstantTransformer implements Transformer, Serializable {
   

    /** Serial version UID */
    private static final long serialVersionUID = 6374440726369055124L;

    /** The closures to call in turn */
    private final Object iConstant;

    public ConstantTransformer(Object constantToReturn) {
   
        super();
        iConstant = constantToReturn;
    }
    public Object transform(Object input) {
   
        return iConstant;
    }
}

可通过查看ConstantTransformer的源码发现,其transform方法无论输入什么类型都会返回一种初始化时定好的类型。

System.out.println(new ConstantTransformer(Runtime.class).transform(String.class));
//输出:class java.lang.Runtime
//无论transform的参数是什么都会得到相同的结果

InvokerTransformer

//以下省去了部分代码
public class InvokerTransformer implements Transformer, Serializable {
   

    /** The serial version */
    private static final long serialVersionUID = -8653385846894047688L;

    /** The method name to call */
    private final String iMethodName;
    /** The array of reflection parameter types */
    private final Class[] iParamTypes;
    /** The array of reflection arguments */
    private final Object[] iArgs;

    public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
   
        super();
        iMethodName = methodName;
        iParamTypes = paramTypes;
        iArgs = args;
    }

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

        } catch (NoSuchMethodException ex) {
   
          ***
    }

}

return method.invoke(input, iArgs);

InvokerTransformertransform方法则是将传入的类的某种方法(方法名和参数同样在初始化的时候设定好了)利用invoke进行调用

System.out.println(new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",new Class[0]}).transform(Runtime.class));
//output:public static java.lang.Runtime java.lang.Runtime.getRuntime()

当输入的参数为Runtime.class时相当于会调用Runtime.classgetMethod方法

public Method getMethod(String name, Class<?>... parameterTypes)

可以看到这个方法所需要的参数为name和参数类型,所以我们如果需要获取RuntimegetRuntime方法则需要传入的参数为 “getRuntime” 即方法名以及其对应的参数类型Class<?>

public static Runtime getRuntime() {
   
        return currentRuntime;
}

getRuntime是个无参函数,所以传入一个空的Class数组即可。即Class[0]

ChainedTransformer

//省略部分代码
public class ChainedTransformer implements Transformer, Serializable {
   

    /** Serial version UID */
    private static final long serialVersionUID = 3514945074733160196L;

    /** The transformers to call in turn */
    private final Transformer[] iTransformers;

    public ChainedTransformer(Transformer
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值