Attacking Insecure Deserialization in .NET — Part 1: Fundamentals, Lab Setup, and $type Metadata Abuse
Introduction
This article introduces Insecure Deserialization attacks in .NET and explains how attackers abuse gadget chains to achieve remote code execution.
In this article, we will explore:
- The fundamentals of .NET deserialization
- Gadget chains Concept, and Serializers
- Build a vulnerable ASP.NET lab for testing
- Type metadata abuse via TypeNameHandling.All
Insecure Deserialization in .NET — Definition, Key Concepts, Tools, and Exploitation Flow
Definition
This vulnerability occurs when an application deserializes untrusted data without proper validation. this can happen when the target application uses vulnerable libraries, framework classes, or built-in platform classes that can be abused during deserialization.
During deserialization, the application reconstructs objects from serialized data. In some cases, special methods (such as constructors or deserialization callbacks like OnDeserialized) may be automatically executed.
If an attacker can control the serialized data, they may craft a malicious object that triggers unintended code execution during the deserialization process.
A vulnerable class that can be abused during deserialization is called a gadget.
When multiple gadgets are chained together so their method calls lead to arbitrary code execution, the sequence is known as a gadget chain.
Key Concepts
- Gadget
- Gadget Chain and Sink
- Serializers / Formatters
Gadget:
Gadget is a legitimate method/property/constructor that lives within a class and can be abused during deserialization to execute unintended behavior. They usually come from Third-party libraries, Framework classes, or Built-in platform classes.
PS. Not every method/class is a gadget.
A method/class becomes a gadget if:
- It does something dangerous
- AND it can be triggered automatically during deserialization
Gadget Chain:
One gadget may not give RCE directly. So attackers chain multiple gadgets to reach RCE or something.
You can think of it as dominos game:
- Deserialization pushing the first domino
- Gadget A calls gadget B
- Gadget B calls gadget C
- Final gadget (Sink gadget) execute something dangerous in the server
Tools like ysoserial.net generate such as these chains automatically.

So, as a summary:
- Gadget → Exploitable class/method
- Gadget Chain → Multiple gadgets chained to reach sink
- Sink → The final gadget in the chain, when triggered leads to RCE
Serializer / Deserializer:
A serializer converts an object → data.
A deserializer converts data → object.
So, Basically the concept is:
1 | |

Formatters:
In old .NET architecture, a formatter is a type of serializer/deserializer designed to convert objects to a specific format.
Example formatters:
- BinaryFormatter: used to convert object to binary format and back (serialization/deserialization)
- SoapFormatter: serialize objects into SOAP-based XML format
- LosFormatter: used in ASP.NET to serialize/deserialize ViewState data
- ObjectStateFormatter: used by ASP.NET for more efficient Viewstate serialization (replaces LosFormatter internally in many cases)
We gonna go deep on formatters, ViewState objects, etc in Part 2
So the relationship simply is like that:
1 | |
Tools — ysoserial.net
A tool used to generate malicious serialized payloads for testing .NET deserialization vulnerabilities.
- Contains a collection of known gadget chains such as
TypeConfuseDelegate,ActivitySurrogateSelector,ObjectDataProvider,WindowsClaimsIdentityetc. these well-known gadget chains also called as ysoserial common gadgets. - It generates serialized objects that embeds a command within the payload to trigger code execution during the deserialized process.
- Used for security testing and research of insecure deserialization.
Official GitHub repository: https://github.com/pwntester/ysoserial.net
Exploitation (Attack flow)
What happen internally?
During deserialization process:
- The application reconstructs objects from user input
- Some objects execute code automatically during construction or property initialization
- If the attacker controls the object data, this behavior can be abused
If the attacker controls both the object type and its data, a gadget chain may execute dangerous functionality.

If an attacker can control the input, they can change the $type to an unexpected class, and it might trigger malicious behavior (like code execution).
In old .NET Framework, gadgets such as ObjectDataProvider, TypeConfuseDelegate, WindowsIdentity were commonly abused.
Note that in modern environments and .NET versions (above 4.0):
- Exploitation is generally more difficult
- Many insecure serializers are deprecated or restricted
- Successful attacks often require vulnerable third-party libraries
- Or custom application code performing unsafe deserialization
Exploitation Conditions & Prerequisites
Exploit prerequisites:
- A vulnerable deserialization endpoint
- The right gadget chain matching the target’s libraries
Environment Setup: Preparing our ASP.NET Lab to Test Deserialization Attacks on .NET
We’re going to setup our ASP.NET webserver which is a web framework developed by Microsoft used to build Web applications, APIs, Enterprise systems, and Internal company portals.
Installing .NET SDK on linux
First, updating our system with sudo apt update and sudo apt upgrade.
Installing the SDK:
1 | |
Verifying the installation:
1 | |
Create a Test ASP.NET Web App
Creating project folder:
1 | |
Creating a new web app:
1 | |
This generates an ASP.NET Core Razor application.
Run the .NET webserver locally:
1 | |
We should see something like:
1 | |
Open browser http://localhost:5000 or testing locally from Burpsuite, we can run the server like that:
1 | |
Then intercepting traffic using burpsuite.
If burpsuite fails to intercept the localhost domain requests, you can edit /etc/hosts and use a custom domain namea instead of localhost or 127.0.0.1.
Since our server is ready now, We can start creating simple vulnerable endpoints in our ASP.NET server and test various formatters such as:
- Newtonsoft.Json
- BinaryFormatter
- LosFormatter
- DataContractSerializer
- ObjectStateFormatter
However, It’s important to note that many of these formatters, including BinaryFormatter, LosFormatter, DataContractSerializer, and ObjectStateFormatter, are no longer supported in modern .NET runtimes, particularly versions above 4.0 Even if these formatters work, you will encounter compatibility issues.
In our case (.NET 6.0), only Newtonsoft.Json is still supported and we can test it with TypeNameHandlingAll.
The remaining formatters are no longer supported by modern SDKs. Because these formatters requires .NET versions <= 4.0.
Create minimal ASP.NET web app
Create template for a minimal ASP.NET web application (no Razor pages, just a simple HTTP server):
1 | |
Project Structure - Overview
1 | |
We have Program.cs which is the application main file:
1 | |
So, that’s endpoint basically will:
- Creates an endpoint /
- Returns “Hello World!” when a client access the endpoint with GET request
Running the application: dotnet run --urls=http://0.0.0.0:5000 and then curl:
1 | |
As you can see, all good now.
Now we can create endpoints like /deserialize, /api/test, etc. for testing our .NET deserialization attacks and web vulnerabilities.
We are going to create samples of small vulnerable .NET endpoints in Program.cs file to test insecure deserialization.
Newtonsoft.Json TypeNameHandling exploit
I created an endpoint in the Program.cs file as you see here:
1 | |
So, we have /deserialize endpoint which read the raw request body and deserialize it using JsonConvert.DeserializeObject.
The important part here is TypeNameHandling is set to All. This allows the JSON payload to specify the .NET type through the $type field, which can lead to insecure deserialization if untrusted input is processed.
To test this behavior, I’ll send a POST request to the endpoint using the following curl command:
1 | |
and this the output of what curl gave me:
1 | |
The error message above tell us exactly what happened during the deserialization process of the provided JSON payload. And based on the revealed errors, we understand that the application resolved the $type specified in the JSON payload but failed because the type Dangerous not found.
Also, the stack trace clearly shows that the error comes from the Newtonsoft.Json library during the deserialization process. This confirms that the request body was processed, and the $type field was read by the application.
What happens internally during deserialization ?
When the server receives something like "$type": "VulnDeserApp.Dangerous, VulnDeserApp", the runtime performs a call internaly like this:
1 | |
In another hand:
1 | |
This resolves the specified type from the assembly. Once the type is resolved, the runtime can dynamically instantiate it using something like:
1 | |
In other words, the value of the $type field directly influences which .NET class is loaded and instantiated at runtime.
Step 1 — Creating a Dangerous User Class
To demonstrate how insecure deserialization can lead to command execution, we create a simple class called User in a new file User.cs. This class contains a property that executes system commands when its value is set.
1 | |
The code above does 2 important things:
Constructor Execution
Whenever the object is instantiated, the constructor runs automatically. That confirms that the object created during deserialization.Dangerous Property Setter
When theCommandproperty is set:- The value from the JSON input is stored in
cmd - The program launches
bash - And then the command is executed using
bash -c
- The value from the JSON input is stored in
Step 2 — The Vulnerable API Endpoint
In our Program.cs file, We already have /deserialize endpoint that reads JSON from the request body and deserializes it. I’m going to call
This endpoint performs three main actions:
- Reads the JSON request body.
- Uses Newtonsoft.Json to deserialize it.
- Having
TypeNameHandling.Allenabled.
Step 3 — Crafting a Malicious Payload
After crafting the malicious payload, we send it to our vulnerable endpoint.
This is how our payload looks like:
1 | |
$type: Specifies the .NET class (User) and assembly (VulnDeserApp) that Newtonsoft.Json should instantiate during deserialization.CommandProperty: Supplies the attacker‑controlled system command (whoami;id) that gets executed when the Command property setter runs.
Example request using curl:
1 | |
This screenshoot shows the result we got after sending our payload to dotnet server:

When the payload is processed, the server logs show the following output:
1 | |
This confirms:
- The User constructor was executed during deserialization.
- The Command property setter executed attacker-controlled input.
- The command
whoami;idran successfully on the system.
This means we achieved remote command execution on the host due Insecure Deserialization.
Quick insight:
- By default, Newtonsoft.Json is generally safe because it does not trust type metadata embedded in JSON payloads.
However, the library becomes dangerous when developers enable certain features. - So, the JSON.NET may load specified .NET type, initiate the object, execute property setters and callbacks, and then trigger a gadget chain.
How attackers discover the correct $type
In real pentest attackers find the correct type by:
① Information Disclosure via Error Messages
Is like our previous example, Stack traces often reveals:
- Namespaces names example:
Namespace.ClassName - Assembly names example:
AssemblyName.dll - File system paths example:
/home/app/bin/
These details help attackers constructs valid $type values.
② Accessible Application Files / DLL downloads
Attackers may attempt to access directories such as /bin/,/api/, or /swagger, And if .dll files are exposed, attackers may try to analyze them to identify:
- Available classes
- Namespaces
- Assembly names
These components are required to construct valid $type payloads.
③ Public Gadget Classes From .NET Framework
In many cases, attackers don’t even need application assemblies at all. Instead, they use built-in classes from .NET Framework that are already available on the server.
Some commonly available assemblies include:
System.DataPresentationFramework
These assemblies contain classes that may act as deserialization gadgets, which can lead to command execution during deserialization process.
A well-known gadget in .NET deserialization is the ObjectDataProvider class from the PresentationFramework assembly.
1 | |
This ObjectDataProvider can be abused to invoke arbitary methods during deserialization, which may lead to command execution.
This is how gadget chains work.
④ Automated Gadget Discovery Tools
Security researchers often rely on tools such as ysoserial.net to generate deserialization payloads using known gadget chains.
Some Useful Resources
Hack The Box Machines Related to Deserialization Attacks
The following Hack The Box machines contains vulnerabilities and techniques related to .NET and Java deserialization attacks, gadget chains, or cryptographic key exploitation (e.g., ViewState / MachineKey abuse).
| Machine | Technology | Topic |
|---|---|---|
| Json | Java | Java deserialization |
| Atlas | ASP.NET | ViewState / MachineKey exploitation |
| Sharp | .NET | .NET application exploitation |
| Visual | ASP.NET | ViewState / MachineKey abuse |
| Scrambled | Java | Java deserialization |
| Monitors | Java | Java Deserialization, more .. |
| Tenet | PHP | Wordpress, PHP Deserialization, Race Condition Vulnerability, Inotify |
| Cereal | .NET | .NET code analysis, Deserialzation, XSS, JWT, GraphQL, SSRF |
| Feline | Java | Java Deserialization, Tomcat, CVE(SaltStack), Docker Engine API |
| Travel | PHP | Wordpress, SSRF, PHP Deserialization, Memcached, LDAP |
| Player | PHP | JWT, FFmpeg Vulnerability, CVE (SSH), PHP Deserialization Vulnerability |
Vedios Sessions
- Attacking .NET deserialization - Alvaro Muñoz
- BlueHat v17 || Dangerous Contents - Securing .Net Deserialization