ASP.Net: Tampering with Event Validation – Part 1
Filed under: Development, Security
UPDATED 12/13/2012 – This post was updated to include a video demonstration of tampering with data with Event Validation enabled. The video is embedded at the bottom of the post.
My last post brought up the topic of tampering with Event Validation (__EVENTVALIDATION) and how it is protected with the ViewStateMAC property. This post, and the next few, will focus on how to actually tamper with the values in Event Validation to test for security vulnerabilities. We will use a very basic demo application to demonstrate this.
Target Application
The target application has a simple screen with a drop down list, a button, and a data grid that displays the selected account information. The drop down list is populated with accounts for the logged on user only. I will show how the data can be modified to view another account that we were not granted access to. It is important to note that there are many variables to requests and this assumes that authorization was only checked to fill the drop down list and not when an actual account is selected. This is a pretty common practice because it is assumed that event validation will only allow the authorized drop down items (the accounts in this instance) to be selected by the user. Not all applications are written in this way, and the goal is to test to see if there is authorization or parameter tampering issues.
Tools
I will use multiple tools to perform this test. These tools are personal choice and other tools could be used. The first, and my favorite, is Burp Suite Pro. This will be my main proxy, but that is just because I like how it works better than some others. Secondly, I will be using Fiddler and the ViewState Viewer plug-in to manipulate the View State field. Finally, I have a custom application that I wrote to generate the Event Validation codes that I need to make this work.
The Process
First, I will just load the application and view the target page. Image 1 shows the initial screen with the values from the drop down list. Notice that only 3 accounts are available and they are all for James. By looking at the source for the drop down list, I can see that the values for each of those items are numeric. This is a good sign, for testing purposes. Numeric values are usually easier at determining, especially if you can find a simple pattern.
Image 1
Next, it is time to de-serialize the view state so we can modify it for the value we want to add. To do this, I will use Fiddler and the ViewState Viewer plug-in. There are two changes I need to make. First, I need to add an item to the ArrayList (seen in Image 2).
Image 2
Second, I need to add the drop down list item I want to try and access. The text will not matter, but the value that I add is the key. Although this may not always be the case, in this simple example, that is what the application uses to query the account data. The value needed could be known, or you could just attempt to try different values until you find one that works. The added item can be seen here in Image 3.
Image 3
Now that my view state has modified, I can press the “Encode” button and get the updated view state. Here is the original and modified view state values:
Original __VIEWSTATE
/wEPDwUKMTE3ODU2MDQzNg9kFgJmD2QWAgIDD2QWAgIFD2QWBAIBDxBkDxYDZg
IBAgIWAxAFDkphbWVzIENoZWNraW5nBQUwMDEwMWcQBQ1KYW1lcyBTYXZpbmdz
BQUwMDEwMGcQBQlKYW1lcyBJUkEFBTAwMTAyZ2RkAgcPPCsACwBkZA==
Modified __VIEWSTATE
/wEPDwUKMTE3ODU2MDQzNg9kFgJmD2QWAgIDD2QWAgIFD2QWBAIBDxBkDxYEZg
IBAgICAxYEEAUOSmFtZXMgQ2hlY2tpbmcFBTAwMTAxZxAFDUphbWVzIFNhdmluZ3M
FBTAwMTAwZxAFCUphbWVzIElSQQUFMDAxMDJnEAUOSGFja2VkIEFjY291bnQFBTA
wMjAxZ2RkAgcPPCsACwBkZA==
The next step is to modify the Event Validation value. There are two options to modify this value:
- Use Fiddler and the ViewState Viewer (just like how we just modified the view state)
- Use my custom application. This is the method I will use for this example. See Image 4 for a reference to the application.
I will retrieve the __EVENTVALIDATION value from the response and paste it into the Original Event Validation textbox and “De-Serialize” it. This will populate the list box with all of the original hash values. To add custom data, we must use the same technique that the ASP.Net uses to calculate the hash value for the items. There are two values we need to modify in this example.
- First, I need to modify our allowed viewstate hash. To do this, I will put my modified __VIEWSTATE value into the “Value” textbox and click the “Get Hash” button. View State is a little different than other control data in that it does not require a Unique Id to be associated with it to generate the hash. The hash value generated is 679154845. This value must be placed in the first array item in event validation.
- Second, I need to add my own drop down item. Previously, I added this to the view state and used a value of 00201. Adding it to event validation is a little different. I will enter in the value (00201) into the “Value” box, and then enter the drop down lists unique id (ctl00$MainContent$ddlAccounts) into the “Unique Id:” textbox. Clicking the “Get hash” button produces the following hash: 439972587. I then add this hash value to the array.
Now that my two hashes have been added, it is time to serialize the data back into the __EVENTVALIDATION value. Here are the two different values we worked with:
Original __EVENTVALIDATION
/wEWBQKc7/W6AwK6gbzTBAK7gbzTBAK9gbzTBAKP5u6DCA==
Modified __EVENTVALIDATION
/wEWBwKdqezDAgK6gbzTBAK7gbzTBAK9gbzTBAKP5u6DCAKh96L5CQKVmpquDg==
Image 4
Due to the time it can take to perform the above steps, I like to do them without holding up my request. Now that I have the values I need, I will refresh my page with my proxy set to intercept the response. I will then modify the response and change the __VIEWSTATE and __EVENTVALIDATION values to my new modified ones. I will let the response continue to allow my page to display.
At this point, nothing appears to have happened. There is no additional drop down list item or anything else to indicate that this has worked. The key is to now just select an existing account and hit the “Get Account” button. If there is an error, something didn’t work right. If you were successful, the page should re-load and you should see a new Drop down List item (See Image 5)
Image 5
I now need to determine if I was lucky enough to pick a valid account number. I will select the “Hacked Account” list item (which is the one I added) and click the “Get Account” button. If no data comes back then the account number did not exist. It is back to the drawing board to try again with a different number. If, however, account details did show up, then I have successfully accessed data I was not given access to. Image 6 shows the results of a successful attempt.
Image 6
Conclusion
This showed the steps necessary to manipulate both view state and event validation to tamper with the allowed accounts were were authorized to see. This requires that ViewStateMAC is disabled and that the view state has not been encrypted. If either of those two factors were different, this would not be possible. This demonstrates the importance of ensuring that you use ViewStateMAC to protect your view state AND event validation. You should also be performing authorization checks on each request that requests sensitive information from your application. This example application is completely fictional and there are no claims that this represents the way that any production application actually works. It will be used to demonstrate the different techniques used to develop applications to understand how they can be fixed.
This information is provided as-is and is for educational purposes only. There is no claim to the accuracy of this data. Use this information at your own risk. Jardine Software is not responsible for how this data is used by other parties.
ViewStateMAC: Seriously, Enable It!
Filed under: Development, Security
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.
ASP.Net Insecure Redirect
Filed under: Development, Security
It was recently discovered that there was a vulnerability within the ASP.Net Forms Authentication process that could allow an attacker to force a user to visit a malicious web site upon success authentication. Until this vulnerability was found, it was thought that the only way to allow the Forms Authentication redirect (managed by the ReturnUrl parameter) to redirect outside of the host application’s domain was to set enableCrossAppRedirects to true in the web.config file. If this property was set to false, the default value, then redirection could only occur within the current site.
So how does it work? When a user navigates to a page that requires authentication, and they are not currently authenticated, ASP.Net redirects them to the login page. This redirection appends a querystring value onto the url that, once successful login occurs, will allow the user to be redirected to the originally requested page. Here is an example (Assuming that EnableCrossAppRedirects=”False” ):
- User requests the following page: http://www.jardinesoftware.com/useredit.aspx
- The framework recognizes that the user is not authenticated and redirects the user to http://www.jardinesoftware.com/logon.aspx?ReturnUrl=useredit.aspx
- The user enters their login information and successfully authenticates.
- The application then analyzes the ReturnUrl and attempts to determine if the Url references a location with the current domain, or if it is outside of the domain. To do this, it uses the Uri object to determine if the Url is an Absolute path or not.
- If it is determined to NOT be an absolute path, by using the Uri object, then the redirect is accepted.
- If it is determined to be an absolute path, additional checks are made to determine if the hosts match for both the current site and the redirect site. If they do, a redirect is allowed. Otherwise, the user is redirected to the default page.
The details are not fully known at this time as to what the malicious link may look like to trick ASP.Net into believing that the Url is part of the same domain, so unfortunately I don’t have an example of that. If I get one, I will be sure to post it. It does appear that some WAF’s are starting to include some signatures to try and detect this, but that should be part of defense in depth, not the sole solution. Apply the patch. The bulletin for MS11-100 describes the patch that is available to remediate this vulnerability.
It is important to note that this is an issue in the FormsAuthentication.RedirectFromLogin method and not the Response.Redirect method. If you are doing the latter, through a custom login function, you would be required to validate the ReturnUrl. If you use the default implementation to redirect a user after credentials have been verified or use the built in asp:Login controls, you will want to make sure this patch gets applied.
This issue requires that a legitimate user clicks on a link that already has a malicious return url included and then successfully logs in to the site. This could be done through some sort of phishing scheme or by posting the link somewhere where someone would click on it. It is always recommended that when users go to a site that requires authentication that they type in the address to the site, rather than follow a link someone sent them.
This issue doesn’t have any impact on the site that requires authentication, it is strictly a way for attackers to get users to visit a malicious site of their own.
For more information you can read Microsoft’s Security Bulletin here: http://technet.microsoft.com/en-us/security/bulletin/ms11-100.
The information provided in this post is provided as-is and is for educational purposes only. It is imperative that developers understand the vulnerabilities that exist within the frameworks/platforms that they work with. Although there is not much you can really do when the vulnerability is found within the framework, understanding the possible workarounds and the risks associate with them help determine proper remediation efforts.
ASP.Net 4: Change the Default Encoder
Filed under: Development, Security
In ASP.Net 4.0, Microsoft added the ability to override the default encoder. This is specifically focused on the HTMLEncode, HTMLAttributeEncode, and URLEncode functionality. These functions are used, in the eyes of security, to help mitigate cross-site scripting (XSS). The problem with the built in .Net routines is that they are built on a black-list methodology, rather than a white-list methodology. The built in routines use a very small list of characters that get encoded. For example, the .Net version of HTMLEncode encodes the following characters: <,>,â€,&. The Microsoft Web Protection Library (previously known as the Anti-XSS Library) instead determines all characters that don’t need encoding, a-z0-9 for example, and then encodes all the rest. This is a much safer approach to encoding.
In this post, I will show you how to use the Web Protection Library as the default encoder for an ASP.Net 4.0 application. The first step is to download the Web Protection Library. In this example, I use version 4.0 which can be found at: http://wpl.codeplex.com/.
Next, you will need to have an application to implement this. You can use an existing application, or create a new one. Add a reference to the AntiXSSLibrary.dll found in†Program Files\Microsoft Information Security\AntiXSS Library v4.0â€.
To use the library, it is time to create a new class. You can see the code in my class in Figure 1. I named the class “MyEncoder†and this is just a sample. (THIS IS NOT PRODUCTION CODE) There are two important factors to this class:
1. The class must inherit from System.Web.Util.HttpEncoder.
2. You must override each Encode Method you want to change.
If you only wanted to update the HTMLEncode and leave the other methods alone, just leave them out of the class.
Figure 1
using System;
using System.Web;
public class MyEncoder : System.Web.Util.HttpEncoder{public MyEncoder(){}
protected override void HtmlEncode(string value, System.IO.TextWriter output){if (null == value)return;
output.Write(Microsoft.Security.Application.Encoder.HtmlEncode(value));
}protected override void HtmlAttributeEncode(string value, System.IO.TextWriter output){if (null == value)return;
output.Write(Microsoft.Security.Application.Encoder.HtmlAttributeEncode(value));
}}The final step to implementing this custom encoding is to update the web.config file. To do this, modify your httpRuntime element to have the “encoderType†attribute set, as seen in Figure 2. Change “MyEncoder†to the name of the class you created. If you do not have the httpRuntime element, just add it in.
Figure 2
<system.web><compilation debug="true" targetFramework="4.0"/><httpRuntime encoderType="MyEncoder"/>
.....Although it would be really nice if the .Net Framework would just start using the Web Protection Library, they are just not ready for that yet. It is important that plenty of testing is always done when working with output encoding. Different encoders produce different outputs and may cause display defects. It is also important to note that this only effects items that get auto-encoded by the framework. For example, a text property of a textbox.
This is just a small example of modifying the default encoding type of your application. There is much more that you could potentially do with this. This is just a sample and this code is NOT FOR PRODUCTION USE.