.NET高级代码审计(第九课) BinaryFormatter反序列化漏洞
字数 1663 2025-08-18 11:38:28

.NET BinaryFormatter 反序列化漏洞深度解析

一、BinaryFormatter 概述

BinaryFormatter 是 .NET 框架中的一个类,位于 System.Runtime.Serialization.Formatters.Binary 命名空间,用于将对象序列化为二进制格式或从二进制格式反序列化对象。

主要特点:

  • 使用二进制格式进行序列化
  • 序列化速度快
  • 跨 .NET 版本兼容性好
  • 支持泛型等数据类型

二、BinaryFormatter 序列化机制

2.1 基本序列化方法

要使类可序列化,需要使用 [Serializable] 特性标记。如果某些成员不需要序列化,可以使用 [NoSerialized] 特性。

[Serializable]
public class TestClass
{
    public string Name { get; set; }
    public int Age { get; set; }
    [NonSerialized]
    public string Secret; // 不会被序列化
    
    public static void ClassMethod(string process)
    {
        Process.Start(process);
    }
}

2.2 序列化过程

TestClass test = new TestClass { Name = "Ivan1ee", Age = 18 };
BinaryFormatter formatter = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream())
{
    formatter.Serialize(ms, test);
    byte[] serializedData = ms.ToArray();
    // 保存或传输 serializedData
}

序列化后的二进制数据格式包含类型信息和对象状态数据。

三、BinaryFormatter 反序列化机制

3.1 反序列化方法

BinaryFormatter 提供了四个主要的反序列化方法:

  1. Deserialize(Stream)
  2. DeserializeMethodResponse(Stream, HeaderHandler, IFormatterConverter)
  3. UnsafeDeserialize(Stream, HeaderHandler)
  4. UnsafeDeserializeMethodResponse(Stream, HeaderHandler, IFormatterConverter)

3.2 基本反序列化示例

BinaryFormatter formatter = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream(serializedData))
{
    TestClass obj = (TestClass)formatter.Deserialize(ms);
    Console.WriteLine(obj.Name); // 输出反序列化后的Name值
}

四、BinaryFormatter 反序列化漏洞

4.1 漏洞原理

BinaryFormatter 反序列化时会完全重建对象图,包括执行对象的构造函数、属性设置器等。攻击者可以构造恶意序列化数据,在反序列化过程中执行任意代码。

4.2 主要攻击向量

4.2.1 ActivitySurrogateSelector 攻击

通过重写 ISerializationSurrogate 接口,可以在反序列化过程中执行自定义代码:

// 恶意SurrogateSelector实现
var surrogateSelector = new SurrogateSelector();
var surrogate = new MySurrogate();
surrogateSelector.AddSurrogate(typeof(Process), 
    new StreamingContext(StreamingContextStates.All), 
    surrogate);

var binaryFormatter = new BinaryFormatter
{
    SurrogateSelector = surrogateSelector
};

// 序列化恶意对象
byte[] payload = Serialize(binaryFormatter, new object());

// 反序列化触发漏洞
BinaryFormatter formatter = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream(payload))
{
    formatter.Deserialize(ms); // 触发RCE
}

4.2.2 WindowsIdentity 攻击

利用 WindowsIdentity 解析 Base64 编码数据的特性,构造恶意数据触发代码执行:

// 构造恶意WindowsIdentity数据
byte[] payload = GenerateMaliciousWindowsIdentityData();

// 反序列化触发漏洞
BinaryFormatter formatter = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream(payload))
{
    formatter.Deserialize(ms); // 触发RCE
}

五、漏洞代码审计要点

5.1 危险方法识别

审计时应重点关注以下 BinaryFormatter 方法的使用:

5.1.1 UnsafeDeserialize

// 不安全的代码示例
public object DeserializeData(string path)
{
    using (FileStream fs = new FileStream(path, FileMode.Open))
    {
        BinaryFormatter formatter = new BinaryFormatter();
        return formatter.UnsafeDeserialize(fs, null); // 危险!
    }
}

5.1.2 UnsafeDeserializeMethodResponse

// 不安全的代码示例
public object DeserializeResponse(Stream stream)
{
    BinaryFormatter formatter = new BinaryFormatter();
    return formatter.UnsafeDeserializeMethodResponse(stream, null, null); // 危险!
}

5.1.3 Deserialize

// 不安全的代码示例
public object DeserializeData(byte[] data)
{
    using (MemoryStream ms = new MemoryStream(data))
    {
        BinaryFormatter formatter = new BinaryFormatter();
        return formatter.Deserialize(ms); // 危险!
    }
}

5.1.4 DeserializeMethodResponse

// 不安全的代码示例
public object DeserializeResponse(Stream stream)
{
    BinaryFormatter formatter = new BinaryFormatter();
    return formatter.DeserializeMethodResponse(stream, null, null); // 危险!
}

5.2 安全建议

  1. 避免反序列化不受信任的数据:永远不要反序列化来自不可信源的二进制数据
  2. 使用安全替代方案:考虑使用 JSON 或 XML 序列化器,如 System.Text.JsonXmlSerializer
  3. 实现类型检查:如果必须使用 BinaryFormatter,实现 SerializationBinder 限制可反序列化的类型
  4. 签名验证:对序列化数据进行数字签名,确保数据完整性
  5. 更新 .NET 版本:较新版本的 .NET 已对 BinaryFormatter 进行了安全限制

六、防御措施

6.1 使用 SerializationBinder 限制类型

public class SafeBinder : SerializationBinder
{
    public override Type BindToType(string assemblyName, string typeName)
    {
        // 只允许反序列化已知安全的类型
        if (typeName == typeof(TestClass).FullName)
        {
            return typeof(TestClass);
        }
        throw new SerializationException("Unexpected type: " + typeName);
    }
}

// 使用方式
BinaryFormatter formatter = new BinaryFormatter
{
    Binder = new SafeBinder()
};

6.2 完全禁用 BinaryFormatter

在最新 .NET 版本中,可以通过配置完全禁用 BinaryFormatter:

<configuration>
  <runtime>
    <enableUnsafeBinaryFormatterSerialization enabled="false"/>
  </runtime>
</configuration>

七、总结

BinaryFormatter 虽然提供了高效的序列化能力,但其反序列化过程存在严重安全风险。开发人员应当:

  1. 充分了解 BinaryFormatter 的安全风险
  2. 避免反序列化不可信数据
  3. 使用更安全的替代方案
  4. 如果必须使用,实施严格的安全控制措施
  5. 保持 .NET 运行时的最新更新

安全开发实践是防止此类漏洞的关键,在设计和实现阶段就应考虑数据序列化的安全性问题。

.NET BinaryFormatter 反序列化漏洞深度解析 一、BinaryFormatter 概述 BinaryFormatter 是 .NET 框架中的一个类,位于 System.Runtime.Serialization.Formatters.Binary 命名空间,用于将对象序列化为二进制格式或从二进制格式反序列化对象。 主要特点: 使用二进制格式进行序列化 序列化速度快 跨 .NET 版本兼容性好 支持泛型等数据类型 二、BinaryFormatter 序列化机制 2.1 基本序列化方法 要使类可序列化,需要使用 [Serializable] 特性标记。如果某些成员不需要序列化,可以使用 [NoSerialized] 特性。 2.2 序列化过程 序列化后的二进制数据格式包含类型信息和对象状态数据。 三、BinaryFormatter 反序列化机制 3.1 反序列化方法 BinaryFormatter 提供了四个主要的反序列化方法: Deserialize(Stream) DeserializeMethodResponse(Stream, HeaderHandler, IFormatterConverter) UnsafeDeserialize(Stream, HeaderHandler) UnsafeDeserializeMethodResponse(Stream, HeaderHandler, IFormatterConverter) 3.2 基本反序列化示例 四、BinaryFormatter 反序列化漏洞 4.1 漏洞原理 BinaryFormatter 反序列化时会完全重建对象图,包括执行对象的构造函数、属性设置器等。攻击者可以构造恶意序列化数据,在反序列化过程中执行任意代码。 4.2 主要攻击向量 4.2.1 ActivitySurrogateSelector 攻击 通过重写 ISerializationSurrogate 接口,可以在反序列化过程中执行自定义代码: 4.2.2 WindowsIdentity 攻击 利用 WindowsIdentity 解析 Base64 编码数据的特性,构造恶意数据触发代码执行: 五、漏洞代码审计要点 5.1 危险方法识别 审计时应重点关注以下 BinaryFormatter 方法的使用: 5.1.1 UnsafeDeserialize 5.1.2 UnsafeDeserializeMethodResponse 5.1.3 Deserialize 5.1.4 DeserializeMethodResponse 5.2 安全建议 避免反序列化不受信任的数据 :永远不要反序列化来自不可信源的二进制数据 使用安全替代方案 :考虑使用 JSON 或 XML 序列化器,如 System.Text.Json 或 XmlSerializer 实现类型检查 :如果必须使用 BinaryFormatter,实现 SerializationBinder 限制可反序列化的类型 签名验证 :对序列化数据进行数字签名,确保数据完整性 更新 .NET 版本 :较新版本的 .NET 已对 BinaryFormatter 进行了安全限制 六、防御措施 6.1 使用 SerializationBinder 限制类型 6.2 完全禁用 BinaryFormatter 在最新 .NET 版本中,可以通过配置完全禁用 BinaryFormatter: 七、总结 BinaryFormatter 虽然提供了高效的序列化能力,但其反序列化过程存在严重安全风险。开发人员应当: 充分了解 BinaryFormatter 的安全风险 避免反序列化不可信数据 使用更安全的替代方案 如果必须使用,实施严格的安全控制措施 保持 .NET 运行时的最新更新 安全开发实践是防止此类漏洞的关键,在设计和实现阶段就应考虑数据序列化的安全性问题。