weblogic-CVE-2020-14756漏洞分析
字数 1741 2025-08-05 11:39:37
WebLogic CVE-2020-14756漏洞深度分析与利用教学
漏洞概述
CVE-2020-14756是Oracle WebLogic Server中的一个远程代码执行漏洞,影响WebLogic Server 12.2.1.3.0、12.2.1.4.0和14.1.1.0.0版本。该漏洞允许未经身份验证的攻击者通过T3协议发送精心构造的恶意请求,在目标系统上执行任意代码。
漏洞原理分析
漏洞利用链分析
漏洞利用链(gadget chain)如下:
com.tangosol.coherence.servlet.AttributeHolder.readExternal()
→ ExternalizableHelper.readObject()
→ ExternalizableHelper.readObjectInternal()
→ ExternalizableHelper.readExternalizableLite()
→ TopNAggregator.PartialResult.readExternal()
→ TopNAggregator.PartialResult.add()
→ (AbstractExtractor)MvelExtractor.compare()
→ MvelExtractor.extract()
→ MVEL.executeExpression()
关键组件分析
-
MvelExtractor:
- 这是漏洞的最终执行点,通过其
extract()方法执行MVEL表达式 - 继承自
AbstractExtractor,使用父类的compare()方法 compare()方法内部会调用extract()方法
- 这是漏洞的最终执行点,通过其
-
TopNAggregator.PartialResult:
- 实现了
ExternalizableLite接口 - 在
readExternal()方法中通过ExternalizableHelper.readObject()加载比较器对象 - 在
add()方法中调用比较器的compare()方法
- 实现了
-
AttributeHolder:
- 作为整个利用链的入口点
- 在
readExternal()方法中调用ExternalizableHelper.readObject()
漏洞利用条件
- 恶意类需要实现
ExternalizableLite接口 - 需要找到合适的非恶意类作为包装类,满足以下条件:
- 不在WebLogic的黑名单中
- 其
readObject、readExternal或readResolve方法中调用ExternalizableHelper.readObject() - 对
ExternalizableHelper.readObject()还原的对象调用extract或compare方法
漏洞挖掘思路
补丁分析
通过对比补丁前后的代码,发现关键修改点在ExternalizableHelper类中:
// 补丁前
String sClass = readUTF((DataInput)in);
value = (ExternalizableLite)loadClass(sClass, loader, inWrapper == null ? null : inWrapper.getClassLoader()).newInstance();
// 补丁后
// 增加了黑名单检查
String sClass = readUTF((DataInput)in);
Class clz = loadClass(sClass, loader, inWrapper == null ? null : inWrapper.getClassLoader());
checkObjectInputFilter(clz);
value = (ExternalizableLite)clz.newInstance();
绕过黑名单机制
WebLogic的黑名单检测点:
readObject调用的resolveClass方法readExternal的resolveClass方法readResolve的resolveClass方法
本漏洞的绕过方式:
- 使用非恶意类作为最上层类(如
AttributeHolder) - 通过该类的
readExternal方法间接加载恶意类(MvelExtractor) - 利用调用链最终触发恶意代码执行
漏洞利用详细步骤
1. 构造恶意对象
需要构造一个AttributeHolder对象,其m_oValue属性设置为精心构造的TopNAggregator.PartialResult对象:
// 创建MVEL表达式执行器
MvelExtractor extractor = new MvelExtractor("恶意MVEL表达式");
// 创建TopNAggregator.PartialResult对象
TopNAggregator.PartialResult partialResult = new TopNAggregator.PartialResult(extractor, 1);
partialResult.add("触发点"); // 确保在反序列化时会进入add方法
// 创建AttributeHolder对象
AttributeHolder holder = new AttributeHolder();
holder.setName("任意名称");
holder.setValue(partialResult);
2. 序列化对象
将构造好的AttributeHolder对象序列化为字节流,准备发送给目标WebLogic服务器。
3. 通过T3协议发送
将序列化后的恶意对象通过WebLogic的T3协议发送到目标服务器。
技术细节说明
PartialResult的构造要求
在PartialResult的readExternal方法中,需要满足以下条件才能进入add方法:
int cElems = in.readInt(); // 需要设置元素数量>0
for(int i = 0; i < cElems; ++i) {
this.add(ExternalizableHelper.readObject(in)); // 需要进入这个循环
}
因此,在构造payload时,需要确保:
- 设置
m_cMaxSize大于0 - 提供至少一个元素供反序列化时添加
MVEL表达式执行
MvelExtractor的extract方法最终会执行:
MVEL.executeExpression(this.m_expr, target);
可以构造如下的MVEL表达式实现RCE:
"Runtime.getRuntime().exec(\"calc\")"
补丁分析
Oracle通过以下方式修复此漏洞:
- 在
ExternalizableHelper.loadClass()前增加黑名单检查 - 将
MvelExtractor加入黑名单,阻止其被加载
关键补丁代码:
// 新增的黑名单检查方法
private static void checkObjectInputFilter(Class clz) {
String className = clz.getName();
// 检查类名是否在黑名单中
if (className != null && !className.isEmpty()) {
if (FilterChecker.check(className)) {
throw new InvalidObjectException("Unauthorized deserialization attempt");
}
}
}
防御建议
- 及时安装Oracle官方发布的安全补丁
- 限制T3协议的访问,只允许可信网络访问
- 使用WebLogic的网络安全配置限制反序列化操作
- 监控和过滤可疑的T3协议流量