Google XSS-Game Walkthrough

XSS-Game is a game that teaches you the basics of XSS vulnerability and how to detect it, so let’s start by access the site From here.

The first level is very simple if you had the general idea about XSS.

XSS-Game | level 1

We have a website with input box, where we put text and it will search for it, so let’s try to search for something.

XSS-Game | level 1 large

As you can see, the website returned the string that we have searched for, so let’s check if the website does any validation for the input.

all we have to do is to add a simple script that shows a popup and this is more than enough to prove that XSS vulnerability is in the site.

to do that we can simply append our first search with the following code that allows the browser to display a popup with the message “hi”.

something <script> alert("hi")</script>

and voila! , we got our first XSS solution

XSS-Game | level 1 success

Let’s go to the next level, it’s a char forum where you can post a message, so let’s try the same previous code first

XSS-Game | level 2

but nothing shows except the text

XSS-Game | level 2 Test

so let’s open the inspect element tools in your browser and hover over the message.

You can see that the script tag is there but it doesn’t run

XSS-Game | level 2 code

let’s toggle the code and see which code is being executed from the moment we submit the text, if you use inspect element tools, you can see that when you submit the form, the following code will be executed

function() {
  var message = document.getElementById('post-content').value;
  DB.save(message, function() {
    displayPosts()
  });
  document.getElementById('post-content').value = "";
  return false;
}

so the code will get the text we have inserted, it will send it to backend to save the data, then it will execute function “displayPosts()”, let’s check that function code.( you can get the code by clicking on “Toggle code and check index.html code)

 function displayPosts() {
        var containerEl = document.getElementById("post-container");
        containerEl.innerHTML = "";
 
        var posts = DB.getPosts();
        for (var i=0; i<posts.length; i++) {
          var html = '<table class="message"> <tr> <td valign=top> '
            + '<img src="/static/level2_icon.png"> </td> <td valign=top '
            + ' class="message-container"> <div class="shim"></div>';
 
          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; 
        }
      }

First, we will get the HTML element that has ID of “post-container”

var containerEl = document.getElementById("post-container");

Then we will reset the inner HTML which means removing everything inside that element.

containerEl.innerHTML = "";

After that, we will get all the posts saved in the Database in the backend

var posts = DB.getPosts();

and now, we will go into for loop which allows us to traverse all the posts the script received from the backend.

for (var i=0; i<posts.length; i++)

then the script will structure the html to be displayed, this is where it starts displaying each and single card and then it append it to the post before.

But there’s one thing that is important, it uses the following command to append the html code.

 containerEl.innerHTML += html; 

why is it important you might ask, well it’s simple because innerHTML doesn’t allow <script> tags to run when it’s added to document. you can check for more information from here and here.

So what other way to execute a javascript, especially an alert() function. A simple but effective method is using the onxxx functions such as onload, onclick, onsubmit etc.

But, you need an element that support the above methods, also you can find more information from here.

so let’s try to do that, create html tag with onload event that will execute the alert() function to display a message.

But, which elements supports onload event, a simple google search will give you many results, we only need one, some of the tags are:

<body>, <frame>, <frameset>, <iframe>, <img>, <link>, <script>

so let’s use the img tag

<img src="anyimagelink" onload="alert('hi')"/> 
XSS-Game | level 2 Success

and now we can advance to the next level.

In this level, we can see multiple tabs where you can switch between them.

XSS-Game | level 3

let’s open the javascript and analyze it, mainly we will focus on this part only

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);
 
        window.location.hash = num;

also , you can see that when the tab is clicked will trigger the above

<div class="tab active" id="tab1" onclick="chooseTab('1')">Image 1</div>

and then the image will be displayed as the following

<img src="/static/level3/cloud1.jpg">

at the same time, you can see that the javascript is setting the url to the number was clicked

https://xss-game.appspot.com/level3/frame#1

so let’s try first to change the value after the # for example, let’s try the following:

https://xss-game.appspot.com/level3/frame#2

we can see the image is changing to the one in the second tab, without the need to click on the tab.

So, what we’re looking for is to escape the <img> tag and execute on load event to success in our xss.

since onload event requires the <img> tag to have a proper and valid source, we will use the image “1.jpg”

so, what we want to do is to specify the image, close the src=”” and then execute the onload, so we should do something like.

https://xss-game.appspot.com/level3/frame#1.jpg' onload="alert('hi')"

and voila, it worked perfectly.

XSS-Game | level 3 Success

now let’s go to level 4, it has an input of timer

XSS-Game | level 4

where if you click on “create timer”, it will send it to new page and shows an alert after 3 seconds (the default)

XSS-Game | level 4 Test

also you can see the URL is structured like this

https://xss-game.appspot.com/level4/frame?timer=3

now let’s set the timer to large number so we can have enough time to see the code, if you use inspect element, you can see the following code:

XSS-Game | level 4 Timer

so the timer is inserted inside the onload in the html, this gives us huge advantage, cause we can close the “startTimer” function and write our own, for example if we use the following:

https://xss-game.appspot.com/level4/frame?timer=')

you can see the function is closed

ok, so let’s try to end function (by using the 😉 and write our alert function

https://xss-game.appspot.com/level4/frame?timer=');alert('hi

but nothing changed, you can see the input is filtered after “;”, one way to escape that is by using URL encoding so if search online on what is the URL encoding of “;” you will get “%3B”, let’s try it

https://xss-game.appspot.com/level4/frame?timer=')%3Balert('hi

and congrats, we got the right solution, now you might ask why we left the “alert(‘” as half open, well because we closed the “setTimer” function but the closing brackets are still in the HTML as you can see above, so if you closed it like this

https://xss-game.appspot.com/level4/frame?timer=')%3Balert('hi')

you will get the following in HTML which will break the code and won’t run

<img src="/static/loading.gif" onload="startTimer('');alert('hi')');">
XSS-Game | level 4 success

Let’s advance to the next level, this level is fairly simple if you know this trick.

you can execute a java script code within HREF of <a> if you write “javascript:” in the beginning of the URL, so let’s see what we mean by the above.

The Challenge starts with a home page where you can signup, so if you click on “signup”

XSS-Game | level 5

you would the following page where you will have to input your email to sign up

XSS-Game | level 5 Test

The thing that we need to pay attention to is in the URL of the page.

https://xss-game.appspot.com/level5/frame/signup?next=confirm

so we have a value being sent to the page as “next”, let’s check the source code of the page.

XSS-Game | level 5 Code

we can see that the “next” HREF is the value we pass to “next”, so let’s do the trick we learned before

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

Now the solution works, if the user click on the “next”, and now let’s head to the last one.

XSS-Game | level 5 Success

This level includes another small trick that you should know about “src”, according to MDN documents , you can use “data:” to load a small file inline instead of saving the file somewhere else and call it.

Now, let’s check the the challenge

XSS-Game | level 6

In this challenge, the code will take a URL and load it in <script> tag ( you can check the code), so by knowing this along with the previous hint, we know that we can load direct data in the src of the <script>, but how can we do that.

well, we need to follow the following structured specified in the documents above

data:[<mediatype>][;base64],<data>

so, we need a media type ( you can check all media types from here)

we don’t need base64 as we don’t need to encode it, knowing all that, let’s write it

data:text/plain,alert("hi")

So, if we use the above in the URL as

https://xss-game.appspot.com/level6/frame#data:text/plain,alert("hi")
XSS-Game | level 6 Success

and congratulations, you have finished this challenge successfully.