Prompt Injection
Andrea Hauser
How to Exploit Prototype Pollution
This section describes JavaScript basics. If you are already familiar with JavaScript, you can easily skip this section.
An object is actually just a collection of properties, where properties are key:value
pairs. An object looks like this:
var exampleObject = { test: "value", exampelMethod: function() { //do something here console.log("test") } }
The properties of an object can be accessed as follows:
exampleObject.test
or
exampleObject['test']
and the method of an object can be accessed as follows:
exampleObject.exampleMethod();
The example above is an explicitly declared object, but in JavaScript almost everything is based on objects in the background. This is solved via the prototype.
The prototype is the mechanism used in JavaScript for inheriting elements from objects. The prototype of an object is nothing more than another object that also has its own prototype. And since practically everything in JavaScript below the surface is an object, this chain ultimately leads back to the uppermost Object.prototype
, whose prototype is then simply the value null
.
In practice, this means that JavaScript does the following in the background when a property is accessed by means of exampleObject.test
or exampleObject['test']
.:
test
in the object exampleObject
.undefined
is returned.An object’s prototype can be accessed as follows:
__proto__
constructor.prototype
With these basics, you should now be able to understand JavaScript Prototype Pollution.
With prototype pollution, an attacker aims to modify Object.prototype
. Since almost all elements in JavaScript inherit from Object, almost all elements can be attacked, if Object.prototype
can be changed. In most cases, prototype pollution is triggered by an insecure merge function that recursively takes properties from an untrusted source. Olivier Arteau describes such a merge function in his paper Prototype pollution attack in NodeJS application as follows:
merge(target, source) foreach property of source if property exists and is an object on both the target and the source merge(target[property], source[property]) else target[property] = source[property]
For Prototype Pollution the following is needed:
The DOM Invader is an extension of the Chromium browser that comes with Burp. This extension is normally deactivated, as it can have unwanted side effects. It can be activated as follows:
In the browser supplied with Burp, select the extension with the title Burp Suite:
Select and activate DOM Invader in the window that opens:
As soon as the extension is active, the web page that is being checked for prototype pollution can be reloaded. This will set up the DOM Invader in the background. In the Developer Tools there is now a new entry with the title DOM Invader. When this is selected, the results of the DOM Invader analysis are displayed. In the example below, two Prototype Pollution possibilities have been identified:
With Scan for gadgets
you can search for gadgets that turn Prototype Pollution into XSS. The scanning looks like this:
And the result of a successful scan as follows:
in the simplest case you can simply select the option Exploit
and an alert(1)
will be executed. If no alert appears, the error message should be displayed in the console and by means of the StackTrace available there, you end up in the JavaScript at the place where the prototype pollution is going wrong. From there, you can simply analyse the payload and adjust it as expected so that the alert is executed.
The manual search for JavaScript prototype pollution can be very time-consuming, especially if the JavaScript code used by the website has been minified. How to go about this has been covered better and in more depth in the articles by Portswigger and Nikita Stupin than can be done here. Reading these articles is highly recommended to deepen one’s knowledge of prototype pollution. In particular, the Portswigger article is recommended, as it also offers labs where the techniques learned can be applied directly.
There are different ways to protect against JavaScript Prototype Pollution. These each come with different advantages and disadvantages:
Object.create(null)
toString()
can no longer be used, as these standard functions are inherited by user-defined objects via the Object Prototype.__proto__
Object.freeze()
Object.seal()
can be used, then no new properties can be defined, but existing properties can still be changed.JavaScript Prototype Pollution is a complex attack possibility that can lead to cross-site scripting or in the worst cases even remote code execution on the server side. It is possible to find such vulnerabilities manually, but it is very time-consuming since most modern websites have a lot and most of the time minified JavaScript code. However, since Portswigger, the developers of Burp, have dealt extensively with the topic, good tooling for identifying this type of vulnerability is provided within Burp. Developers have a wide range of options with various advantages and disadvantages for hardening JavaScript code against Prototype Pollution.
Our experts will get in contact with you!
Andrea Hauser
Andrea Hauser
Andrea Hauser
Andrea Hauser
Our experts will get in contact with you!