Smuggling Script via URL: Short HTML-based XSS payload

Let’s learn a neat trick on having the XSS payload in the URL for achieving shorter XSS payloads — straight from the greats!

SecurityGOAT
5 min readAug 10, 2021

Introduction

In the Twitterverse, someone dropped this interesting payload and I took it:

That caught my attention! Ofcourse if you have some neat JS tricks, I am happy to learn those :)

So I read and found something that blew my mind, never thought of this. Never! And that’s good — I learnt something that I didn’t knew before and broadened my knowledge on how to go to the weirdest level and push the boundaries!

So today’s post will be dedicated to this neat trick, which was initially shared by Gareth Heyes (I really enjoy this man’s work! One of the many I respect and admire a lot!)

You should really check this out! Amazing stuff :)

And this is one of those enlightening stuff for me! Too good :)

Image Credits: SecurityGOAT (That’s me ;)

The Trick

Okay enough of suspense building, let’s get real!

So Gareth Heyes shared this post long back in 2012 sharing this neat idea that:

URLs can be valid Javascript!

Neat isn’t it?!

Now you might be wondering what? And how?

Let’s break it down! Let’s take a simple URL:

URL: http://www.thespanner.co.uk/2012/05/08/eval-a-url/

Now you can see we have a label, and a comment if you treat it as Javascript.

A Label? What’s that?!

A labeleled statement or a statement with a label is just a way of having a reference for a line so that we can visit it if we wish to. Mostly useful while doing looping unconventionally!

If you have some experience with writing Assembly, then you must have definitely used labels. The labels in JS are the same*.

* Note: Star because JS has no goto statement, so labels are only used with break & continue keywords.

Feel free to read more on MDN.

Okay so a URL basically is a label and a comment when treated as valid JS!

So what’s the point to have it? Comment means no execution right!

But wait, there’s a way to execute JS. If somehow there was a way to instruct the JS parser to put some URL parts on newline, then they should be parsed correctly right!

Something like this (from Gareth’s post):

http://thespanner.co.uk\nalert(1)
(label) (comment) (newLine) (functionCall)

Again, phrasing Gareth’s words:

Trouble is the new line isn’t allowed inside the browser url bar or is it? ES5 introduced in the standard that line separators and paragraph separators would act as traditional new lines in JavaScript and separate new statements. Thankfully our friend IE allows us to do this directly in the url. Using these characters allows you to create an eval’able url.

So we can use line separators & paragraph separators! But in IE :/

We want something that works in our browsers today :)

So if you go ahead and try the payload Gareth mentioned, it won’t work now…

And that’s where the Tweet I showed comes in! This guy rediscovered this trick and to execute the JS, he passed the URL to unescape function!

So now there’s no need to think of line separators or anything else, a normal newline (0x0A) works as well.

URL:

https://aem1k.com/location/script/#%0Adocument.write%28%60%0A%3Cmeta%20name%3D%22viewport%22%20content%3D%22width%3D560px%22%20/%3E%0A%3Cbody%20style%3D%22max-width%3A500px%3Bfont-family%3Amonospace%22%3E%0A%3Cb%20style%3D%27color%3A%2306F%27%3EThis%20is%20an%20%28almost%21%29%20empty%20document%3C/b%3E%0A%3Cp%3EEverything%20you%20see%20here%20was%20injected%20via%20a%20script%20that%20has%20been%20encoded%20into%20the%20URL%20of%20this%20web%20page.%20The%20HTML%20source%20of%20the%20original%20document%20is%20only%20these%2042%20bytes%3A%0A%3Cp%3E%3Ctt%3E%26lt%3Bscript%3E%3Cb%3Eeval%28unescape%28location%29%29%3B%3C/b%3E%26lt/script%3E%3C/tt%3E%3C/p%3E%0A%3Cp%3EGo%20ahead%20and%20view%20the%20page%20source%20yourself%21%20Also%20the%20network%20panel%20will%20tell%20you%20that%20there%20is%20nothing%20more.%3Cp%3E%0A%3Cp%3ENow%20take%20a%20closer%20look%20at%20the%20URL%20and%20you%20will%20see%20an%20encoded%20newline%20character%20%27%250A%27%20after%20the%20hash%20followed%20by%20the%20encoded%20script.%3C/p%3E%0A%3Cp%3E%3Ca%20href%3D%22https%3A//twitter.com/aemkei/status/1424845917052674050%22%3ERead%20more%20%u2026%3C/a%3E%3C/p%3E%0A%3Cp%3EYou%20are%20welcome%21%20%3Cbr%3E%u2014%20Martin%3C/p%3E%0A%3C/body%3E%0A%60%29%3B%0A

Medium won’t allow me to add this as a URL, so had to dump it :/

Code to evaluate the URL:

eval(unescape(location));

And that would render this cool page:

Note: Whatever your payload is, must be added after the ‘#’ because that is the fragment on the client side and thus it won’t be used to request for some non-existing page right!

Ofcourse you can get creative and create pages with cool stuff :)

Not sure for how long this link stays up, but the code is fairly simple, as I already showed before:

So feel free to set this up locally :)

So the Twitter post author (Martin Kleppe) claimed that:

You only need 42 bytes and a (long) URL to render any web page you like!

https://aem1k.com/location/…#[ENCODED_SCRIPT]

Taking it further

Michał Bentkowski, another amazing researcher I admire and appreciate a lot came up with this:

That’s great since we don’t even need script tag! So it’s a shorter page indeed!

But the caveat is that the page with this payload won’t work in Safari, as noted.

Then another researcher jumped in (TomNomNom), I have known him for short time but he is also a great researcher!

Yet another, even shorter payload! Great progress!! But he mentioned that we need to open this page with window.open, not ideal! But ofcourse that’s not needed, as Gareth mentioned:

Some of you might be thinking that’s cheating! Since I would have to go to this page first to prepare for another page xP

But these are just different ways to shorten your final payload, not asking you to try them out, but just learn from the stuff :)

Bonus Trick

Heindl Jonathan mentioned (in the same thread) a neat and fun idea of abusing URL shortening services like bit.ly can be abused as static page servers!

You just keep this code on your page and then shorten your payload containing URLs and shorten them using bit.ly or the like! And when expanded, your URLs would render your full pages :)

Sweet!

But ofcourse there’s a limitation to that — URL size limit (expect it to be ≤ 2000 characters).

Closing Thoughts

Indeed a tweet with a great set of tricks! I definitely had fun seeing all this, and I hope you did too!!

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 :)

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

--

--