Prototype Pollution - Part 1
Part 1 of exploring the Prototype Pollution vulnerability.
Last updated
Part 1 of exploring the Prototype Pollution vulnerability.
Last updated
Prototype Pollution is a JavaScript vulnerability that allows attackers to add arbitrary properties to global object prototypes which may then be inherited by user-defined objects.
Just to note, Prototype Pollution cannot be exploited as a standalone vulnerability. In fact, when it was discovered, many security researchers thought that the way that it can be exploited is very theoretical and it won't happen in reality but history has proven them wrong . So why do researchers feel that it is theoretical? It is because Prototype Pollution allows attacker to control properties of objects that would otherwise be inaccessible. However, if the application handles an attacker-controlled property in an unsafe way, Prototype Pollution could be chained with other vulnerabilities and it can lead to deadly consequences! If it is client-slide, it will usually lead to a DOM XSS vulnerability. If it is server-side, it can lead to remote code execution (RCE).
To understand how it works, we need to be familiar with how prototype and inheritance work in JavaScript. So Imma give a crash course.
Unlike Java, JavaScript uses a prototype inheritance model which works differently from the class-based model which we are used to in languages like C#, Java or Golang. Both are different styles of Object-Oriented Programming (OOP). Below is a table that shows the differences:
Definition
Objects inherit directly from other objects aka prototypes.
Objects are instances of classes that define a blueprint.
Programming Languages
JavaScript.
Java, C#, Golang and many others.
Inheritance Mechanism
Use object prototypes where objects inherit properties directly from other objects.
Uses classes and instances, where objects are instantiated from a class.
Object Creation
Objects are created by cloning other objects.
Objects are instantiated from class templates.
Method Sharing
Methods are shared via the prototype chain.
Methods belong to the class and are inherited by instances.
Encapsulation
Less enforced; any object can modify its prototype chain.
More structured, with class-based encapsulation mechanisms.
A JavaScript object is essentially just a collection of key:value
pairs known as "properties". It is similar to JSON. Properties can include data and as well as executable functions. This function can also be known as a method.
To access these properties we can use the following:
When you reference a property of an object, the JavaScript engine will first try to find it in the object. If it is not there, it will look for it in the object's prototype. In this example from the picture above, I can reference myObject.propertyA
.
Every object in JavaScript is linked to another object of some kind, this is known as its prototype. Since JavaScript is a prototype inheritance model, every new object will be automatically assigned to one of JavaScript's built-in prototypes. For example, strings are automatically assigned to the built-in String.prototype
.
As we know, these objects will automatically inherit all of the properties of their assigned prototype, unless they already have their own property with the same key. This helps developers to create new objects that can be reuse the properties and methods of existing objects.
As everything in JavaScript is an object, this chain leads back to the top level Object.prototype
, whose prototype is a null
.
Another thing we should take note of is that objects don't just inherit properties from their immediate prototype, they also inherit properties from all the objects above them in the prototype chain.
Each object has a special property that you can use to access its prototype. We can use __proto__
! __proto__
serves as both the getter and setter for the object's prototype. This means that you can use it to read the prototype and even change it!
We can even chain the prototype of an object!
Since __proto__ is used as a getter and setter, it is possible to modify JavaScript's built-in prototypes. This also means that developers can customize or override the behaviour of built-in methods and even add new methods to perform useful operations.
Prototype pollution vulnerabilities arise when a JavaScript function recursively merges an object that contains user-controllable properties into an existing object without sanitizing the keys! This allows attackers to inject a property with a key like __proto__
along with arbitrary nested properties.
Because __proto__
has a special meaning, the merge operation may assign the nested properties to the object's prototype instead of the target object itself! This allows the attacker to pollute the prototype with properties that contain values which can be used by the application in a dangerous way.
To exploit this successfully, we need a few key components:
A prototype pollution source - This is any input that enables you to poison the prototype objects with arbitrary properties.
A sink - a JavaScript function or DOM element that enables arbitrary code execution.
An exploitable gadget - Basically any properties that is passed into a sink without proper sanitization.
I will continue on how we can exploit Prototype Pollution in another Part 2 article.
What is Prototype pollution?
How does prototype-inheritance model contribute to the Prototype pollution vulnerability?
How does the prototype chain relate to prototype pollution?
Offsec - Advanced Web Attacks and Exploitation
Frost