Demystifying an XSS payload!

Just found an weird and cool trick by Gareth Heyes, so thought to reverse engineer it and find out the root cause :)

SecurityGOAT
4 min readJul 29, 2021

Introduction

In case you haven’t heard of Gareth, he is an amazing researcher from PortSwigger! He has been the part of an amazing hacker community (“Slackers”), where all the great people like Dr. Mario, and others have been hanging around and discussing about the interesting research!

Enough for the intro, let’s see what Gareth came up with now and see what it is under the hood.

Backstory

So I just finished writing 1 post for the day and then saw a tweet by Gareth:

He found some interesting thing. And that got my attention! So I set out to find out what this trick did under the hood — I mean its fascinating to me that just by adding a function reference to an array gave it special super powers to call the __proto__ method.

How? Let’s find out!

Poking Around

So I wanted to try this payload first and see if it worked and also find out how it worked! And therefore I opened the browser console and tried this trick that Gareth mentioned. And it worked (it had to, ofcourse!)

So now I started poking around with this and see if I can make some sense out of it!

So first off, let’s keep it simple and see how we can pop alert using the __proto__ property:

__proto__.constructor.constructor(“alert(1)”)()

The __proto__.constructor.constructor results in the Function constructor which allows you to generate a function from a string and therefore execute arbitrary code, like we did for the alert in this case!

Now let’s see Gareth’s payloads:

Payload #1 which supposedly fails:

__lookupGetter__(‘__proto__’)

and

Payload #2 which successfully leads to an alert:

[__lookupGetter__][0](‘__proto__’).constructor(‘alert(1)’)()

So my first thought was what is this array doing. Did it changed the __lookupGetter__ method?

So I tried to check if the __proto__ property and the function:

Indeed they were different! I initially thought I found the difference, but that didn’t gave me the reason...

So I tried a bit more — trying to print the prototype chain to see for any differences and check the available functions etc.

All that lead to a dead-end! And then I checked the tweet back again and found that @TomNomNom just did a simple console.log to see what the difference was:

Did you see?! this got bound to the Array!

And that array contains the reference to the function fun()!

So, in the payload Gareth posted, the trick was — this pointed to Window object initially now points to the array object containing the reference to the window and all its methods and that’s what got the whole thing working!

@TomNomNom pointed out that this things was same as:

Which is brilliant right! Same technique as we saw with the Array — this got changed from Window to the object we just declared and thus all the window object properties are inside this new object that this points to!

Gareth then pointed to amazing payloads:

({f: valueOf}).f()

this.valueOf() shows the value of the current object:

And

({f: toString}).f()

Since this got changed, notice the output difference!

Closing Thoughts

It was great learning about this new trick and how Javascript works! Thanks to Gareth Heyes for sharing amazing XSS vectors.

I hope you learnt something interesting from this post :)

Let me know your feedback in the comments below and feel free to connect on twitter: @_SecurityGOAT

Lastly, if you have been enjoying my work and would love to support me, consider checking my Patreon page or you can even Buy Me a Coffee :)

See ya!
Until next time, keep learning and happy hacking.

--

--