In this blog, we are going to see the difference between HTTP parameter pollution and mass assignment.
They both seem to be kind of similar as they both require the attacker to inject an ‘extra’ parameter that causes the application to act in a weird way. But this is only on the surface level, behind the scenes they both are very different. Let’s have a look at these examples.
HTTP Parameter Pollution (Web Vulnerability) #
Exploitation: Attackers exploit HTTP Parameter Pollution by sending multiple parameters with the same name in a single HTTP request. For example, if an application expects a single user
parameter, the attacker might send:
https://example.com/login?user=admin&user=guest
Behavior: Depending on how the application processes these duplicate parameters, it may exhibit unexpected behavior. Some applications might use the first parameter, others might use the last, and some might concatenate the values. This depends on the web framework being used by the application, for example PHP gives more priority to last parameter.
Impact: This can lead to various security issues, such as bypassing security checks, altering application logic, or facilitating injection attacks. For example, an application might bypass input validation or use a default value due to the unexpected input.
If you want to learn everything about parameter pollution, check out this video!
HTTP Parameter Pollution: Vulnerable Code (PHP) Example #
//login.php
<?php
// Connect to the database
$conn = new mysqli("localhost", "username", "password", "database");
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// Get user parameter from the query string
$user = $_GET['user'];
// Construct SQL query
$sql = "SELECT * FROM users WHERE username = '$user'";
// Execute query
$result = $conn->query($sql);
if ($result->num_rows > 0) {
// User found
echo "Welcome, " . $user . "!";
} else {
// User not found
echo "User not found.";
}
$conn->close();
?>
Explanation #
- The script retrieves the
user
parameter from the query string using$_GET['user']
.: - The
user
parameter is directly inserted into the SQL query without any sensitization or validation. (This is SQL Injection vulnerability in itself but for this scenario ignore it). - The SQL query is executed.
Vulnerable Behavior #
- If an attacker sends a request with duplicate
user
parameters, likehttps://example.com/login?user=admin&user=guest
, the behavior depends on the server’s handling of duplicate parameters. - In PHP,
$_GET['user']
would typically hold the last value, i.e.,guest
.
Secure Code Example: #
<?php
if (isset($_GET['user'])) {
$user = is_array($_GET['user']) ? $_GET['user'][0] : $_GET['user'];
echo "Hello, " . htmlspecialchars($user) . "!";
} else {
echo "Hello, guest!";
}
?>
- This code checks if
$_GET['user']
is an array (indicating multiple parameters). - If it is an array, it takes the first element. Otherwise, it uses the single value.
- This approach ensures that only the first occurrence of the
user
parameter is used, mitigating the HPP vulnerability.
Mass Assignment (API Vulnerability) #
Exploitation: Attackers exploit Mass Assignment by sending additional parameters that the application does not explicitly expect or validate. Web frameworks often map user input directly to model attributes, and if not configured correctly, this can include unintended parameters. For example, a user registration form might unintentionally allow an attacker to set an isAdmin
attribute:
POST /register
{
"username": "newuser",
"password": "password123",
"isAdmin": "true"
}
Behavior: The application automatically binds all provided parameters to the user model, potentially allowing attackers to set properties they should not control.
Impact: This can lead to unauthorized actions, such as privilege escalation, where a regular user gains administrative rights, or tampering with critical settings
If you want to learn more about Mass Assignment, watch this video 👇.
Mass Assignment: Vulnerable Code (Ruby on Rails) #
#app/controllers/users_controller.rb
class UsersController < ApplicationController
def create
@user = User.new(user_params)
if @user.save
redirect_to @user, notice: 'User was successfully created.'
else
render :new
end
end
private
def user_params
params.require(:user).permit(:username, :password, :isAdmin)
end
end
Explanation #
- User Parameters Handling:
- The
user_params
method allows:username
,:password
, and:isAdmin
parameters to be assigned directly to theUser
model. - This method is intended to filter which parameters can be assigned, but here it mistakenly includes
:isAdmin
.
- The
- Mass Assignment Vulnerability:
- When the application receives a registration request, it automatically assigns all provided parameters to the
User
model. - An attacker can exploit this by sending a
POST
request with theisAdmin
parameter, setting it totrue
.
- When the application receives a registration request, it automatically assigns all provided parameters to the
You should check out the practical example with labs in this video to understand this better.
What is an Object here tho? #
In the case of mass assignment, an object is usually a data model that represents an entity in the application, such as a user, product, or order. This model object will have attributes or properties corresponding to the columns in the database table.
For example, consider a User
object in a web application:
class User
attr_accessor :username, :password, :isAdmin
def initialize(username, password, isAdmin = false)
@username = username
@password = password
@isAdmin = isAdmin
end
end
In a framework like Ruby on Rails, a User
model might be defined to interact with a users
table in the database.
Secure Code #
#app/controllers/users_controller.rb
class UsersController < ApplicationController
def create
@user = User.new(user_params)
@user.isAdmin = false # Ensure isAdmin is not set through mass assignment
if @user.save
redirect_to @user, notice: 'User was successfully created.'
else
render :new
end
end
private
def user_params
params.require(:user).permit(:username, :password)
end
end
Explanation #
- User Parameters Handling:
- The
user_params
method only allows:username
and:password
to be set for theUser
model. - The
:isAdmin
parameter is not included, so it cannot be set through this method.
- The
- Explicitly Handling Sensitive Attributes:
- The line
@user.isAdmin = false
in the controller sets theisAdmin
attribute tofalse
. - This ensures that it cannot be changed through the user input, blocking any attempt to make a user an admin during registration.
- The line
- Preventing Mass Assignment:
- By not allowing
:isAdmin
in the permitted parameters and setting it explicitly, you prevent attackers from changing this attribute by sending a specialPOST
request.
- By not allowing
Similarities in Exploitation #
Both vulnerabilities involve manipulating input parameters sent to the web application. In both cases, the attacker provides unexpected input to trick the application into behaving in unintended ways. This manipulation often leads to security issues by exploiting how the application processes and validates input.
Differences #
- HTTP Parameter Pollution: This is when you trick the application by sending multiple instances of the same parameter. Depending on the web framework being used, the application gives precedence to a particular parameter, which can cause the app to act in unexpected ways.
- Mass Assignment: This is when you add another parameter in the JSON body of the HTTP request, which already exists in the backend, but its value is not supposed to be set by a normal user. In this case, a normal user can change the value of that parameter, which can cause the application to behave in an unexpected way.
Final Thoughts #
By analyzing the backend code, we can see that both vulnerabilities are different behind the scenes. It is important to understand the difference. Also, I’ve created multiple videos on mass assignment and parameter pollution as well. Don’t forget to check them out!