.NET高级代码审计(第七课) NetDataContractSerializer反序列化漏洞
字数 1671 2025-08-18 11:38:23

.NET高级代码审计:NetDataContractSerializer反序列化漏洞

一、NetDataContractSerializer概述

NetDataContractSerializer是.NET框架中用于序列化和反序列化Windows Communication Foundation (WCF)消息中数据的类。与DataContractSerializer相比,它有以下重要区别:

  1. 包含CLR类型信息:NetDataContractSerializer包含了完整的CLR类型信息,通过保存类型引用支持类型精确性
  2. 使用限制:只有在序列化和反序列化端使用相同的CLR类型时才能使用
  3. 序列化方法:WriteObject或Serialize
  4. 反序列化方法:ReadObject或Deserialize

二、NetDataContractSerializer序列化

基本序列化示例

public class TestClass
{
    public string name;
    public string classname;
    public int age;
    
    public static void ClassMethod(string cmd)
    {
        Process.Start(cmd);
    }
}

// 序列化示例
TestClass test = new TestClass();
test.name = "Ivan1ee";
test.classname = "360";
test.age = 18;

NetDataContractSerializer serializer = new NetDataContractSerializer();
using (MemoryStream ms = new MemoryStream())
{
    serializer.Serialize(ms, test);
    string xml = Encoding.UTF8.GetString(ms.ToArray());
    Console.WriteLine(xml);
}

序列化后的XML输出示例:

<TestClass z:Id="1" z:Type="WpfApp1.TestClass" z:Assembly="WpfApp1,Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" xmlns="http://schemas.datacontract.org/2004/07/WpfApp1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
    <age>18</age>
    <classname z:Id="2">360</classname>
    <name z:Id="3">Ivan1ee</name>
</TestClass>

三、NetDataContractSerializer反序列化

3.1 反序列化原理和用法

NetDataContractSerializer继承自XmlObjectSerializer抽象类和IFormatter接口,实现了以下关键方法:

  1. ReadObject:核心反序列化方法
  2. WriteObject:核心序列化方法
  3. Deserialize:内部调用ReadObject实现反序列化

反序列化示例代码:

NetDataContractSerializer serializer = new NetDataContractSerializer();
using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
{
    TestClass test = (TestClass)serializer.ReadObject(ms);
    Console.WriteLine(test.name);
}

3.2 攻击向量—MulticastDelegate

利用多路广播委托(MulticastDelegate)实现RCE的核心思路:

  1. MulticastDelegate:继承自Delegate,调用列表中可以拥有多个元素
  2. GetInvocationList:获取委托链中的委托数组
  3. Comparison:位于System.Collections.Generic命名空间,用于创建比较委托
  4. Comparer:使用Create方法创建比较器,在反序列化时重构集合排序

攻击载荷构造步骤:

  1. 使用Comparison类返回委托
  2. 使用Delegate或MulticastDelegate的Combine方法将委托添加到链中
  3. 使用Comparer的Create方法创建比较器
  4. 选择SortedSet类作为载体,利用其反序列化时重构排序的特性

四、漏洞利用与代码审计

4.1 漏洞利用点

  1. Deserialize方法:直接反序列化不可信的XML数据
  2. ReadObject方法:从不可信源读取XML流并反序列化

4.2 代码审计要点

审计时需要重点关注以下场景:

  1. 从不可信源读取XML数据并反序列化:
// 危险示例1
public void DeserializeData(string xml)
{
    NetDataContractSerializer serializer = new NetDataContractSerializer();
    using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
    {
        object obj = serializer.Deserialize(ms);
        // 处理反序列化后的对象
    }
}

// 危险示例2
public void ReadObjectData(Stream stream)
{
    NetDataContractSerializer serializer = new NetDataContractSerializer();
    object obj = serializer.ReadObject(stream);
    // 处理反序列化后的对象
}
  1. 从文件读取XML内容并反序列化:
public void LoadFromFile(string path)
{
    string xml = File.ReadAllText(path);
    NetDataContractSerializer serializer = new NetDataContractSerializer();
    using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
    {
        object obj = serializer.Deserialize(ms);
        // 处理反序列化后的对象
    }
}

五、漏洞复现与防御

5.1 漏洞复现

  1. 构造恶意XML载荷(完整POC见原文)
  2. 将载荷传递给存在漏洞的反序列化方法
  3. 成功执行任意命令(如弹出计算器)

5.2 防御措施

  1. 避免反序列化不可信数据:不要反序列化来自不可信源的XML数据
  2. 使用安全替代方案
    • 使用DataContractSerializer代替NetDataContractSerializer
    • 使用Json.NET等更安全的序列化器
  3. 输入验证:对反序列化的XML数据进行严格验证
  4. 类型限制:使用SerializationBinder限制反序列化的类型

六、总结

  1. NetDataContractSerializer由于包含完整的CLR类型信息,比DataContractSerializer更容易触发反序列化漏洞
  2. 通过MulticastDelegate和Comparer的组合可以实现远程代码执行
  3. 在代码审计时需要特别关注ReadObject和Deserialize方法的使用场景
  4. 在必须使用NetDataContractSerializer的场景下,应采取严格的安全措施防止反序列化攻击

附录:相关资源

  1. .NET反序列化系列课程
  2. .NET安全知识库
  3. 原文提供的完整攻击POC(见原文XML部分)
.NET高级代码审计:NetDataContractSerializer反序列化漏洞 一、NetDataContractSerializer概述 NetDataContractSerializer是.NET框架中用于序列化和反序列化Windows Communication Foundation (WCF)消息中数据的类。与DataContractSerializer相比,它有以下重要区别: 包含CLR类型信息 :NetDataContractSerializer包含了完整的CLR类型信息,通过保存类型引用支持类型精确性 使用限制 :只有在序列化和反序列化端使用相同的CLR类型时才能使用 序列化方法 :WriteObject或Serialize 反序列化方法 :ReadObject或Deserialize 二、NetDataContractSerializer序列化 基本序列化示例 序列化后的XML输出示例: 三、NetDataContractSerializer反序列化 3.1 反序列化原理和用法 NetDataContractSerializer继承自XmlObjectSerializer抽象类和IFormatter接口,实现了以下关键方法: ReadObject :核心反序列化方法 WriteObject :核心序列化方法 Deserialize :内部调用ReadObject实现反序列化 反序列化示例代码: 3.2 攻击向量—MulticastDelegate 利用多路广播委托(MulticastDelegate)实现RCE的核心思路: MulticastDelegate :继承自Delegate,调用列表中可以拥有多个元素 GetInvocationList :获取委托链中的委托数组 Comparison 类 :位于System.Collections.Generic命名空间,用于创建比较委托 Comparer 类 :使用Create方法创建比较器,在反序列化时重构集合排序 攻击载荷构造步骤: 使用Comparison 类返回委托 使用Delegate或MulticastDelegate的Combine方法将委托添加到链中 使用Comparer 的Create方法创建比较器 选择SortedSet 类作为载体,利用其反序列化时重构排序的特性 四、漏洞利用与代码审计 4.1 漏洞利用点 Deserialize方法 :直接反序列化不可信的XML数据 ReadObject方法 :从不可信源读取XML流并反序列化 4.2 代码审计要点 审计时需要重点关注以下场景: 从不可信源读取XML数据并反序列化: 从文件读取XML内容并反序列化: 五、漏洞复现与防御 5.1 漏洞复现 构造恶意XML载荷(完整POC见原文) 将载荷传递给存在漏洞的反序列化方法 成功执行任意命令(如弹出计算器) 5.2 防御措施 避免反序列化不可信数据 :不要反序列化来自不可信源的XML数据 使用安全替代方案 : 使用DataContractSerializer代替NetDataContractSerializer 使用Json.NET等更安全的序列化器 输入验证 :对反序列化的XML数据进行严格验证 类型限制 :使用SerializationBinder限制反序列化的类型 六、总结 NetDataContractSerializer由于包含完整的CLR类型信息,比DataContractSerializer更容易触发反序列化漏洞 通过MulticastDelegate和Comparer 的组合可以实现远程代码执行 在代码审计时需要特别关注ReadObject和Deserialize方法的使用场景 在必须使用NetDataContractSerializer的场景下,应采取严格的安全措施防止反序列化攻击 附录:相关资源 .NET反序列化系列课程 .NET安全知识库 原文提供的完整攻击POC(见原文XML部分)