CVE-2020-14756 漏洞利用以及分析
0x01利用思路
weblogic
的T3
协议反序列化漏洞一直是一个比较热门也比较好用的漏洞,weblogic
针对该漏洞的解决方案就是不断填充黑名单,在高版本jdk
下配合jep290
机制实现黑名单,在低版本下配合resolveClass
进行防御,所以安全人员对于T3
反序列化的利用也是一直在寻找黑名单之外的利用链。
CVE-2020-14756
这个漏洞的利用比较巧妙,通过利用weblogic coherence
组件中的类,绕过了黑名单机制的检测,重新能够利用黑名单中的类,造成代码执行。
0x02漏洞分析
在weblogic
的coherence.jar
中,存在着一个比较特殊的接口com.tangosol.io.ExternalizableLite
,他继承了Serializable
接口。
readExternal
和writeExternal
方法
而ExternalizableLite
接口的对象可以在com.tangosol.util.ExternalizableHelper
里被序列化。
这里的nType
是在writeObject写入的,是可控的
readExternalizableLite
方法的具体内容为:
这里会加载传入的对象,对象需要是ExternalizableLite
的实现类
这里直接调用class.forName
还原对象
之后,会继续调用对象的readExternal
方法,这样一来,后续的流程就绕过了ObjectInputStream对于对象的还原,而weblogic的黑名单检测也主要是针对ObjectInputStream
的,所以,现在只需要找到后续的利用链就可以造成代码执行。
漏洞发现者使用了com.tangosol.util.aggregator.TopNAggregator.PartialResult
这个类。这里会利用ExternalizableHelper
还原m_comparator
参数,是一个Comparator
类型的对象。
然后调用了instantiateInternalMap
方法,传入m_comparator
首先实例化SortedBag.WrapperComparator
,赋值f_comparator
,然后返回TreeMap
对象
接着,调用add方法,在add方法里调用super.add
,即SortedBag.add
,继续调用put
方法。
在put
方法里,调用了compare
方法
而这里又会调用WrapperComparator
的compare
方法
这个f_comparator
就是之前已经赋值过的。
所以,最终的利用就在f_comparator
这里,f_comparator
从前面可以知道,需要是一个Comparator
类型,这里使用的是 MvelExtractor
这是之前黑名单里的一个类,在CVE-2020-2555中有使用,不过现在我们不受黑名单的限制,MvelExtractor
没有compare
方法。于是调用父类AbstractExtractor
的compare
方法。
然后又会调用子类MvelExtractor
的extract
方法。
序列化入口一
到现在我们的入口是TopNAggregator$PartialResult
,他的readExternal(DataInput in)
不是标准的readExternal(ObjectInput in)
,序列化的过程中是不会自动调用到该方法的,所以还需要找一个入口,这里作者发现了AttributeHolder
。
这里不但会将ObjectInput
转为DataInput
,还会主动调用ExternalizableHelper.readObject
。所以我们只需要m_oValue
是TopNAggregator$PartialResult
即可完成利用。
调用栈
序列化入口二
另外一个入口是com.tangosol.net.security.PermissionInfo
,我们看他的readExternal
方法,将输入流传入readCollection
方法里,PermissionInfo
是ExternalizableHelper
的子类,所以这里PermissionInfo
没有readCollection
方法,直接调用其父类ExternalizableHelper
的方法。
判断输入流类型之后,调用了readObject
。
在调用readCollection
的时候,将ObjectInput
转为了DataInput
走到这里,就和之前的流程一模一样了。
调用栈
0x03 12.1.3版本问题
经测试,12.1.3
利用存在如下问题
从前面的分析可以知道,类的加载是在loadClass
方法里,利用class.forName
去加载类。
这里的loader
就很关键了,决定了哪些类可以加载,哪些类没发加载,这里的loader
是调用getContextClassLoader
获得的一个线程上下文类加载器。
这里的线程上下文类加载器是默认的 AppClassLoader
,在loaders
里发现JarLoader
加载了的coherence
组件的依赖只有coherence.jar
和coherence-web.jar
,而MvelExtractor
在coherence-rest.jar
里,所以没有办法加载。
以下是一些尝试(未成功):
于是我这里先是考虑了另一个在黑名单的类,ReflectionExtractor
,这个类在coherence.jar
包下,不过在构造利用这个反射执行链的时候,需要反序列化Runtime.class
对象,而Runtime.class
对象不是ExternalizableLite
的实现类,根据nType
,在序列化的时候会调用readSerializeable
方法
该方法还是会走ObjectInputStream
的反序列化流程,即使是通过修改nType
让他走readExternalizable
,后面还是会有类型转换报错。
所以这样是不行的,12.1.3版本很多类都利用不了,比如RemoteConstructor
、UniversalExtractor
、LockVersionExtractor
这些类在 12.1.3
版本中都没有,已知的利用链在 12.1.3 来说是没有办法进行利用的。
0x04官方修复之梅开二度
(补丁只能针对实现了jep290
的jdk
)
根据补丁来看:
对输入流的类型进行了判断,如果是ObjectInputStream
,那么会去调用checkObjectInputFilter
方法,方法如下:
这里会获取filter
,在ExternalizableHelper
的静态代码块里初始化了filter
首先会获取是否存在ObjectInputFilter
,来判断jdk
环境中是否存在jep290
。
然后通过getObjectInputFilter/getInternalObjectInputFilter
方法去获取serialFilter
,之后,调用checkInput
,对当前序列化的类进行检测。
不过,对于没有实现jep290
的jdk
版本而言,这个修补是没有作用的,因为低版本jdk
不存在ObjectInputFilter
,所以说filter
参数就为null
,也就是说checkObjectInputFilter
方法直接返回true
。
既然为true
,那么还是能进行类的实例化。
- 本文作者: 带头大哥
- 本文来源: 奇安信攻防社区
- 原文链接: https://forum.butian.net/share/41
- 版权声明: 除特别声明外,本文各项权利归原文作者和发表平台所有。转载请注明出处!