Sunday, September 21, 2008 

ASP.NET Defending Against Form Hackers

Something I've pondered previously: an ASP.NET page is populated with data retrieved from ViewState, is it possible to falsify the ViewState in the POST and trick the server into doing something that it shouldn't. In other words, a scenario where the original developer is just "trusting" information coming from ViewState.

Here's an example - a company 'extranet' application which gives me an admin page to manage the username/passwords of my subordinate users. Let's guess the "trusting" developer behind this system implements the save by iterating over the GridView rows, and updating the database with the emails / passwords in the textboxes.

My superior's login is 'jvandelay' - of course I'm not able to see his record on my admin screen. After a postback the page is being populated using the data stored in ViewState. Can I craft up some viewstate that will add a row to the dataview, allowing me to update my superior's password?

Seaching around gets some good articles to answer my intial questions.

  • Can you falsify ViewState? By default: no - From ScottGu's Cool Viewstate Decoder: "Note that ViewState is MAC (message authentication check) encoded to prevent tampering by remote clients. As such, while you can decypher the viewstate settings using the above program, you can't actually change them and repost to the server.". There is a setting "EnableViewStateMac" on the @ Page directive to switch this off, so we can have a play around.
  • How would you build a falsified ViewState? Paul Wilson's ViewState: All You Wanted to Know give a good intro to the ViewState format, and the LosFormatter class used to serialize/deserialize ViewState

How do you craft up the 'malicious' ViewState? Let's start with deserializing the ViewState using LosFormatter. Paul Wilson's article provides a some code to traverse the object graph. See the results here. Now I can insert the objects into the object graph to fake an extra row in the ViewState. I've modified Paul Wilson's code to give to generate code to access the unwieldy positions in the graph, see the code here.

Here's the code to fake the ViewState, and serialize it back to a string we can put in a browser: here. The fake ViewState can be inserted into the __VIEWSTATE hidden field with the Web Developer extension in Firefox: right-click > Web Developer > Forms > Display Form Details. Click 'Save' and we get...

Foiled by EventValidation - somthing else I can switch off in the @ Page directive. More on Event Validation in K. Scott Allen's ASP.NET Event Validation and “Invalid Callback Or Postback Argument” : Part I. Interestingly the __EVENTVALIDATION value is derived from a hash of UniqueIDs XORed with a hash of the allowed values. Would I be able to fake this also? Maybe I'll follow that up in another blog article...

Anyway with EnableEventValidation off we get:

Success! And I certainly can fill in the email and password details for 'jvandelay' and see them saved! So it is did take quite a few things to come together to make this possible:

  • the original developer was a little to 'trusting' - the application could be testing if my login is attempting to update a superior's details
  • ViewState MAC encoding and Event validation needed to be turned off

Labels: ,