0x00 前言
不安全的反序列化漏洞已经逐渐成为攻击者/研究人员在面对Java Web应用时寻找的目标。这些漏洞通常能得到可靠的远程代码执行(RCE)效果,并且修复起来比较困难。在本文中,我们将分析CVE-2020-2555(ZDI-20-128)漏洞,该漏洞由来自VNPT ISC的Jang提交。这个漏洞级别较高(CVSS评分9.8),存在于Oracle Coherence
库中,从而影响使用该库的Oracle WebLogic服务器等常见产品。官方在1月份修复了包括该漏洞在内的300多个漏洞。
0x01 补丁分析
漏洞根源存在于某个Java方法中,攻击者可以调用该方法,并且能控制相关参数。在Java中,当重新创建对象图时,类的readObject()
或readExternal()
会被自动调用。因此,这两个方法(以及在方法内部可达的其他方法)可以被视为反序列化gadget的根源点。
CVE-2020-2555的补丁引入了非常有趣的一处修改,涉及LimitFilter
类的toString()
方法:
补丁在toString()
中删除了对extract()
方法的所有调用语句,下文中将重点分析extract()
方法的重要性。这种修改操作非常有趣,因为我们可以通过各种标准的JRE类(如BadAttributeValueExpException
)的readObject()
方法,成功访问toString()
方法。
如上图所示,经过序列化的BadAttributeValueExpException
类实例可以用来调用任意类的toString()
方法。这种技术可以用来访问受此补丁影响的LimitFilter
类的toString()
方法。
关于使用toString()
作为入口点的gadget,大家可以参考ysoserial项目的CommonsCollections5 gadget.
0x02 寻找sink点
Sink点指的是具有各种副作用的Java方法调用,这类副作用包括:
1、通过调用FileOutputStream.write()
实现任意文件创建;
2、通过调用Runtime.exec()
实现任意命令执行;
3、通过调用Method.invoke()
实现任意方法调用。
对于该漏洞,我们主要关注的是Method.invoke()
,该调用能通过反射来调用任意Java方法。了解该信息后,我们开始查找具备extract()
方法的所有实例(根据前文分析,该方法正是补丁分析后我们得出的根源点),并且最终会调用Method.invoke()
。在Coherence
库中,似乎只有一个可序列化类(实现Serializable
或者Externalizable
接口)实例满足条件。
观察ReflectionExtractor
类后,我们可以进一步确认前面的猜测:
ReflectionExtractor
提供了一种较为危险的操作原语,可以让攻击者调用任意方法,并且攻击者可以控制具体方法及相关参数。
0x03 实现RCE
通常情况下,攻击者需要调用多个方法才能实现RCE。比如,在常见的Apache Commons Collections gadget中,攻击者需要使用ChainedTransformer
将任意方法调用串接起来,从而实现RCE。与此类似,Coherence
库中也提供了这样一个类(ChainedExtractor
),可以让我们串接extract()
调用:
将以上信息结合起来,我们可以使用如下调用链,最终实现远程代码执行:
因此,如果有目标环境使用了Coherence
库,并且攻击者可以投递恶意序列化对象,那么攻击者就能实现远程代码执行。为了演示攻击环境,这里我们以WebLogic的T3协议作为目标,具体操作过程可参考此处视频。
0x04 总结
自从Chris Frohoff和Gabriel Lawrence在AppSecCali提出Java反序列化相关概念后,研究人员就一直在寻找反序列化漏洞,以实现可靠的代码执行。在针对SCADA应用的Pwn2Own Miami活动中,我们已经收到了多个这类报告,这也是我们在相关报告中特别关注反序列化问题的原因之一。