Neat XSS trick from a G.O.A.T — Gareth Heyes special

Let’s discuss about this interesting XSS challenge, that was shared yesterday by Gareth Heyes, a GOAT that I admire and learn from!

SecurityGOAT
6 min readAug 12, 2021
Image Credits: SecurityGOAT (That’s me folks!)

XSS is something that has become second nature to me! I am in love with this vulnerability so much that every other day some new payload catches my attention! The result? It’s the interesting posts that you end up seeing like this one :)

Today’s post would be about the interesting XSS challenge that Gareth Heyes shared on Twitter:

Ofcourse, when I see something like this, especially from the GOATs that I admire, I have to try such challenges and see if I can do them or it. And if I fail, I end up learning something new. And if I succeed, it just happens because I had tried hard for it, which is again a success for me. So in any case, it always brings me immense joy and pleasure to get exposed to such stuff, as this helps me improve my craft!

The Challenge

So what’s so interesting about this challenge? Yet another XSS challenge? Pop-up alert and call it a day? Hmm.. not quite! Look closely to see what are the possible sinks that you would want to reach in order to get XSS!

In this challenge there’s a sink — innerHTML!

There’s just one problem — obj type is checked and if it’s undefined, only then we set the specified property’s innerHTML to the XSS payload.

So which (obj, property) combination would get the job done?

Ofcourse this seems quite unintuitive at first because if an object is undefined, how can I even go ahead and set its properties in the first place. So weird! But since Gareth shared it, there must be something in there… So let’s believe that indeed there’s some way to bypass this check and reach the XSS sink!

Hunting for the solution

Now the goal is to bypass the check by having some object that is undefined but still can have properties on it.

So for that I went on and checked the typeof operator page to see when it returns ‘undefined’, possibly to get some hint on if there are any caveats with that!

I thought that table would indicate me some interesting behaviour but nah… it didn’t gave any such value. Only undefined type seems to return “undefined” as the result!

So instead of check any further, I had 2 thoughts!

  • Can I create any custom object and maybe overwrite their property which reflects their type?
  • Can I somehow modify the behaviour of typeof operator?

Turns out that I couldn’t do either of those!

Atleast that what these answers indicated:

Me trying to play around and see if I can somehow change the type reported by typeof operator!
https://stackoverflow.com/questions/17333761/changing-the-behaviour-of-the-typeof-operator-in-javascript

So it seemed quite impossible there… But I knew there has to be a trick!

And I was determined to find it!! So I went back to the MDN page for typeof operator and started to check the examples.

Soon enough everything fell into place and I found what I have been looking for!!

There is a non-standard host object that all browsers currently expose: document.all

And it’s type is… “undefined”!

It is a violation of the ECMA Javascript standard due to this object having a custom type set to a predefined one, rather than something different from predefined types, as the spec says…

But what does this object has?

Let’s check in browser console (press Ctrl+Shift+I):

So it contains all the HTML tags in the page in form of an array, including the html, head, and the others…

You can read more on Document interface’s read-only all property here:

Great! Now we know how to get “undefined” type for an object. And remember the challenge prop? It had a div as well with id “x”.

So we can access this div by it’s id from the document.all and when passed to the solve function, this would result in the div having the img tag inserted via the innerHTML sink!

And (boom!) that leads to XSS!

And we win!

So that would be the supposed happy ending of this challenge ;)

Bonus Section — Digging deeper

The challenge was infact quite easy — relied on a neat trick that you had to know or had to acquire by reading the documentation (or the spec).

If you check the Conversion to boolean section of the documentation for document.all:

https://developer.mozilla.org/en-US/docs/Web/API/Document/all#conversion_to_boolean

You would notice that this object infact is a falsy object (which is a fancy way of saying that when converted to boolean, it results in false as the response).

There is also some weird stuff there that this object has the [[IsHTMLDDA]] internal slot.

Michal Bentkwoski, another GOAT that I follow, also shared the link of the relevant ECMAScript specification section, containing this information:

In short, it just says that any object that has the [[IsHTMLDDA]] internal slot, would return undefined when using the typeof operator against it!

Point made clear now? I guess I need to throw some hard stuff before you all agree with me xP

But anyways, this must have been more exact reason for the curious ones :)

Word of advice

I hope that this post was quite informative and helped to learn about the importance of reading the documentation & the spec.

I have myself learnt this over time that how important the document and specification is, if you wish to learn something deeply! And that’s what I aim for, so that I can become a GOAT as well!

I also showed you my process of approaching things! It’s always important to ask questions and then the answers unveil themselves :)

And more importantly, there has to be a structure on how to attack things — like military folks do — a tactical approach! If you play with structure, it will take you way ahead of those who don’t.

Closing Thoughts

I think this was quite neat trick which would definitely be helpful in some sandbox bypass scenario. I have added it to my pentester arsenal, and so should you!

So with that, I would close this post. I hope this post was informational and fun to read. In case you enjoyed it, please share it among your friends in the infosec community :)

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

You can also send any topic you wish to learn more about. Send me DM on Twitter or let me know in the comments :)

Lastly, the line which should mostly be a plain ol’ boring one which I have to copy from my previous post every single time!!!! — 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 :)

And also, get ready for more fun posts! I have more fun ideas lately and planning to expand more, with more technical content for your brain muscles!

So help me spread these posts around to help make infosec more approachable for the beginners and more fun for the GOATS ;)

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

--

--