Java XStream 反序列化:Gadget 挖掘思路分享

admin 2025年2月11日14:54:41评论21 views字数 3473阅读11分34秒阅读模式
一、前  言

二、XStream简介

三、历史漏洞

四、Gadget挖掘思路

五、总  结

前  言
Java语言中最常见的一类漏洞就是反序列化漏洞,在各种数据格式到Java对象的转化过程中,常常存在这类漏洞。常见的数据类型例如jdk提供的原生序列化数据、json、yaml、xml等等。针对这类漏洞存在一种特别的漏洞挖掘方式—Gadget挖掘,这种漏洞挖掘不需要去寻找特定的外部入口漏洞入口,入口往往是公开的,应用通过对传入的数据内容进行过滤和检查。

XStream是一款针对XML和Java对象转换而开发的工具库,由于其本身的一些特点,成为了这类漏洞挖掘里一个很典型的例子,因此本文针对XStream进行Gadget挖掘分析。本文更多的是分享Gadget挖掘时的思路,进而可以在其他类型的序列化中进行类似的思考和尝试。

XStream简介
XStream是一个常用的Java对象和XML相互转换的Java库。

从Java对象到XML:

Java XStream 反序列化:Gadget 挖掘思路分享

Java XStream 反序列化:Gadget 挖掘思路分享

从XML到Java对象:

Java XStream 反序列化:Gadget 挖掘思路分享

Java XStream 反序列化:Gadget 挖掘思路分享

XStream在1.4.18版本以前是存在许多CVE的,核心原因在于的它使用类的黑名单进行防御,因此层出不穷的绕过,在1.4.18版本以后默认为白名单,用户需要自行根据需要使用的类进行配置,到这个版本XStream才没有继续爆出高危的反序列化漏洞。

Java XStream 反序列化:Gadget 挖掘思路分享

值得一提的是,XStream中有CVE编号的利用链都是不依赖任何第三方库,纯利用JDK中的类进行利用,由此可见XStream对于反序列化的宽泛程度。

历史漏洞
简单介绍一下XStream反序列的特点。反序列化漏洞的本质是,基于可以利用的Java类:序列化数据流→SourceGadgetSink

对于原生的Java反序列化来说,可以利用的Java类是任意实现了Serializable的类,入口是ObjectInputStreamreadObject方法。

对于XStream来说,可以利用的Java是任意类,入口是XStream的fromXML方法。

以一个经典的CVE-2013-7285来说,PoC如下,执行的sinkProcessBuilder.start()

Java XStream 反序列化:Gadget 挖掘思路分享

XStream中有一系列的Converter,用于对不同的标签进行转化。

Java XStream 反序列化:Gadget 挖掘思路分享

这里sorted-set标签对应的是TreeSetConverter,它的代码逻辑中会调用TreeMapput方法,而TreeMapput方法会调用方法的compare方法对传入Map的对象进行判断对象应该存放的位置。

Java XStream 反序列化:Gadget 挖掘思路分享

Java XStream 反序列化:Gadget 挖掘思路分享

这里传入的对象是一个动态代理java.beans.EventHandler对象。在 Java 中,动态代理对象是一种在运行时创建的代理对象,它实现了InvocationHandler接口的invoke方法,从而将方法调用按照动态代理的invoke的实现逻辑进行转发。

Java XStream 反序列化:Gadget 挖掘思路分享

它的特点是会在执行非hashCodeequals以及toString这些方法时,会执行其target属性的对象及指定方法。因此在执行到这个动态代理对象的compare方法时,它实际上会执行其target属性ProcessBuilderstart方法,也就是任意命令执行。

XStream对于此漏洞的补丁也很简单,默认禁用了java.beans.EventHandler这个动态代理类。

Java XStream 反序列化:Gadget 挖掘思路分享

Gadget挖掘思路
以这条链的禁用进行思考新链的挖掘方式,java.beans.EventHandler这个动态代理类被禁,那么是否存在其他动态代理类,也具有这样的这样可以执行任意方法的类,毕竟动态代理类本身设计就是用来在一个方法调用时,定向调用其他的方法,如果invoke方法中对传入方法或者类检测不严格,那么就很容易产生任意方法执行,并且jdk中有非常多的动态代理实现,因此可以尝试挖掘。

把jdk的类利用tabby生成图,执行如下语句:

Java XStream 反序列化:Gadget 挖掘思路分享

以动态代理类的实现类的invoke方法为source,可控的Method.invokesink,并且不包含com.sun.org.glassfish包中的类,因为这个包中存在多个实现类似的invoke方法,对传入类做了严格限制,无法利用,为了方便排查,屏蔽这个包的结果:

Java XStream 反序列化:Gadget 挖掘思路分享

一共存在12条链路。其中可以看到有一个sun.reflect.annotation.AnnotationInvocationHandler类。看过Java反序列化的同学一定认识这个类,因为这个类就是原生反序列化中很经典的一条利用链Jdk7u21

Java XStream 反序列化:Gadget 挖掘思路分享

而这里给出的链路其实就是Jdk7u21的利用链路,既然它在原生反序列化中可以使用,那么对于适用范围更广的XStream来说,也很有可能可以用。

验证起来也很简单,直接将jdk7u21生成的对象toXML,然后再调用fromXML,就会发现是可以触发代码执行的。

Java XStream 反序列化:Gadget 挖掘思路分享

生成的XML如下:

Java XStream 反序列化:Gadget 挖掘思路分享

从前面的分析可以知道这条链最终做到的是任意方法执行TemplatesImpl.getOutputProperties方法进行字节码加载。当然这里也可以选择和CVE-2013-7285一样的ProcessBuilder.start,只需要把TemplatesImp标签替换为ProcessBuilder就可以了。

Java XStream 反序列化:Gadget 挖掘思路分享

需要注意的是这条利用链的外层入口类不再是sorted-set标签,而是linked-hash-set,原因是这条链中用到的AnnotationInvocationHandler必须触发其equals方法才能进入equalsImpl,最终触发任意代码执行。

Java XStream 反序列化:Gadget 挖掘思路分享

AnnotationInvocationHandlerEventHandler的特性非常相似,那么Java原生反序列化链是否也可以使用EventHandler?答案是否定的,原因也很简单,就是前面提到的可以被反序列化的类的类型存在限制。

Java XStream 反序列化:Gadget 挖掘思路分享

Java XStream 反序列化:Gadget 挖掘思路分享

当然这条利用链也和原生反序列化中一样,在高版本jdk被修复了,因此还是需要看之前分析结果中的其他链。分析剩下的几个类中的Method.invoke调用,会发现这些method都不可控或者无法利用,因此继续分析3层利用:

Java XStream 反序列化:Gadget 挖掘思路分享

虽然数量很多,但是链的起始点都是com.sun.corba.se.spi.orbutil.proxy.CompositeInvocationHandlerImpl

Java XStream 反序列化:Gadget 挖掘思路分享

CompositeInvocationHandlerImpl其实就是一个动态代理的封装。

Java XStream 反序列化:Gadget 挖掘思路分享

因此继续分析4层调用。

可以看到此时出现了一个sun.tracing.ProviderSkeleton,并且浅看代码,在invoke中是没有过滤的。

Java XStream 反序列化:Gadget 挖掘思路分享

因此查看下这个类开始的链:

Java XStream 反序列化:Gadget 挖掘思路分享

Java XStream 反序列化:Gadget 挖掘思路分享

invoke函数代码如下:

Java XStream 反序列化:Gadget 挖掘思路分享

可以看到上图中的两条链路对应的是var2.invoke和下方的triggerProbevar2是动态代理的方法,因此是不可控的,仅剩的一条利用链调用如下:

Java XStream 反序列化:Gadget 挖掘思路分享

这里的implementing_methodproxy都是DTraceProbe的属性,符合反序列化的要求,因此只需要按照需要构造出一个ProviderSkeleton对象就可以。构造的代码如下, 使用Unsafe构造对象可以避免生成很多用不到的属性,从而污染输出的xml。

Java XStream 反序列化:Gadget 挖掘思路分享

对于生成出来的动态代理对象XML,只需要在最外层套用一层linkedhashset,即可在其实现中调用对象的hashCode方法,从而进入动态代理的invoke函数,最终触发任意方法执行。在本例中选择的是processBuilder.start,同样的也可以使用TemplatesImpl.getOutputProperties进行代码代码执行。事实上这就是XStream CVE-2021-39149的挖掘过程。

总  结
就动态代理的利用来说,jdk已被挖掘的七七八八,XStream其他的公开利用链,基本上都基于CompareTotoStringhashCode等方法进行展开,找到一些潜在的特定格式的特定参数可控的方法执行后,再进一步填入不同的类,进行漏洞的完整利用。这种寻找Gadget的方法在Weblogic、Websphere、Dubbo hessian等固定存在序列化入口,通过黑名单进行防御的漏洞挖掘中常常被用到,不同的只是对类的限制、要求不同,在看清真实的需求的情况下,利用自动化工具一步步寻找,就可以有效地进行Gadget挖掘。

【版权说明】

本作品著作权归YYHY所有

未经作者同意,不得转载

Java XStream 反序列化:Gadget 挖掘思路分享

原文始发于微信公众号(奇安信天工实验室):Java XStream 反序列化:Gadget 挖掘思路分享

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

发表评论

匿名网友 填写信息