Introduce the flaw
When developing software, developers often use pre-built frameworks for development. This is both convenient and minimizes the time and effort of building up from scratch. These frameworks have been developed with security features in place to help ensure the security of the application being developed. But sometimes improper use or misuse causes serious vulnerabilities.
Some web development frameworks (e.g. Laravel, Ruby on Rails, ..), for development convenience, it allows the developer to automatically push parameters via HTTP requests into program variables or arguments. statue. From there, the program will take and process data on the server. This sometimes causes problems and security. An attacker can take advantage of this to insert malicious data that are parameters of the program (these parameters are not allowed or transmitted by developers) to execute the undesirable behavior. This security vulnerability is known as Mass Assigment.
Some other names for this attack:
- Mass Assignment : Ruby on Rails, NodeJS.
- Autobinding : Spring MVC, ASP NET MVC.
- Object injection : PHP
How to attack
To better understand how to attack, let’s go through a few examples to better understand this security vulnerability.
Example 1: Create a new user in the system
User has the following fields of information:
1 2 3 4 5 6 7 8 9 | public class User { private String userid; private String password; private String email; private boolean isAdmin, default: false; //Getters & Setters } |
The programmer creates a new user creation form as follows:
1 2 3 4 5 6 7 | <form> <input name="userid" type="text"> <input name="password" type="text"> <input name="email" text="text"> <input type="submit"> </form> |
Here, the developer designed to allow users to update 3 fields: userid, password và email
The processing of the controller will be done as follows:
1 2 3 4 5 6 | @RequestMapping(value = "/addUser", method = RequestMethod.POST) public String submit(User user) { userService.add(user); return "successPage"; } |
And a normal reuqest posted would look like this:
1 2 3 4 | POST /addUser ... userid=bobbytables&password=hashedpass& <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> |
As usual, after the POST request is submitted, the application will read and retrieve the data and insert into the database. A user is created with the following information:
- userid : bobbytables
- password : hashedpass
- email : [email protected]
- isAdmin : false
A normal flow of work and of course here, the developer has completed the task of feature development and it runs completely fine.
So how can the above application be hacked? The problem here is that in the controller processing, the developer has inadvertently created an opportunity for the attacker to perform the attack. As we can see, the user has 4 fields of information and the developer develops a feature that allows the creation of a user with the above 3 fields (not including the: isAdmin field) because this field is an important field that defines the role of the user and should only be updated by the system admin. But controller, developer process to receive all user parameters passed without checking which parameters are allowed or not?
So the hacker will perform the attack by passing more parameters in the request to create a new user:
1 2 3 4 | POST /addUser ... userid=bobbytables&password=hashedpass& <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> &isAdmin=true |
After the POST request is sent, the application will perform read and retrieve data and perform insert into the database. A user is created with the following information:
- userid : bobbytables
- password : hashedpass
- email : [email protected]
- isAdmin : true
So attacker can create a user as admin account. Obviously this was not by design and caused a critical vulnerability, allowing a highly privileged account to be created in the system.
So we understand how this vulnerability attacks. But there is one more problem here, is how an attacker can guess that the user has the isAdmin
information isAdmin
to perform the attack. There are several ways that an attacker can find it.
- Through the function of viewing user information, updating user information attacker can see the fields that the user has
- Through the review of the sourcode and documentation of the system
- Through guessing technique to guess some sensitive information field. (Example: isAdmin, admin, isAthenticated ..)
Consequence
The consequences of this vulnerability depend on the function and the field that an attacker can attack. It can cause several types of attacks:
- Privilege escalation attacks in the system
- Attacks unauthorized modification of information in the system
Prevention
Depending on the framework we use, we have different behavior, but it all will follow the same mechanism:
- Whitelist fields are allowed to bind
- Blacklist fields are not allowed to bind
- Use Data Transfer Objects ( refer here ). DTO defines exactly what fields are allowed to bind:
1 2 3 4 5 6 7 8 9 10 | public class UserRegistrationFormDTO { private String userid; private String password; private String email; //NOTE: isAdmin field is not present //Getters & Setters } |
Some examples of implementation with frameworks
Spring MVC
Whitelisting
1 2 3 4 5 6 7 8 9 10 11 | @Controller public class UserController { @InitBinder public void initBinder(WebDataBinder binder, WebRequest request) { binder.setAllowedFields(["userid","password","email"]); } ... } |
Blacklisting
1 2 3 4 5 6 7 8 9 10 11 | @Controller public class UserController { @InitBinder public void initBinder(WebDataBinder binder, WebRequest request) { binder.setDisallowedFields(["isAdmin"]); } ... } |
PHP Laravel
Whitelisting
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?php namespace App; use IlluminateDatabaseEloquentModel; class User extends Model { private $userid; private $password; private $email; private $isAdmin; protected $fillable = array('userid','password','email'); } |
Blacklisting
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?php namespace App; use IlluminateDatabaseEloquentModel; class User extends Model { private $userid; private $password; private $email; private $isAdmin; protected $guarded = array('isAdmin'); } |
See more frameworks here
Case study
Github: Public Key Security Vulnerability and Mitigation
In 2012, Github was exposed to a Mass Assigment vulnerability. A hacker exploited the vulnerability through the public key update form to be able to add his public key and rails organization, from which he could access the github of this organization and push the file up as he pleased.
During security testing, I also encountered many applications that encountered the above error. The application still allows updating information fields that are not allowed. So, right now, developers need to review to see if they have done as recommended by the frameworks to avoid this vulnerability.