Hands On training | Google XSS Game

Hello everyone,

In a previous post, I talked about XSS aka Cross Site Scripting. Hope you all got a basic knowledge now. In this post, I am giving you more information on XSS with a hands on training on the Google XSS Game. You can find a video on how to solve this at the bottom of the page.

At first, Google XSS Game is a training platform provided by google to practice XSS. It consist of 6 levels and in each level, you have to execute a JavaScript alert in order to advance to next level. In each level, you'll be provided with different problems and you've to execute the alert using different techniques in each level. This will help you to understand various methods than can be used to execute XSS in a web page.

There are hundreds of such websites available which allow you to practice various types of vulnerabilities.

So let's get started.

Navigate to https://xss-game.appspot.com. This is where the Google XSS Game is available.

You'll see a page like this

Click the button Let me at 'em! to enter to the game.

First task : Hello world of XSS

You have to inject the xss payload in the virtual browser.  You can view the source code by clicking the "toggle" link. If you are unable to inject, you can get the hints by clicking the "show" link.

While checking the source code, it is a python script and the 2 interesting parts in the function
 def get(self) are

self.response.headers.add_header("X-XSS-Protection", "0")


query = self.request.get('query', '[empty]')     
message = "Sorry, no results were found for <b>" + query + "</b>."
message += " <a href='?'>Try again</a>."

The first part will turn off the chrome XSS auditor and allow us to inject the XSS payload in the browser.

The second part shows that the value of url param query is directly added to the body. That is where we have to exploit.

This is a simple one and you can try to enter any of the following (and even more are there) in the search box and search it

<a href="javascript:alert()">Link</a>

<img src=X onerror="alert()">


And so on. If you used the first one, you have to click on the Link in order to execute alert.

Great!!! You've successfully completed level 1. Now you'll see a button to advance to next level.

Second task : Persistence is the key

In this task, you have to execute alert by adding a post. In this game, it is DOM XSS, but when test on real chat/ comment applications, it will be a stored XSS.

Ok let's take a look at the source and the previous message as well.

When inspecting the source, you can see the default message uses different types of html tags to style it. That's our key.

Check the source to confirm it. This is how our post is rendered

html += '<b>You</b>';
html += '<span class="date">' + new Date(posts[i].date) + '</span>';
html += "<blockquote>" + posts[i].message + "</blockquote";
html += "</td></tr></table>"
containerEl.innerHTML += html; 

You can see that the post doesn't passes through any filters. So we can use any of the method mentioned above.

<a href="javascript:alert()">Link</a>

<img src=X onerror="alert()">

And so on.

Congrats. You've completed level 2. Now advance to next level.

Task 3 : That sinking feeling

This is quiet different from the 2 which we've completed. Here, we have to learn about window.location.hash. It is the part coming after # symbol and is used for in-page navigation. It is a browser feature and it will work even without JavaScript.

Let's inspect the source code for this one.

The interesting part in the code is

var html = "Image " + parseInt(num) + "<br>";
html += "<img src='/static/level3/cloud" + num + ".jpg' />";

num holds the value of window.location.hash and used in 2 places. At first place, it is used inside the parseInt function hence our payload won't work there. But in the next line, the raw data is used. That's where we are going to inject our payload.

The code is <img src='/static/level3/cloud" + num + ".jpg' /> and we have to inject our payload at the place of num. When rendered, it will become <img src='/static/level3/cloud1.jpg' />

So we have to close a single quot ' there and we need to inject our payload.

You can try any payload inside ' ' After #

Try to put any of the below after # and visit the url.

1' onerror='alert()

1'><img src=X onerror="alert()">'


1'><a href="javascript:alert()">Link</a>'

And so on.

Great. Now we can advance to next level.

Task 4 : Context Matters

We have a space to enter the duration of timer. That's where we're going to exploit.

Let's check the source code.

In timer.html, we can see this line

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

We have to exploit in the expression {{ timer }} But it is placed inside a function startTimer(''); which is an event handler to onload event. The main point to note is that the event handler attribute in HTML accept multiple callback functions.

So we need to close the function and execute our alert there. Do note that, the value didn't passed through a parseInt function instead the raw data is used. So we can close the function by adding a '); and then inject our alert. Since it is used as inline, we can't inject alert(); there because it will break things. The statement will become onload="startTimer('3'); alert();')" and it won't work.

So we have to add a pattern that keep the pattern unbroken.
Add alert(' and it is enough.

So our payload will be


Clicking on start timer button will execute the alert and we've finished this level.

Advance to next task.

Task 5 : Breaking Protocol

In the home page, we don't have a way to inject anything. All we have is a link. So let's click it.

Here, we can see 2 places to inject our payload. one on the url itself and another one on the input box. The input box is a place to enter email and hope it won't get reflected somewhere else. So let's go to the first one. On the url.

Inspect the source code of current pag, that is signup.html and we can see the line

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

Great place to inject a payload. Our payload will be set as the value of href attribute in an a tag. If we are able to add javascript:alert() we can execute our payload. Now let's see what is the value of next. We can't find any in the page. Where do we look for it???

Python code to the rescue. Check level.py and we will see

if "signup" in self.request.path:
   {'next': self.request.get('next')})

So the value of next in the url will be used.

Change the value of next in the url from confirm to javascript:alert() and the final url will look like


Now clicking on Next >> in the page will trigger our payload.

We now completed level 5. And 1 level remains.

Task 6 : Follow the 🐇

There is a path to a js file in the url.

Let's inspect the source code. In page index.html, you can see a function includeGadget and inside the function body, you can see the following code.

var scriptEl = document.createElement('script');

// This will totally prevent us from loading evil URLs!
if (url.match(/^https?:\/\//)) {
"Sorry, cannot load a URL containing \"http\".");
// Load this awesome gadget
scriptEl.src = url;

So we can load external js file but not from a http or https url.

Here, let's try the data urls.

Data urls are in the form data:{type},content

So change the value after # to


or to

data:text/plain,alert() and we can execute the alert.

Congrats!!! Now you've successfully completed all tasks in Google XSS Game.

Now Start Hacking!!!

Here's the video in case if anyone having any doubt.

Like this post or have queries? Contact me or Support me

Liked the post? Buy me a coffeeBuy me a coffee


Popular posts from this blog

Download Guarded Profile Picture From Facebook

Introduction to XSS - Methods, Impact and Prevention