Exploiting __VIEWSTATE Knowing the Secret
If you don’t know the keys yet, start with the sister page about recovering / guessing them. This page is for the case where you already have the validationKey (and sometimes the decryptionKey) and want to forge a valid malicious __VIEWSTATE.[1]
When is the secret enough?
In practice, “knowing the secret” usually means you obtained the values from a leaked web.config, machine.config, registry/host access, another node in the same web farm, or from a publicly disclosed / hardcoded machineKey.
The minimum material you need depends on the framework mode:
- .NET < 4.5:
- If encryption is not enforced, the
validationKeyand validation algorithm are enough. - Even if
ViewStateEncryptionMode="Always"is configured, older versions still accept an unencrypted ViewState if__VIEWSTATEENCRYPTEDis removed from the request.
- If encryption is not enforced, the
- .NET >= 4.5 /
compatibilityMode="Framework45":- You usually need both the
validationKeyand thedecryptionKey, plus their algorithms. - The payload also depends on the target page path and application path.
- You usually need both the
Quick triage checklist
Before generating the payload, collect:
__VIEWSTATE__VIEWSTATEGENERATORif present- Target page path (for example
/dir/app/page.aspx) - IIS application path / virtual root (for example
/app/) - Validation algorithm +
validationKey - Decryption algorithm +
decryptionKeyif the target uses modern ViewState protection ViewStateUserKeyif the application salts ViewState per user / session
If you only know the keys but not the exact gadget to use, check the nearby .NET gadget page.
Forging the payload with ysoserial.net
Legacy targets (.NET 4.0 and below)
When the target uses the legacy signing logic, ysoserial.net can use either:
--generator=<__VIEWSTATEGENERATOR>if the page exposes that value, or--path+--apppathif you know the IIS application root.
Example using the exposed generator value:
ysoserial.exe -p ViewState -g TypeConfuseDelegate \
-c "cmd /c whoami" \
--generator=CA0B0334 \
--islegacy \
--validationalg="SHA1" \
--validationkey="<VALIDATION_KEY>"
If the page is configured with ViewStateEncryptionMode="Always" but runs on .NET < 4.5, remove __VIEWSTATEENCRYPTED from the request and send an unencrypted but correctly signed payload.
If you need the request to still look encrypted on a legacy target, recent ysoserial.net builds also expose --isencrypted, which wraps the legacy payload instead of relying only on the __VIEWSTATEENCRYPTED removal trick.
Modern targets (.NET 4.5 and above)
Modern ViewState derivation uses the target page path and application path when deriving the protection material, so you normally need both:[1]
ysoserial.exe -p ViewState -g TextFormattingRunProperties \
-c "cmd /c whoami" \
--path="/content/default.aspx" \
--apppath="/" \
--validationalg="HMACSHA256" \
--validationkey="<VALIDATION_KEY>" \
--decryptionalg="AES" \
--decryptionkey="<DECRYPTION_KEY>"
If the payload fails and you suspect the path or app path is wrong, retry with --isdebug. The plugin prints the derived values and helps validate whether your guess matches the target’s __VIEWSTATEGENERATOR / path logic.
Recent ysoserial.net builds also expose --minify, which is handy when you need to keep the forged payload short enough for WAF, proxy, or URL-length constraints.
Common gotchas
__VIEWSTATEGENERATOR is helpful, but mostly for legacy targets
ysoserial.net’s ViewState plugin explicitly treats --generator as a legacy shortcut. For .NET 4.5+ you should expect to need the real --path and --apppath values.
ViewStateUserKey will break otherwise valid payloads
If the application binds ViewState to a user, session, or anti-CSRF token, you must include the same value when generating the payload:
ysoserial.exe -p ViewState -g TextFormattingRunProperties \
-c "cmd /c whoami" \
--path="/content/default.aspx" \
--apppath="/" \
--validationalg="HMACSHA256" \
--validationkey="<VALIDATION_KEY>" \
--decryptionalg="AES" \
--decryptionkey="<DECRYPTION_KEY>" \
--viewstateuserkey="<KNOWN_OR_GUESSED_VSUK>"
Recovering ViewStateUserKey in practice
Once the keys are known, ViewStateUserKey is the most common reason for a forged payload to fail. In real applications, it is often derived from:
Session.SessionID__AntiXsrfToken/ anti-CSRF cookies- A value stored in
web.config,appSettings,Global.asax, or a sharedBasePage
If you already have filesystem access or an ASPX execution primitive, grep for it directly:
rg -n "ViewStateUserKey|AntiXsrf|__AntiXsrfToken|Session\.SessionID" .
If you only have HTTP access, inspect the response cookies before guessing blindly. Current badsecrets / crapsecrets logic already tries common candidates such as ASP.NET_SessionId, __AntiXsrfToken, and small built-in wordlists, so they are also useful for validating whether the missing piece is really the per-user salt.
GET requests can also work
Although POST is the common delivery path, some applications also parse __VIEWSTATE from a GET request. This is useful when trying to stay close to the application’s normal traffic or when replaying a payload through a URL-based gadget delivery point.
Start with the highest-value endpoints
Once you know the keys, test the pages that are both reachable pre-auth and guaranteed to post back before spending time on random forms. Recent real-world examples include:
- SharePoint
/_layouts/15/ToolPane.aspx(see the SharePoint page) - Sitecore
/sitecore/blocked.aspx, which was abused in 2025 when older deployments reused a published samplemachineKey[3]
In practice, license, error, login, and admin helper pages are often better initial sinks than the main application workflow because they expose a stable hidden __VIEWSTATE field without requiring a full authenticated UI path.
__EVENTVALIDATION can be abused with the same secrets
The same signing material can also become useful against __EVENTVALIDATION, but exploitation is more constrained than normal ViewState abuse: you need a POST request, a page that actually processes input, and a valid control/input name.
On .NET 4.5+, the secret is reused with a different cryptographic purpose string: __VIEWSTATE uses WebForms.HiddenFieldPageStatePersister.ClientState, while __EVENTVALIDATION uses WebForms.ClientScriptManager.EventValidation. So if a forged ViewState works but a forged event payload does not, double-check the page/app path, the specific purpose, and whether the target control is actually allowed to raise that event.[1]
Why this still matters in 2025-2026
This workflow is still very relevant because attackers increasingly do not need an additional bug once the keys are known:
- Microsoft reported in February 2025 that threat actors were abusing publicly disclosed ASP.NET machine keys to generate valid malicious ViewState blobs.[2]
- Mandiant documented in September 2025 that Sitecore deployments reusing an old sample
machineKeycould be hit pre-auth through/sitecore/blocked.aspx, turning a documentation mistake into direct ViewState RCE.[3] - SANS observed in August 2025 that post-exploitation SharePoint activity frequently included dumping machine keys first, because one recovered key pair can be replayed laterally against sibling IIS applications.[4]
- In shared IIS / SharePoint farms, one recovered key pair can often be replayed laterally against sibling applications that trust the same configuration.
So, once you recover a single valid key pair, immediately test:
- Other virtual directories on the same host
- Sibling nodes behind the load balancer
- Admin-only pages that expose richer gadget surfaces
- Alternate state parameters such as
__EVENTVALIDATION