Mass Assignment Sensitive Field Exposure

One of the scenarios that I always demonstrate during an ASP.NET MVC class is how to create a mass assignment vulnerability and then execute an over-posting attack. It is a mass assignment vulnerability that led to a severe problem on github last week.

Let's say you have the following model.

public class User { public string FirstName { get; set; } public bool IsAdmin { get; set; } }

When you want to let a regular user change their first name, you give them the following form.

@using (Html.BeginForm()) { @Html.EditorFor(model => model.FirstName) <input type="submit" value="Save" /> }

There is no input in the form to let a user set the IsAdmin flag, but this won't stop someone from crafting an HTTP request with IsAdmin in the query string or request body. Maybe they saw the "IsAdmin" name somewhere in a request displaying account details, or maybe they just got lucky and guessed the name.

If you use the MVC model binder with the above request and the previous model, then the model binder will happily move the IsAdmin value into the IsAdmin property of the model. Assuming you save the model values into a database, then any user can become an administrator by sending the right request. It's not enough to leave an IsAdmin input out of the edit form.

Fortunately, there are at least 6 different approaches you can use to remove the vulnerability. Some approaches are architectural, others just involve adding some metadata or using the right API.

Weakly Typed Approaches

The [Bind] attribute will let you specify the exact properties a model binder should include in binding (a whitelist).

[HttpPost] public ViewResult Edit([Bind(Include = "FirstName")]User user) { // ... }

Alternatively, you could use a blacklist approach by setting the Exclude parameter on the attribute.

[HttpPost] public ViewResult Edit([Bind(Exclude = "IsAdmin")] User user) { // ... }

If you prefer explicit binding with the UpdateModel and TryUpdateModel API, then these methods also support whitelist and blacklist parameters.

[HttpPost] public ViewResult Edit() { var user = new User(); TryUpdateModel(user, includeProperties: new[] { "FirstName" }); // ... }

Strongly Typed Approaches

TryUpdateModel will take a generic type parameter.  You can use the generic type parameter and an interface definition to restrict the model binder to a subset of properties.

[HttpPost] public ViewResult Edit() { var user = new User(); TryUpdateModel<IUserInputModel>(user); return View("detail", user); }

This assumes your interface definition looks like the following.

public interface IUserInputModel { string FirstName { get; set; } }

Of course, the model will also have to implement the interface.

public class User : IUserInputModel { public string FirstName { get; set; } public bool IsAdmin { get; set; } }

There is also a [ReadOnly] attribute the model binder will respect. ReadOnly metadata might be want you want to use if you never want to bind the IsAdmin property. (Note: I remember ReadOnly not working in MVC 2 or MVC 1, but it is working in 3 & 4 (beta)).

public class User { public string FirstName { get; set; } [ReadOnly(true)] public bool IsAdmin { get; set; } }

An Architectural Approach

One of many architectural approaches to solve the problem is to always put user input into a model designed for user input only.

public class UserInputViewModel { public string FirstName { get; set; } }

In this approach you'll never bind against business objects or entities, and you'll only have properties available for the input you expect. Once the model is validated you can move values from the input model to the object you use in the next layer of software.

Whatever approach you use, remember to treat any data in an HTTP request as malicious until proven otherwise.

Mass assignment is a computer vulnerability where an active record pattern in a web application is abused to modify data items that the user should not normally be allowed to access such as password, granted permissions, or administrator status.

Many web application frameworks offer an active record and object-relational mapping features, where external data in serialization formats is automatically converted on input into internal objects and, in turn, into database record fields. If the framework's interface for that conversion is too permissive and the application designer doesn't mark specific fields as immutable, it is possible to overwrite fields that were never intended to be modified from outside (e.g. admin permissions flag).[1]

These vulnerabilities have been found in applications written in Ruby on Rails,[2]ASP.NET MVC,[3] and JavaPlay framework.[4]

In 2012 mass assignment on Ruby on Rails allowed bypassing of mapping restrictions and resulted in proof of concept injection of unauthorized SSH public keys into user accounts at GitHub.[5][6] Further vulnerabilities in Ruby on Rails allowed creation of internal objects through a specially crafted JSON structure.[7]

In ASP.NET Core mapping restriction can be declared using the attribute.[8]

See also[edit]

References[edit]

  1. ^"CWE-915: Improperly Controlled Modification of Dynamically-Determined Object Attributes". Common Weakness Enumeration. NIST. Retrieved February 27, 2013. 
  2. ^"Mass Assignment". Ruby On Rails Security Guide. Retrieved February 27, 2013. 
  3. ^"Mass Assignment Vulnerability in ASP.NET MVC". IronsHay. Retrieved February 27, 2013. 
  4. ^Alberto Souza (2014). "Playframework, how to protect against Mass Assignment". 
  5. ^"GitHub suspends member over 'mass-assignment' hack". ZDnet. 2012. Retrieved February 27, 2013. 
  6. ^"[SEC][ANN] Rails 3.2.12, 3.1.11, and 2.3.17 have been released!". Retrieved January 7, 2016. 
  7. ^"Denial of Service and Unsafe Object Creation Vulnerability in JSON (CVE-2013-0269)". Retrieved January 7, 2016. 
  8. ^https://docs.microsoft.com/en-us/aspnet/core/mvc/models/model-binding

0 thoughts on “Mass Assignment Sensitive Field Exposure

Leave a Reply

Your email address will not be published. Required fields are marked *