ViewStateMAC: Seriously, Enable It!
I have been doing a lot of research lately around event validation and view state. I have always been interested in how Event Validation worked under the covers and if it could be tampered with. I will attempt to explain that it is, in fact, possible to tamper with the Event Validation field in a similar manner that view state can be tampered. I know, the title of the post reads “ViewStateMACâ€, don’t worry I will get to that. But first, it is important to discuss a little about how Event Validation works to understand why ViewStateMAC is important.
__EVENTVALIDATION – Basics
Event Validation is a feature that is built into ASP.Net web forms. It is enabled by default and it serves the purpose to ensure that only valid data is received for controls that register valid events or data. As a quick example, think for a moment about a drop down list. Each value that is programmatically added to the control will be registered with Event Validation. Code Example 1 demonstrates loading values into a drop down list (data binding is also very common). Each of these values will now exist in the Event Validation feature. When a user attempts to submit a form, or post back, the application will verify the value submitted for that control is a valid value. If it is not, a not so pretty exception is generated.
{
  ddlList.Items.Add(new ListItem("1", "1"));
  ddlList.Items.Add(new ListItem("2", "2"));
  ddlList.Items.Add(new ListItem("3", "3"));
  ddlList.Items.Add(new ListItem("4", "4"));
  ddlList.Items.Add(new ListItem("5", "5"));
}
__EVENTVALIDATION – Hash
Event Validation is primarily based on storing a hash value for each of the values it needs to check for validity. More specifically, there is a specific routine that is run to create an integer based hash from the control’s unique id and the specified value (the routine is beyond the scope of this post). Every value that gets stored in Event Validation has a corresponding integer hash value. These hash values are stored in an array list which gets serialized into the string that we see in the __EVENTVALIDATION hidden form field on the web page.
__EVENTVALIDATION – Page Response
When a page is requested by the user it goes through an entire lifecycle of events. To understand how Event Validation really works, lets first take a look at how the field is generated. Before the page is rendered, each control or event that is registered for event validation will have its value hashed (see previous section) and added to the array list. As mentioned before, this can be values for a list control, valid events for the page or controls (for example, button click events), and even View State. This array is serialized and stored in the __EVENTVALIDATION hidden field.
__EVENTVALIDATION – Post Back Request
The request is where Event Validation takes action. When a user submits a post back to the server, event validation will validate the values that have been registered. So in the Drop Down List example in "Example 1†Event Validation is there to make sure that only the values 1-5 are submitted for ddlList. It does this by taking the value that was sent (Request.Form[“ddlListâ€]) and re-generates the numeric hash. The hash is then compared to the list and if it exists, the value is allowed. If it doesn’t exist in the de-serialized Event Validation list, then an exception is thrown and the page cannot continue processing.
__EVENTVALIDATION – Manipulation
De-serializing the Event Validation value is pretty easy. This is very similar to how it is done for View State. After writing my own tool to tamper with the Event Validation, I found the ViewState Viewer (http://labs.neohapsis.com/2009/08/03/viewstateviewer-a-gui-tool-for-deserializingreserializing-viewstate/) plug-in for Fiddler. The ViewState Viewer plugs right into Fiddler with no issues. Don’t let the name mislead you, this tool works great with the Event Validation data as well. When you paste in your Event Validation string and click the “Decode†button, it generates a nice XML snippet of the contents. The screen shot below demonstrates the Event Validation value and its decoded value from a test page I created.
Once you have the information decoded, you can now add in your own integers to the System.Collections.ArrayList. Look closely and you might see that the last integer –439972587 is not aligned with the rest of the items. This is because that is a custom value that I added to the event validation. These numbers don’t look like they really mean anything, but to Event Validation, they mean everything. If we can determine how to create our own numbers, we can manipulate what the server will see as valid data. Once you have made your modifications, click the “Encode†button and the value in the top box will refresh with the new __EVENTVALIDATION value. It may be possible to attempt brute forcing the data you want (if you can’t create the exact hash code) by just padding a bunch of integers into the list and submitting your modified data. This is definitely hit or miss, could be time consuming, and would probably generate a lot of errors for someone to notice. We are monitoring our error logs right?
__EVENTVALIDATION – Thoughts
Maybe just me, but I always thought that if I had event validation enabled, as a developer, I didn’t have to validate the data from drop down lists that was submitted. I thought that this type of data was protected because event validation enforced these constraints. This is obviously not the case and honestly brings up a very important topic for another day; “We shouldn’t be relying solely on configuration for protectionâ€. Although this post uses the drop down lists as an example, this has a much greater effect. What about buttons that are made visible based on your role. If event validation can be tampered with, now those buttons that didn’t exist, can have their events added to the acceptable list. If you are not checking that the user has the proper role within that event, you may be in big trouble.
So what types of attacks are possible?
- Parameter tampering
- Authorization bypass
- Cross Site Scripting
- Maybe More…
ViewStateMAC – Finally!!
Ok, it is not all bad news and finally we come to our friend (or worst enemy if it is disabled) ViewStateMAC. Keep in mind that ViewStateMAC is enabled by default, so if this is disabled, it was done explicitly. ViewStateMAC adds a message authentication code to ViewState obviously, judging by its name. Basically, it adds a hash to the view state so that an attacker cannot tamper with its data. So if we go back to the drop down list, if a developer uses code like Example 2 to access the selected item, then you have to be able to tamper the view state, otherwise the first item in the original item will get selected. But if you use code like Example 3 to access that data, you could add your value to the EventValidation and get it accepted by the application. Or can you?
{
  Response.Write(ddlList.SelectedItem.Value);
}
{
  Response.Write(Request.Form["ddlList"].ToString());
}
Actually, ViewStateMAC does more than sign ViewState, it also signs the Event Validation value. I was not able to identify any documentation on MSDN that indicates this feature, but apparently __PREVIOUSPAGE may get signed with this as well. I have run extensive tests and can confirm that ViewStateMAC is critical to signing Event Validation. So in general, If ViewStateMAC is enabled, it protects both ViewState and Event Validation from being tampered with. That is pretty important and I am not sure why it is not listed on MSDN. Unfortunately, disable it and it creates a much greater security risk than initially thought because it effects more than ViewState.
ViewStateMAC – Not a Replacement for Input Validation
In no way should a developer rely solely on ViewStateMAC, Event Validation and ViewState as their means of input validation. The application should be developed as if these features do not even exist. Drop down lists should be validated that only valid values were submitted. Control events should be verified that they are allowed. Why not use these features? I am not saying that you should not use these features, but they should be in addition to your own input validation. What if ViewStateMAC were to get disabled during testing, or for some other unknown reason? Even if Event Validation is still enabled, it is not looking good. Unless you have ViewState being encrypted, which would help block tampering with the view state, an attacker could still manipulate the event validation code.
Conclusion
The details provided here have been high level with not much actual detail in actually manipulating the Event Validation field. The post would be too long to include all the details here. Hopefully there is enough information to make developer’s aware of the severity of ViewStateMAC and how Event Validation actually works. From a penetration tester’s view, if you visit a .net webform application with ViewStateMAC disabled, this should be researched more to help accurately identify risk for the application. Devs, please, please, please do not disable this feature. If you are on a web farm, make sure the same machine key is set for each machine and this should be supported. Remember, these features are helpers, but not complete solutions. You are responsible for performing proper input validation to ensure that the data you expect is what you accept.
The information provided is for informational and educational purposes only. The information is provided as-is with no claim to be error free. Use this information at your own risk.