Intigriti XSS Challenge 0522
Introduction⌗
This was an XSS challenge hosted by Intigriti whose original creator was @PiyushThePal. You can find it here.
Source Code review⌗
The first thing I do while checking for XSS is just press CTRL+U
on the page and quickly skim through the interesting-looking JS files to find something that might stand out, like the use of innerHTML
or using dangerous functions like eval
etc. In the view source page, I found a js file that was being referenced from a githack page (somehow, now they have changed the view source page and now they have explicitly added the code that was in that file earlier, I was lucky to have tried to solve the challenge before this was edited). So, I searched for query-plugin-query-object
which was the file name of this file and I found a repository that had the exact same code (almost). I figured out that they have made the challenge around this code and omitted some code to create a vulnerable code. So, I diff the 2 files:
132,137c132,135
< if(!key.includes("__proto__")){
< var value = !is(val) ? null : val;
< var parsed = parse(key), base = parsed[0], tokens = parsed[1];
< var target = this.keys[base];
< this.keys[base] = set(target, tokens.slice(0), value);
< }
---
> var value = !is(val) ? null : val;
> var parsed = parse(key), base = parsed[0], tokens = parsed[1];
> var target = this.keys[base];
> this.keys[base] = set(target, tokens.slice(0), value);
Clearly, as you can see they have omitted the __proto__
check from the original code. This means this has to be prototype pollution leading to XSS. Now, I am not good at Prototype pollution (or at anything for that matter, lol). So, I started looking for some resources on the internet to get some knowledge about Prototype pollution until I found a youtube video by Intigriti’s PinkDraconian on a previous XSS challenge that too required exploiting prototype pollution leading to XSS. You can find that here. After watching this video, I found a goldmine for prototype pollution. This is a repository by BlackFan that has a lot of prototype pollution scenarios and payloads for them 🤯. And, fortunately, it has what we need too.
Finding the payload⌗
While having a look at the source code, I found where our input, that is page
param, is being stored.
var pl = $.query.get('page');
if(pages[pl] != undefined){
console.log(pages);
document.getElementById("root").innerHTML = pages['4']+filterXSS(pages[pl]);
}else{
document.location.search = "?page=1"
}
I thought this $.query.get('page')
is vulnerable to prototype pollution and there were some scenarios similar to this in that repository too, so I started applying those payloads but nothing was working. After some time, I realised some characters cause an error like %
.
e.g.: ?page=meispi%
I tried to look for these errors but found nothing interesting and got bored. After some time, I looked at the repo again and found a scenario that was based on the use of js-xss
and our code too made the use of this library. Notice the filterXSS
function, that is the vulnerable part.
So, reading the repo, I figured out that our payload needs to be something like: ?__proto__[whiteList][img][0]=onerror&__proto__[whiteList][img][1]=src
Before adding the whiteList
variable:
After adding the whiteList
variable:
Ok, now how do we reach the if part to load our payload through innerHTML
. Somehow, we need to enter our payload in pages[pl]
. But pages
is already defined and I tried to overwrite it through the URL using __proto__
but it was again overwritten by the content when I reload the page. I tried to analyze the key-value pairs of the pages
dictionary, but I could find nothing.
Inspect element to the rescue!
Remember our incomplete payload, I just put that in the url and opened inspect element to see what has changed, ?__proto__[whiteList][img][0]=onerror&__proto__[whiteList][img][1]=src&page=1
Ah!!! Our payload becomes a property of the pages
object, so we simply need to add another property to the pages
object and call that using page
param.
Final payload: ?__proto__[whiteList][img][0]=onerror&__proto__[whiteList][img][1]=src&__proto__[x]=<img%20src%3dx%20onerror%3dalert(document.domain)>&page=x
Works on both chrome and firefox!