ViewState XSS: What’s the Deal?

Posted by on September 17, 2012

Many of my posts have discussed some of the protections that ASP.Net provides by default.  For example, Event Validation, ViewStateMac, and ViewStateUserKey.  So what happens when we are not using these protections?  Each of these have a different effect on what is possible from an attacker’s stand point so it is important to understand what these features do for us.  Many of these are covered in prior posts.  I often get asked the question “What can happen if the ViewState is not properly protected?”  This can be a difficult question because it depends on how it is not protected, and also how it is used.  One thing that can possibly be exploited is Cross-site Scripting (XSS).  This post will not dive into what XSS is, as there are many other resources that do that.  Instead, I will show how an attacker could take advantage of reflective XSS by using unprotected ViewState.

For this example, I am going to use the most basic of login forms.  The form doesn’t even actually work, but it is functional enough to demonstrate how this vulnerability could be exploited.  The form contains a user name and password textboxes, a login button, and an label control that displays copyright information.  Although probably not very obvious, our attack vector here is going to be the copyright label.

Why the Label?

You may be wondering why we are going after the label here.  The biggest reason is that the developers have probably overlooked output encoding on what would normally be pretty static text.  Copyrights do not change that often, and they are usually loaded in the initial page load.  All post-backs will then just re-populate the data from the ViewState.  That is our entry. Here is a quick look at what the page code looks like:

 1: <asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
 2:     <span>UserName:</span><asp:TextBox ID="txtUserName" runat="server" />
 3:     <br />
 4:     <span>Password:</span><asp:TextBox ID="txtPassword" runat="server" TextMode="Password" />
 5:     <br />
 6:     <asp:Button ID="cmdSubmit" runat="server" Text="Login" /><br />
 7:     <asp:Label ID="lblCopy" runat="server" />
 8: </asp:Content>

We can see on line 7 that we have the label control for the copyright data.   Here is the code behind for the page:

 1: protected void Page_Load(object sender, EventArgs e)
 2: {
 3:     if (!Page.IsPostBack)
 4:     {
 5:         lblCopy.Text = "Copy 2012 Test Company";
 6:     }
 7: }

Here you can see that only on initial page load, we set the copy text.  On Postback, this value is set from the ViewState.

The Attack

Now that we have an idea of what the code looks like, lets take a look at how we can take advantage of this.  Keep in mind there are many factors that go into this working so it will not work on all systems.

I am going to use Fiddler to do the attack for this example.  In most of my posts, I usually use Burp Suite, but there is a cool ViewState Decoder that is available for Fiddler that I want to use here.  The following screen shows the login form on the initial load:

I will set up Fiddler to break before requests so I can intercept the traffic.  When I click the login button, fiddler will intercept the request and wait for me to fiddle with the traffic.  The next screen shows the traffic intercepted.  Note that I have underlined the copy text in the view state decoder.  This is where we are going to make our change.

The attack will load in a simple alert box to demonstrate the presence of XSS.  To load this in the ViewState Decoder’s XML format, I am going to encode the attack using HTML Entities.  I used the encoder at to perform the encoding.  The following screen shows the data encoded in the encoder:

I need to copy this text from the encoder and paste it into the copy right field in the ViewState decoder window.  The following image shows this being done:

Now I need to click the “Encode” button for the ViewState.  This will automatically update the ViewState field for this request.   Once I do that, I can “Resume” my request and let it complete.   When the request completes, I will see the login page reload, but this time it will pop up an alert box as shown in the next screen:

This shows that I was able to perform an XSS attack by manipulating a ViewState parameter.  And as I mentioned earlier, this is reflected since it is being reflected from the ViewState.  Win for the Attacker.

So What, I Can Attack Myself

Often times, when I talk about this technique, the first response is that the attacker could only run XSS against themselves since this is in the ViewState.  How can we get that to our victim.  The good news for the attacker…. .Net is going to help us attack our victims here.  Without going into the details, the premise is that .Net will read the ViewState value from the GET or POST depending on the request method.  So if we send a GET it will read it from the querystring.   So if we make the following request to the page, it will pull the ViewState values from the QueryString and execute the XSS just like the first time we ran it:


Since we can put this into a GET request, it is easier to send this out in phishing emails or other payloads to get a victim to execute the code.  Yes, as a POST, we can get a victim to run this as well, but we are open to so much more when it is a GET request since we don’t have to try and submit a form for this to work.

How to Fix It

Developers can fix this issue quite easily.  They need to encode the output for starters.  For the encoding to work, however, you should set the value yourself on postback too.  So instead of just setting that hard-coded value on initial page load, think about setting it every time.  Otherwise the encoding will not solve the problem.  Additionally, enable the built in functions like ViewStateMac, which will help prevent an attacker from tampering with the ViewState, or consider encrypting the ViewState.

Final Thoughts

This is a commonly overlooked area of security for .Net developers because there are many assumptions and mis-understandings about how ViewState works in this scenario.  The complexity of configuration doesn’t help either.  Many times developers think that  since it is a hard-coded value.. it can’t be manipulated.   We just saw that under the right circumstances, it very well can be manipulated.

As testers, we need to look for this type of vulnerability and understand it so we can help the developers understand the capabilities of it and how to resolve it.  As developers, we need to understand our development language and its features so we don’t overlook these issues.  We are all in this together to help decrease the vulnerabilities available in the applications we use.

Updated [11/12/2012]: Uploaded a video demonstrating this concept.


Comments are closed.