First of all, what is a JavaScript Object
?
JavaScript objects are used to store various key:value
pairs. They can be seen as collections of properties, where each property is an association between a key and a value. These values can be a function
, an array
, another object
, or any other data type available in JavaScript, including numbers
, strings
, and booleans
.
What is surprising is that all of the data structures are Objects
under the hood, even functions!
What is a Prototype
in JavaScript?
Let's use a student and teacher analogy.
Imagine a Classroom
- Student (Object): knows some things, may not know others.
- Teacher (Prototype): knows a lot of things and can teach students.
Example
If you ask the student to solve a multiplication problem:
- The student first tries to solve it on their own.
- If they can't, they ask the teacher.
- The teacher explains how to do multiplication.
- Now, the student can solve multiplication problems too.
Objects (students) like strings
, functions
, arrays
are linked to other objects (teachers) through prototypes.
For example, all strings are assigned the String.prototype
, where they inherit the toUpperCase()
method. As a result, all strings automatically have a ready-to-use method for converting them to uppercase, amongst others.
How Prototype Inheritance works
In programming terms, when we reference a property of an object (asking the student to solve a multiplication problem), JavaScript tries to access it directly first (step 1 of our analogy). But if said object doesn't have a matching property to return, then it will start to look (ask the teacher) for it on the object's prototype instead.
That's why we could call toUpperCase
function on input
variable without defining it first.
The Prototype Chain 😱
- Everything is an Object in JavaScript
- Every Object gets assigned a Prototype from where it inherits properties and methods
- Then... every Prototype is an Object
- Therefore... every Prototype has a Prototype assigned to it. And so on
This madness is called "The Prototype Chain" and it ultimately leads back to the top-level Object.prototype
, whose prototype is simply null
. (Don't look at us like that, alright? It's not our fault.)
Most importantly, objects inherit properties and methods from all the objects' prototypes above them in the chain. This means that our input
object has access to the properties and methods of both String.prototype
and Object.prototype
.
Modifying Prototypes
You can access an object's prototype by using its __proto__
property. And you can use it to read or reassign any prototype's properties. (You can also play around the prototype chain)
Understanding Client Prototype Pollution Vulnerabilities
Prototype Pollution vulnerabilities arise when a JavaScript function recursively merges an object containing user-controllable data into an existing object, without first sanitizing the keys. This may allow a bad actor to inject the __proto__
key along with arbitrary nested properties.
Then, the merge operation may assign these nested properties to the object's prototype instead of the target object itself, allowing the bad actor to pollute prototypes with harmful values.
For successful exploitation of Prototype Pollution you require three key components:
- A prototype pollution source --> This is any input that enables you to poison prototype objects with arbitrary properties.
- An exploitable gadget -->This is any property that is passed into a sink without proper filtering or sanitization.
- A sink --> A JavaScript function or DOM element that enables arbitrary code execution.
But don't worry about those for now, we'll learn more about them in a future blog post. Stay tuned for more experienced exploits!
Exploiting Client Prototype Pollution Vulnerabilities
On your web application add the ?__proto__[vulnerable]=true
parameter as follows:
https://website.com/?__proto__[vulnerable]=true
In this case, the JS engine will treat __proto__
as a getter for the object's prototype and assign the vulnerable
key to it. Assuming that the target object uses the default Object.prototype
, all objects in the JavaScript runtime will now inherit vulnerable
, unless they already have a property of their own with a matching key.
In our analogy terms, we showed the teacher the vulnerable
payload, so all the students will now learn the same. Making the whole classroom vulnerable.
In practice, injecting a property called vulnerable
is unlikely to have any effect on the web app. However, a bad actor can use the same technique to pollute the prototype with properties that are used by the application, or any imported libraries.
vulnerable
property into it (or any other property name you tested).Other useful tips
- If the property was not added to the prototype, try switching to dot notation rather than bracket notation, or vice versa:
https://website.com/?__proto__.vulnerable=true
- If neither of these techniques is successful, you may still be able to pollute the prototype via its constructor. We'll cover this in a future blog post, but have in mind that
myObject.constructor.prototype
is equivalent tomyObject.__proto__
. - So
https://website.com/?constructor.prototype.vulnerable=true
orhttps://website.com/?constructor[prototype][vulnerable]=true
provide an alternative vector for Prototype Pollution.
Conclusion
We have shared some insights about Prototype Pollution vulnerabilities so you can start looking for them in the wild. That way, we are part of your Cyber Security journey. We would love to see you succeed.
That's why we invite you to experience the VIDOC tool firsthand by trying our platform are free. There are several vulnerability modules so you can sit back and wait for vulnerabilities to arise. Check them out here.
_________________________________________________________
Check our other social media platforms to stay connected:
Website | www.vidocsecurity.com
Linkedin | www.linkedin.com/company/vidoc-security-lab
X (formerly Twitter) | twitter.com/vidocsecurity
YouTube | www.youtube.com/@vidocsecuritylab
Facebook | www.facebook.com/vidocsec
Instagram | www.instagram.com/vidocsecurity