Pedro Henrique Cardoso
Jul 19 · 6 min read

Google has a funny beginner like XSS game, and although it was quite easy I learned a thing or two.

So this article is for those who are stuck in the game or someone who wants to just understand why the levels’ payloads works.


Just an advice: If you are just stuck i recommend you to take a walk, drink some coffee, and try later with a fresher mind. Going straight to the solution very often do not teach you too much as when you do by yourself.

Well, let’s go:


Level 1: Hello, world of XSS

Solution: Well this level is just an introductory challenge just to show how a XSS works, of course its a “very basic and non realistic” example. Anything we type get embedded into the page. Hence, just inject a script tag with an alert code.

Level 1 Payload:

<script>alert()</script

Why does it work: The code is just adding the user input into the webpage with no sanitizing, so it is understood by the browser as part of the page code and executed.


Level 2: Persistence is key

Solution: Like the previous level, this page’s vulnerability is to include HTML straight into the page. But, this time there is a validation which prevent us from using the script tag. To bypass it we can insert a image tag with an invalid URL and a onerror attribute which will execute a javascript alert.

Level 2 Payload:

<img src='x' onerror='alert()'>

Why does it work: The page will try to load the image from the source ‘x’ which will fail miserably and then trigger the onerror attribute’s code.


Level 3: That sinking Feeling…

Solution: The application chooses the image tab based on first URL fragment, (the hash after the URL). Passing a malicious fragment that will get inserted into the page will trigger the alert.

Level 3 Payload:

1' onerror='alert();//

Why does it work: The page’s source code shows that it gets the URL fragment and passes to a choosetab function.

window.onload = function() {chooseTab(unescape(self.location.hash.substr(1)) || "1");}

This function adds then fragment text to the image tag source, and load the new tag into the page.

function chooseTab(num) {// Dynamically load the appropriate image.var html = "Image " + parseInt(num) + "<br>";html += "<img src='/static/level3/cloud" + num + ".jpg' />";$('#tabContent').html(html);...

We can fool this by closing the src attribute with a single quote, and then add an onerror attribute with an alert function like in the previous level, and commenting the ‘.jpg’ part with double slashes.

It will create the following img tag, that works fine.

<img src='/static/level3/cloud1' onerror='alert();//.jpg' />

Level 4: Context matters

Solution: The index page shows a form which we can pass a number, that is passed to the timer page which function is just to count the number we passed in seconds and then redirect us back to the beginning. We can fool its timer function to execute arbitrary code, since it is straightly added to the page.

Level 4 Payload:

3'**alert());//

Why does it work: The value we passed by the index page is straightly added into the function parameter at the timer.

<img src="/static/loading.gif" onload="startTimer('{{ timer }}');" />

So we can manipulate the javascript executed here. If we pass the following parameter:

3'**alert());//

The javascript will try to evaluate 3**alert() before it calls the startTimer function. Furthermore, to evaluate the result of 3**alert() it needs to get the value returned by the function alert(), which will make the browser execute the alert function.


Level 5: Breaking protocol

Solution 1

Solution: Actually the welcome page does nothing, just lead us to the sign up page, where the magic happens. At the sign up page we can enter an e-mail address (or anything, its not evaluated after all), and hit the link next that will lead us to the page passed by the next parameter (e. g. ?next=confirm). We can fool this parameter by injecting javascript code into it, executing the alert function.

Level 5 Payload:

https://xss-game.appspot.com/level5/frame/signup?next=javascript:alert()

Why does it work: The page code just input the parameter next’s value into the href attribute of the next link.

<a href="{{ next }}">Next >></a>

So we can inject javascript code in the attribute, that will be understood by the browser as a bookmarklet.

javascript:alert()

Solution 2

Solution: After hitting the next link, you will go to the confirm page, that will redirect you to the beginning in a given time. But looking at the confirm’s source code, we see that it also accepts the next parameter, which is used to redirect you to its given value. We can then, again, mess with this.

Level 5 Payload (need to wait the time runs out):

https://xss-game.appspot.com/level5/frame/confirm?next=javascript:alert()

Why does it work: The confirm page also accepts the next parameter and uses it to redirect the user to its given value.

<script>setTimeout(function() { window.location = '{{ next }}'; }, 5000);</script>

After the time runs out, we will be redirected to the link:

javascript:alert()

That will be understood by the browser as a bookmarklet, executing the code.


Level 6: Follow the 🐇

Solution: The page adds a script tag with the src attribute pointing to the first URL fragment’s value. But, before doing so, it evaluates if the fragment begins with the ‘http’ or ‘https’ words, to prevent us from loading external files. But we can bypass this validation by omitting the ‘http’ protocol. For this solution I am using the default file provided by google in the challenge (replacing ‘foo’ for ‘alert’).

Level 6 Payload:

//www.google.com/jsapi?callback=alert

Why does it work: When you omit the protocol in the URL it will inherit the protocol from the current environment (the page). In this case it will inherit the protocol ‘https’. More about it here (briefly) and here (complete).


Congratulations

So we have completed the challenge. Just a last tip: the main skill to exploit the whole application was being able to look for sources and sinks, so if you are not familiarized with this concept, take a look at this awesome video.

How Irated

How did you like the game overall? A: I loved it!

How about the difficulty? A: Too easy.

Hope you enjoyed the write-up! If you liked, send me some claps 👏, tell me where have you been stuck, if you solved it in a different way or how you rated this challenge in the comments.

See ya! 😁

BugDecoder

Hacking blog

Pedro Henrique Cardoso

Written by

Senior BI analyst and cybersecurity enthusiast. Loves Python and work as a bug hunter in the “backend”.

BugDecoder

Hacking blog

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade