WebLogic CVE-2020-14756 T3/IIOP 反序列化RCE 

# 复现
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/0a190c57-1208-6f7e-7e89-6049cb59eea1.png)

# 分析
在coherence包中 `com.tangosol.io.ExternalizableLite` 存在反序列化接口

其借助`com.tangosol.io.ExternalizableLite`实现序列化反序列化逻辑
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/6a4fe436-c41c-e8e2-ef25-3c35769a4849.png)

在ExternalizableLite中有readObjcet()

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/d50b0196-52cb-a83a-dc44-87ffa987969f.png)

readObjectInternal()会根据nType进入不同的反序列化函数

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/6861a1ca-9bba-1148-9225-05900de5b633.png)

其中nType在writeObject中由getStreamFormat()决定。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/d3a54113-9b21-59e8-0fec-33039928de0c.png)

代码如下

```java
public static int getStreamFormat(Object o) {
    return o == null ? 0 : (o instanceof String ? 6 : (o instanceof Number ? (o instanceof Integer ? 1 : (o instanceof Long ? 2 : (o instanceof Double ? 3 : (o instanceof BigInteger ? 4 : (o instanceof BigDecimal ? 5 : (o instanceof Float ? 14 : (o instanceof Short ? 15 : (o instanceof Byte ? 16 : 11)))))))) : (o instanceof byte[] ? 8 : (o instanceof ReadBuffer ? 7 : (o instanceof XmlBean ? 12 : (o instanceof ExternalizableHelper.IntDecoratedObject ? 13 : (o instanceof ExternalizableLite ? 10 : (o instanceof Boolean ? 17 : (o instanceof Serializable ? 11 : (o instanceof Optional ? 22 : (o instanceof OptionalInt ? 23 : (o instanceof OptionalLong ? 24 : (o instanceof OptionalDouble ? 25 : (o instanceof XmlSerializable ? 9 : 255))))))))))))));
}
```

10对应的是实现了ExternalizableLite接口的类。继续跟进readExternalizableLite()，其使用loadClass进行加载类，不受weblogic黑名单限制。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/c182838b-e994-4a44-5fd3-2c29b3391587.png)


那么现在就可以调用黑名单类中的 readExternal 方法，作者使用的是之前漏洞中使用过的`com.tangosol.coherence.rest.util.extractor.MvelExtractor`，它实现了ExternalizableLite接口。

在其MvelExtractor的readExternal()中进行了m_sExpr表达式赋值，而m_sExpr是可控的。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/d5d67603-a081-d8a7-e935-d50d62b2ac4b.png)

那么只需要触发extract方法就行了。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/b133c2d4-4424-8e74-145c-998d413a5542.png)


现在就在于如何触发extract方法。找到`com.tangosol.util.aggregator.TopNAggregator.PartialResult`类，在他的readExternal()中

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/5f3326f9-898b-9bc9-1887-bc66257fea3d.png)

会自动触发`this.instantiateInternalMap(this.m_comparator)`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/cb4d253a-92ba-5644-dbfe-91d06f538841.png)

这里返回一个map，而其中的comparator可控为我们的MvelExtractor。回头再看上图for循环中的`this.add(ExternalizableHelper.readObject(in))`

add()方法

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/02a8404b-e0e1-a9b0-7520-604e0f64ebde.png)

跟进 super.add(value) `com.tangosol.util.SortedBag#add`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/e127cf8c-fd05-d1cc-9127-41e2261fb3a8.png)

从自身拿到一个map

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/095f64a6-0664-236b-b3ef-278734b21cd9.png)

然后进行map.put，跟进`java.util.TreeMap#put`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/9542c02c-2fd0-856a-9744-d1632e36f658.png)

然后

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/2c0e4321-5915-d350-5b00-bac91c550b3a.png)

这里进入到MvelExtractor父类的`com.tangosol.util.extractor.AbstractExtractor#compare`方法，调用了extract方法。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/df300dd0-158d-e75e-d8f2-1ca474d27da9.png)

然后就成了，但是还有个问题，`com.tangosol.util.aggregator.TopNAggregator.PartialResult`类并没有实现ExternalizableLite接口，因此readExternal在反序列化时不会被触发，所以需要寻找一个实现了Externalizable接口的类，并能调用ExternalizableHelper.readObject方法。

找到`com.tangosol.coherence.servlet.AttributeHolder#readExternal(java.io.DataInput)`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/97437be9-84f2-ea7d-0ea4-4183348e4faf.png)

在其readExternal调用了ExternalizableHelper.readObject，可以触发PartialResult的readExternal。

堆栈

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/e66b9b6d-1878-9105-f872-45cdbb5d6cb1.png)


# EXP
[见我的GitHub](https://github.com/Y4er/CVE-2020-14756)


# 思考

在com.tangosol.util.ExternalizableHelper#readObjectInternal中nType有多种类型

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/1310d8b3-8a16-091b-2da5-1858840c654e.png)

其他的case应该也有漏洞吧

# 参考
1. https://mp.weixin.qq.com/s/E-4wjbKD-iSi0CEMegVmZQ