Prototype Pollution – what is it, how can you exploit it, how to defend against it, and more…

AGENDA

Okay, let’s explore a vulnerability known as Prototype Pollution. Here is a quick outline of what we’re going to cover, in case you want to jump to any specific section(s).

  • JavaScript Primer
  • Vulnerability
  • History
  • Exploitation
  • Defense
  • References
  • Hands-On Learning
  • Conclusion

Quick disclaimer before we continue: you will at the very least have to know some programming. Having familiarity with JavaScript syntax also helps. But, if you at least have programming experience, you can somewhat pick up the syntax and still follow along.

Also, please use this for educational purposes. Do not use this to conduct any illegal or unethical actions. Before you attempt to do any testing on devices that you do not own, ensure you get the proper authorization and follow the appropriate laws.

JAVASCRIPT PRIMER

Without diving crazy deep into programming, a class is seen as a blueprint template, where objects are created from. Both class-based and prototype-based programming styles have classes, but the difference is how inheritance is implemented. In class-based, inheritance is extended by defining the class of the object. In prototype-based, an instance is instead cloned.

JavaScript is a programming language that is known as a prototype-based object-orientated language. Inheritance is a mechanism within most object-orientated languages where the creation of an object or an instance receives its characteristics from its “parent” class.

Now that you are fully confused, let’s use an example to hopefully clear the mind. A very easy example is taking a simple subject like a house and breaking it down further. All houses have features like color, stories, bedrooms, bathrooms, etc. If house is an object, then the features are what we would refer to as properties.

Consider the following code snippet, where we create two objects called “house1” and “house2” and we assign different values to the same properties or features:

var house1 = {color: “Brown”, stories: 2, bedrooms: 4, bathrooms: 2};
var house2 = {color: “Yellow”, stories: 1, bedrooms: 3, bathrooms: 2};

If we want to select a specific property within the object, we can refer to it as such:

Command: house2.color;
OR
Command: house2[‘color’];

Both commands should output ‘Yellow’

What happens if you try to access a property that does not exist, for example, property named “garage”? If the property does not exist, the commands will return “undefined” basically meaning that value was not assigned or declared.

In addition to properties, objects also have methods. Methods work similar to functions, in that it takes something as input and returns something as output. In JavaScript, when a method of an object is called, but that method is not defined within that object, JavaScript will actually search for the method within the object of the parent. Back to our house example, if the method turnLightOn() is not defined in the “house” object, it will attempt to find it in its parent. In this case, “Object” is defined as the class which the house object was cloned from.

Again, now that we are super confused, let’s check out the code snippet below:

Command: Object.getPrototypeOf(house)
Output: {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, …}

What just happened?? In addition to the properties (color, stories, etc) that we declared for the object house, there are some special “inherit” properties. [[Prototype]] is one of those special properties. In the code above, we used the getPrototypeOf() method to return the prototype values of the object “house”. The output actually looks very familiar to Object.prototype. In this specific case, we are actually referring to the built-in JavaScript class known as “Object”. Another way to return prototype values of objects is to use __proto__. See below for example:

Command: house.__proto__
Output: {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, …}

We are basically asking, “What values are inherit to thi object?” In this case the parent class is Object, so we see those values. Some objects have parents of parents multiple times before it reaches the parent class of “Object”. This concept is known as Prototype Chaining.

VULNERABILITY

Spoiler alert, in case you haven’t guessed it by now, the vulnerability exists because of the way the language works normally. Child objects inherit properties and methods from parent classes. If we are able to manipulate certain values of the parent class, the child object can also be subject to manipulation since it receives those values from the parent. Enter prototype pollution, where you pollute the prototype property of the parent class and therefore pollute the values of it’s child objects.

The majority of this research began with Olivier Arteau in which he outlines the vulnerability in great detail. I will link the video and research paper in the References section.

According to Olivier’s research, there are 3 specific API that can be exploited

  • Object recursive merge
  • Property definition by path
  • Object clone
  • BONUS: Extend operation – another vulnerable API, which was not discussed until ~2019

And wouldn’t you know that they all have to do with user input. If the attacker can manipulate certain parameters, they are able to pollute the prototype, and depending on how the application works, it can lead to RCE.

Although this vulnerability technically existed since the birth of the programming language, it hasn’t always been publicly known. As a matter of fact, as or right now, the exploit is relatively “new”. Before we break down the exploitation, let’s see how things evolved over time.

HISTORY

I have done my best to identify the majority of articles, videos, and papers related to this, but I am human so I may have missed one or two. With that said, here’s a breakdown the highlights that has lead to this exploit:

  • Nicholas Zakas wrote an article in 2010 discussing a talk he previously gave back in 2007. Here he discusses the ability to modify objects you don’t inherently “own” (i.e. objects that are built in to the programming language). He basically identifies that while it is possible and potentially advantageous in the short run, it can lead to confusion and disaster in the long run. At the time it was seen more through an administrative lens as opposed through a security lens.
  • Fast forward to 2014, and Nicolas Bevacqua briefly discusses Object.prototype pollution. This is the first instance I was able to find the specifically refers to this technique as prototype pollution. Based on his article, it still seems to be a relatively unknown topic, but it is beginning to flourish.
  • Now, jump to 2018, where security researcher, Olivier Arteau (which I mentioned previously) releases a white paper and presented his research in great detail at NorthSec. There are numerous articles that reference his research, and this seems to be the point where this vulnerability is taken seriously.
  • In 2019, Snyk released an article discussing a prototype pollution vulnerability specific to jQuery library.
  • Finally, in 2019-2020, security researcher at Securitum, Michal Bentkowski, released two articles detailing prototype pollution, and how he used it specifically to exploit Kibana and gain RCE. On the account of how widely popular Kibana is, his research has been heavily referenced.

By now, we should have a decent understanding of why this vulnerability exists, and how it developed until now. This next section is probably why you are really here for: exploitation. Without further ado, let’s check it out.

EXPLOITATION

So previously we discussed that certain operations that takes user input can lead to exploitation. Here is a very basic example that Olivier and Nikita presents:

var a = {};
var b = process.argv[2];
var c = ‘test’;
var d = process.argv[3];
console.log(({}).test);

If we run the above program and give “__proto__” as the first argument and something “random” like “123” as the second argument, the output will be undefined. That is because object a does not have a property named “test”; therefore, similar to our example earlier, the result is undefined. What happens if we do the following:

a[b][c] = d;
console.log(({}).test);

When you run this program with the same arguments: __proto__ 123, the result will be 123. By assigning __proto__ to variable b, you are basically defining the property of c with the value of d for the object of a.

This of course is a very rudimentary example and will not likely be found in the real world. However, there are a few real world examples that I will drop the links to in the References section.

Ultimately the impact depends on how the library is used or how the application works. Based on real world examples, the impact can be anywhere from DoS to RCE.

DEFENSE

Two main mitigation techniques are using an object without a prototype (object.create(null)) and using freezing object.prototype using the object.freeze() method. The downsides to those defense mechanisms is that it can break normal functionality of certain functions and dependencies.

Two additional techniques are validating input against a JSON schema and using Map instead of Object. The key difference between the two is that Object has prototypes, but Map does not not. Map only contains the properties that are specifically assigned to it.

Really, other “mitigation methods” is having a defense in depth mindset. Don’t allow applications to run as root on a system. Monitor the network traffic to your system to quickly identify the root cause of the DoS and be able to recover from it. This means having a plan in place and validating that plan in case services are denied access for whatever reason. You can have the best defense mechanisms in the world, but nothing is impenetrable. One day, something will get through and cause destruction. Through proper logging, monitoring, and recovery operations, you can drastically reduce a negative impact on day to day operations.

REFERENCES

In this section, I am going to provide a list of references that I used to generate this article. Unbeknownst to me, there are actually quite a few articles and videos out there that can really help you better grasp this vulnerability.

  • https://humanwhocodes.com/blog/2010/03/02/maintainable-javascript-dont-modify-objects-you-down-own/
  • https://ponyfoo.com/articles/how-to-avoid-objectprototype-pollution
  • https://www.youtube.com/watch?v=LUsiFV3dsK8&ab_channel=NorthSec
  • https://github.com/HoLyVieR/prototype-pollution-nsec18
  • https://blog.0daylabs.com/2019/02/15/prototype-pollution-javascript/
  • https://github.com/Kirill89/prototype-pollution-explained
  • https://medium.com/node-modules/what-is-prototype-pollution-and-why-is-it-such-a-big-deal-2dd8d89a93c
  • https://snyk.io/blog/after-three-years-of-silence-a-new-jquery-prototype-pollution-vulnerability-emerges-once-again/
  • https://codeburst.io/what-is-prototype-pollution-49482fc4b638
  • https://blog.sonatype.com/cve-2018-16487-lodash-rce-prototype-pollution
  • https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/
  • https://research.securitum.com/prototype-pollution-and-bypassing-client-side-html-sanitizers/
  • https://blog.sonatype.com/how-can-adversaries-exploit-npm-modules
  • https://portswigger.net/daily-swig/prototype-pollution-the-dangerous-and-underrated-vulnerability-impacting-javascript-applications
  • https://portswigger.net/daily-swig/prototype-pollution-bug-in-popular-node-js-library-leaves-web-apps-open-to-dos-remote-shell-attacks
  • https://portswigger.net/daily-swig/node-js-applications-open-to-prototype-pollution-attacks-via-legacy-function-in-popular-encryption-library
  • https://portswigger.net/daily-swig/prototype-pollution-vulnerability-left-bug-bounty-platform-hackerone-open-to-attack
  • https://www.youtube.com/watch?v=__65_GFERKs&ab_channel=CyberSecurityTV
  • https://github.com/BlackFan/client-side-prototype-pollution
  • https://blog.p6.is/AST-Injection/
  • https://blog.p6.is/Real-World-JS-1/
  • https://infosecwriteups.com/javascript-prototype-pollution-practice-of-finding-and-exploitation-f97284333b2
  • https://labs.detectify.com/2021/06/08/what-is-a-prototype-pollution-vulnerability-and-how-does-page-fetch-help/
  • https://book.hacktricks.xyz/pentesting-web/deserialization/nodejs-proto-prototype-pollution
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript
  • https://www.w3schools.com/js/default.asp
  • https://nodejs.org/en/
  • https://json-schema.org/
  • https://hackerone.com/reports/712065

HANDS-ON LEARNING

So this last section is to provide you with some hands-on learning. Some of the resources above can actually help create your own testing environment to try things out on your machine, so that is certainly an option.

Another very cool option is tryhackme’s room – kiba. This room is free, so all you have to do is create an account and have fun learning. Without spoiling anything else, this rooms obviously walks you through a real world prototype pollution exploit.

CONCLUSION

Thanks for reading and I hope you learned something. Come back for more future articles. See you next time!