Prototype pollution is a very simple vulnerability yet tricky to find. In this blog post, I will try to explain prototype pollution, how it occurs and how should we search to find one.
What is Prototype ?
JavaScript is a dynamic language. You can attach new properties to an object at any time.
1
2
3
4
5
6
7
8
9
10
11
function person() {
this.name = 'Bob';
this.gender = 'Male';
}
let person1 = new person();
let person2 = new person();
person1.age = 15;
console.log(`Person 1 age: ${person1.age}`);
console.log(`Person 2 age: ${person2.age}`); // undefined
The age
property is attached to person1 instance. However, person2 instance will not have the age
property because it is defined only on person1 instance.
So what to do if we want to add new properties at later stage to a function which will be shared across all the instances?
The answer is Prototype
.
A prototype Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function person() {
this.name = 'Bob';
this.gender = 'Male';
}
let instantiated_person = new person();
console.log(`instantiated_person.prototype:\n${instantiated_person.prototype}`);
console.log(`instantiated_person.__proto__:\n${instantiated_person.__proto__}`);
console.log(`person.prototype:\n${person.prototype}`);
console.log(`person.__proto__:\n${person.__proto__}`);
console.log("Is \"person.prototype\" and \"instantiated_person.__proto__\" same ?");
console.log( person.prototype == instantiated_person.__proto__ );
If we update the prototype of the instantiated object, newly instantiated objects will have the updated prototype as well.
1
2
3
4
5
6
instantiated_person.__proto__.job = "doctor";
let newly_instantiated_person = new person();
console.log(`instantiated_person.job is: ${instantiated_person.job}`);
console.log(`newly_instantiated_person.job is: ${newly_instantiated_person.job}`)
As you can see, eventhough newly setted job property passed onto other newly instantiated objects.
newly_instantiated_object
doesnt have the job
property directly, it is set by the prototype.
What is Prototype Pollution ?
If an attacker controls the prototype of an object, s/he can inject arbitrary javascript objects, modify, update or controll the objects.
1
2
3
4
5
let attacker = new person();
attacker.__proto__.bank_account = "attackers_bank_account";
let victim = new person();
console.log(`Victim's bank account: ${victim.bank_account}`);
Attacker polluted the prototype and a prototype pollution has occured.
How Prototype Pollutions Occur ?
Prototype pollutions need some specific conditions to occur. Therefore, they are pretty tricky to find in the wild.
JSON requests are probably one of the most popular environments we find prototype pollutions in but they are still pretty case dependent.
We see prototype pollution especially in the functions such as, merge
, forge
, clone
, extend
, assign
etc.
For example, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
What is the impact ?
As all the javascript objects share the same prototype, an attacker can modify window object and perform Cross Site Scripting attacks. Also we shouldn’t forget that on the desktop applications XSS means RCE.
Analyzing a CVE & Lab
In this part, I suggest you to visit this link http://ctf.m3.wtf/pplab.html
I’ve prepared a small lab that you can follow along.
Useless Prototype Pollution
http://ctf.m3.wtf/pplab1.html
Function can.deparam(https://canjs.com/doc/can-deparam.html) of CanJS is vulnerable to prototype pollution.
In the PoC we will supply __proto__[custom]=test
as an argument to the function
After the first iteration of the loop, current becomes the prototype, and the value polluted
assigned to property custom
And the value polluted is returned
So this, on its own, is not a big deal. We just achieved a prototype pollution but after some try & error, we can see that we can not actually achieve XSS because window object gets overwritten afterwards.
Script Gadgets
Gadgets are life savers in cyber security. The term gadget is being used in many fields, binary exploitation, web exploiation etc. They help you in the exploitation or they basically help you increasing the impact of the vuln.
There are some gadgets in prototype pollution attacks as well. For example,
http://ctf.m3.wtf/pplab2.html
If an attacker can somehow access to JS directly. S/he can achieve XSS with the payload below because there is a prototype pollution in this library. However, by design, it is not a security issue.
1
2
3
4
<script src="https://www.google.com/recaptcha/api.js?render=6LeaqxYbAAAAAF_-OJc1v8VAuRgMg8sK-SRwVAUQ"></script>
<script>
Object.prototype.srcdoc=['<img src onerror=alert(document.domain)>']
</script>
Combining two useless prototype pollution to achieve reliable XSS
As the title suggests, yes we can combine two of those scenarios and achieve reliable XSS. If those 2 libraries are being used in the same website.
http://ctf.m3.wtf/pplab3.html
Summary
In my opinion, this vulnerability is pretty underrated and needs more attention.
Thank you for reading.