.NET高级代码审计(第二课) Json.Net反序列化漏洞
字数 1810 2025-08-18 11:38:08
.NET高级代码审计:Json.Net反序列化漏洞深度解析
一、Json.Net库概述
Newtonsoft.Json(Json.NET)是一个高性能的.NET JSON操作类库,主要功能包括:
- 实现.NET对象与JSON之间的转换
- 提供序列化(SerializeObject)和反序列化(DeserializeObject)方法
- 支持丰富的自定义序列化配置选项
性能对比:Json.NET在性能上优于微软内置的DataContractJsonSerializer和JavaScriptSerializer
二、Json.Net序列化机制
基本序列化示例
public class TestClass
{
[JsonIgnore]
public string Classname { get; set; } // 被忽略的属性
public string Name { get; set; }
public int Age { get; set; }
public static void ClassMethod(string file)
{
Process.Start(file);
}
}
// 序列化过程
var testClass = new TestClass { Name = "Ivan1ee", Age = 18 };
string jsonString = JsonConvert.SerializeObject(testClass);
关键点:
- 静态方法不参与序列化过程
- 使用
[JsonIgnore]特性可忽略特定属性
高级序列化配置
var settings = new JsonSerializerSettings
{
TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Full,
TypeNameHandling = TypeNameHandling.All
};
string testString = JsonConvert.SerializeObject(testClass, settings);
配置选项:
TypeNameAssemblyFormatHandling:控制程序集名称格式TypeNameHandling:控制类型名称处理方式
三、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 攻击向量分析
攻击向量1:ObjectDataProvider
漏洞原理:
当TypeNameHandling设置为非None值时,攻击者可构造恶意JSON实现RCE
PoC构造步骤:
- 序列化TestClass获取基础JSON结构
- 替换关键字段:
- 修改
$type为攻击目标类型 - 设置
MethodName为要执行的方法 - 配置
MethodParameters参数
- 修改
示例攻击JSON:
{
"$type": "System.Diagnostics.Process, System",
"StartInfo": {
"$type": "System.Diagnostics.ProcessStartInfo, System",
"FileName": "calc.exe",
"Arguments": ""
}
}
攻击向量2:WindowsIdentity
漏洞原理:
利用WindowsIdentity类的ISerializable接口实现和BootstrapContext属性
关键类分析:
System.Security.Principal.WindowsIdentitySystem.Security.Claims.ClaimsIdentitySystem.Runtime.Serialization.ISerializable
攻击步骤:
- 构造恶意BootstrapContext值(base64编码的payload)
- 通过ISerializable接口的GetObjectData方法注入恶意数据
- 反序列化时触发代码执行
示例代码:
var identity = new WindowsIdentityTest();
string json = JsonConvert.SerializeObject(identity, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All
});
// 修改$type为WindowsIdentity完全限定名
json = json.Replace(
"\"$type\":\"WindowsIdentityTest\"",
"\"$type\":\"System.Security.Principal.WindowsIdentity\"");
3.3 漏洞触发条件
- 反序列化时TypeNameHandling设置为非None值
- 攻击者能够控制输入JSON数据
- 目标环境中存在可利用的类和方法
四、代码审计要点
危险模式识别
- 直接风险:
JsonConvert.DeserializeObject(inputJson, new JsonSerializerSettings {
TypeNameHandling = TypeNameHandling.All // 高风险
});
- 间接风险:
JsonConvert.DeserializeObject(inputJson, new JsonSerializerSettings {
TypeNameHandling = TypeNameHandling.Auto // 仍然危险
});
- 安全模式:
JsonConvert.DeserializeObject(inputJson, new JsonSerializerSettings {
TypeNameHandling = TypeNameHandling.None // 安全
});
审计关注点
- 查找所有JsonConvert.DeserializeObject调用
- 检查TypeNameHandling参数设置
- 确认输入数据是否可控
- 检查是否有自定义JsonConverter实现
五、防御建议
-
输入验证:
- 严格验证反序列化的JSON输入
- 使用白名单限制允许的类型
-
安全配置:
- 尽可能使用TypeNameHandling.None
- 如需使用类型信息,限制反序列化类型:
var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects, SerializationBinder = new MyCustomBinder() // 自定义绑定器限制类型 };
-
替代方案:
- 考虑使用System.Text.Json(.NET Core 3.0+)替代Newtonsoft.Json
- 使用安全反序列化库
六、漏洞复现案例
复现步骤
- 构造恶意JSON payload
- 通过Web接口提交payload
- 服务器端反序列化触发RCE
示例攻击流程:
- 访问
http://localhost:5651/DefaultPost - 提交恶意JSON数据
- 服务器调用
JsonConvert.DeserializeObject反序列化 - 触发计算器弹出(证明RCE成功)
七、总结
- Json.NET反序列化漏洞源于不安全的TypeNameHandling配置
- 主要攻击向量包括ObjectDataProvider和WindowsIdentity
- 漏洞危害严重,可导致远程代码执行
- 代码审计时应重点关注TypeNameHandling配置和输入控制
- 防御关键在于限制类型处理和验证输入数据
扩展资源: