.NET高级代码审计(第四课)JavaScriptSerializer反序列化漏洞
字数 1332 2025-08-18 11:38:08

JavaScriptSerializer反序列化漏洞分析与防御

一、概述

JavaScriptSerializer是.NET Framework 2.0之后提供的JSON序列化和反序列化类,位于System.Web.Script.Serialization命名空间,通过System.Web.Extensions引用。当开发者使用DeserializeDeserializeObject方法处理不安全的JSON数据时,可能导致反序列化攻击,实现远程代码执行(RCE)。

二、JavaScriptSerializer序列化机制

基本序列化示例

public class TestClass {
    public string Name { get; set; }
    public string Age { get; set; }
    public string Address { get; set; }
    
    public static void ClassMethod(string cmd)
    {
        Process.Start(cmd);
    }
}

// 序列化示例
TestClass test = new TestClass {
    Name = "Ivan1ee",
    Age = "18",
    Address = "BeiJing"
};

JavaScriptSerializer serializer = new JavaScriptSerializer();
string json = serializer.Serialize(test);

默认序列化输出:

{"Name":"Ivan1ee","Age":"18","Address":"BeiJing"}

使用类型解析器

JavaScriptSerializer serializer = new JavaScriptSerializer(new SimpleTypeResolver());
string json = serializer.Serialize(test);

添加SimpleTypeResolver后的输出包含程序集全标识:

{"__type":"TestClass, AppName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null","Name":"Ivan1ee","Age":"18","Address":"BeiJing"}

三、反序列化漏洞原理

反序列化流程

  1. DeserializeObjectDeserialize方法调用DeserializeInternal
  2. 检查字典中是否包含__type键(ServerTypeFieldName常量)
  3. 通过ConvertObjectToTypeConvertObjectToTypeMainConvertObjectToTypeInternal方法链处理
  4. 最终在ConvertDictionaryToObject方法中:
    • 获取__type
    • 强制转换为字符串serverTypeName
    • 通过System.Activator.CreateInstance创建实例

漏洞触发条件

  1. 初始化JavaScriptSerializer时使用了SimpleTypeResolver
  2. 反序列化的JSON数据可控
  3. JSON中包含恶意构造的__type字段

四、漏洞利用

利用ObjectDataProvider类

{
    "__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"
        }
    }
}

漏洞触发代码

string json = "恶意JSON数据";
JavaScriptSerializer serializer = new JavaScriptSerializer(new SimpleTypeResolver());
serializer.Deserialize<Object>(json);

五、代码审计要点

危险代码模式

  1. 使用SimpleTypeResolverJavaScriptSerializer初始化:
// 危险代码
JavaScriptSerializer serializer = new JavaScriptSerializer(new SimpleTypeResolver());
serializer.Deserialize(input);
  1. 直接反序列化不可信输入:
// 危险代码
public object DeserializeJson(string input)
{
    JavaScriptSerializer serializer = new JavaScriptSerializer();
    return serializer.DeserializeObject(input);
}

安全代码模式

  1. 不使用类型解析器(默认安全):
// 安全代码
JavaScriptSerializer serializer = new JavaScriptSerializer();
  1. 使用自定义安全类型解析器(白名单):
public class SafeTypeResolver : JavaScriptTypeResolver
{
    public override Type ResolveType(string id)
    {
        // 只允许特定类型
        if (id == typeof(SafeClass).AssemblyQualifiedName)
            return typeof(SafeClass);
        return null;
    }
    
    public override string ResolveTypeId(Type type)
    {
        return type.AssemblyQualifiedName;
    }
}

六、防御措施

  1. 避免使用SimpleTypeResolver:默认情况下JavaScriptSerializer不使用类型解析器是安全的
  2. 使用白名单机制:如需使用类型解析器,实现自定义解析器并限制可反序列化的类型
  3. 验证输入数据:反序列化前验证JSON数据,过滤可疑内容
  4. 使用替代方案:考虑使用更安全的JSON库如Newtonsoft.Json(需正确配置)
  5. 最小权限原则:运行应用程序的账户应具有最小必要权限

七、总结

JavaScriptSerializer反序列化漏洞的关键在于:

  1. 使用了SimpleTypeResolver类型解析器
  2. 反序列化了不可信的JSON数据
  3. JSON中包含恶意构造的__type字段指定危险类型

在开发中应避免直接反序列化不可信数据,如需处理外部JSON输入,应使用安全的配置或替代方案。审计时应重点关注JavaScriptSerializer初始化时是否使用了类型解析器,以及反序列化的数据来源是否可控。

JavaScriptSerializer反序列化漏洞分析与防御 一、概述 JavaScriptSerializer是.NET Framework 2.0之后提供的JSON序列化和反序列化类,位于 System.Web.Script.Serialization 命名空间,通过 System.Web.Extensions 引用。当开发者使用 Deserialize 或 DeserializeObject 方法处理不安全的JSON数据时,可能导致反序列化攻击,实现远程代码执行(RCE)。 二、JavaScriptSerializer序列化机制 基本序列化示例 默认序列化输出: 使用类型解析器 添加 SimpleTypeResolver 后的输出包含程序集全标识: 三、反序列化漏洞原理 反序列化流程 DeserializeObject 或 Deserialize 方法调用 DeserializeInternal 检查字典中是否包含 __type 键( ServerTypeFieldName 常量) 通过 ConvertObjectToType 、 ConvertObjectToTypeMain 、 ConvertObjectToTypeInternal 方法链处理 最终在 ConvertDictionaryToObject 方法中: 获取 __type 值 强制转换为字符串 serverTypeName 通过 System.Activator.CreateInstance 创建实例 漏洞触发条件 初始化 JavaScriptSerializer 时使用了 SimpleTypeResolver 反序列化的JSON数据可控 JSON中包含恶意构造的 __type 字段 四、漏洞利用 利用ObjectDataProvider类 漏洞触发代码 五、代码审计要点 危险代码模式 使用 SimpleTypeResolver 的 JavaScriptSerializer 初始化: 直接反序列化不可信输入: 安全代码模式 不使用类型解析器(默认安全): 使用自定义安全类型解析器(白名单): 六、防御措施 避免使用SimpleTypeResolver :默认情况下 JavaScriptSerializer 不使用类型解析器是安全的 使用白名单机制 :如需使用类型解析器,实现自定义解析器并限制可反序列化的类型 验证输入数据 :反序列化前验证JSON数据,过滤可疑内容 使用替代方案 :考虑使用更安全的JSON库如 Newtonsoft.Json (需正确配置) 最小权限原则 :运行应用程序的账户应具有最小必要权限 七、总结 JavaScriptSerializer 反序列化漏洞的关键在于: 使用了 SimpleTypeResolver 类型解析器 反序列化了不可信的JSON数据 JSON中包含恶意构造的 __type 字段指定危险类型 在开发中应避免直接反序列化不可信数据,如需处理外部JSON输入,应使用安全的配置或替代方案。审计时应重点关注 JavaScriptSerializer 初始化时是否使用了类型解析器,以及反序列化的数据来源是否可控。