This is my walkthrough of all the stages of the XSS Challenge (by yamagata21). There are a total of 19 stages in this challenge. The aim of each stage is to inject the JavaScript command: alert(document.domain);
into the input field and trick the server into executing it.
A few stages only seem to work in the older versions of Internet Explorer, and haven't been covered in this writeup.
Link to the challenge:
The link to the next stage is received upon completion of the previous one.
Let's dive right into it!
Stage #1
This is understandably the easiest stage of this game. Simply enter this payload in the input field:
<script>alert(document.domain)</script>
You'll get an alert and the stage will be cleared!
Stage #2
This is where the game actually begins. The hint says that there is an existing tag that needs to be closed first. In order to do this, our payload should begin with something like: "><script……

This is how the input tag is being closed to begin the injected script tag.

You'll get an alert and the stage will be cleared!
Stage #3
The input field seems to be properly escaped. However, we are introduced to a new input field here; the dropdown.
The previous payload fails because of HTML encoding. Try intercepting the traffic using Burp Suite.
You'll find another input field 'p2'.
Enter this payload in place of 'Japan' in p2.
"><script>alert(document.domain)</script>
Forward this request.
You'll get an alert and the stage will be cleared!
Stage #4
The hint says there's a hidden input field.
We have a target to exploit. Intercept the traffic in Burp Suite.
You'll find another input field 'p3'.
Enter the same payload as stage 2 in the 'p3' field.
"><script>alert(document.domain)</script>
Forward the request.
You'll get an alert and the stage will be cleared!
Stage #5
The hint says that the input field is now restricted to a certain input length.
Open DevTools -> Elements and simply change the 'maxlength' and 'size' values to a big value like 50.
Now enter the same payload as stage 2 in the input field.
"><script>alert(document.domain)</script>
Submitting will get you the alert and the stage will be cleared!
This is a client-side validation bypass.
Stage #6
The hint says that this stage has something to do with event handler attributes.
These include 'onmouseover', 'onclick', 'oninput' and many more.
So it is safe to assume that the payload in this stage needs to be designed using an event handler attribute. Something like:
" onmouseover="alert(document.domain)"
Submitting will get you an alert and the stage will be cleared.
Stage #7
This stage seems to be similar to the previous one.
The previous stage's payload won't work here, since this stage adds an extra " for every double quote entered.
This payload works for this stage:
" onmousover=alert(document.domain)
Stage #8
The hint mentions something about JavaScript scheme.
We are expected to 'Make a link' using JavaScript scheme.
The payload will simply look like:
javascript:alert(document.domain)
Submitting this payload will create a link.
Clicking on it will send an alert and the stage will be cleared!
Stage #9
This stage has something to do with UTF-7 which is supported in older versions of Internet Explorer only. The stage can be skipped by simply entering 'alert(document.domain)' in the Console in DevTools.
Stage #10
The hint mentions something which I didn't get.
However I tried the classic <script>alert(document.domain)</script> payload and found out that the word 'domain' (word after the '.') is being removed.
There are a few different approaches to solve this stage.
- The payload here is designed in such a way that the word 'domain' will be regenerated if broken down.
"><script>alert(document.dodomainmain)</script>
- Encode and decode 'document.domain' with Base64.
"><script>(eval(atob('YWxlcnQoZG9jdW1lbnQuZG9tYWluKQ==')))</script>
- Split the 'document.domain' part and concatinate it back.
<script>alert(eval('document.dom'+'ain'))</script>
Submitting any of these payloads will generate an alert and the stage will be cleared.
Stage #11
This stage isn't available.
Stage #12
A lot of articles and walkthroughs suggest that this stage works on Internet Explorer only, so I switched to a device with IE support.
The hint displays a regex "s/[\x00-\x20\<\>\"\']//g;"
which seems to filter out the input and rejects <, > and " ".
The solution to this stage is quite different and involves the use of backticks (`). The regex has no rule to reject backticks and this is what we'll utilise here.
The payload:
``onmouseover=alert(document.domain);
The payload works and gives an alert on mouseover.
Stage #13 — #14
I tried multiple solutions that are publicly available through walkthroughs on Internet Explorer, but none of them seemed to work. This might be an issue regarding the version of Internet Explorer required to solve these stages. I skipped these and moved on to the 15th stage.
Stage #15
The hint suggests that this stage has something to do with the 'document.write()' function.
I tried a test payload of the usual '<script>alert(document.domain)</script>' and observed that the characters '<', '>' are being HTML encoded.
This means we need to encode the characters ourselves to bypass this check. Convert the payload to Hex which will look like this:
\x3cscript\x3ealert(document.domain)\x3c/script\x3e
But the server just removes the backslashes from the input.
Simply add another backslash for every backslash in Hex. The payload should look like:
\\x3cscript\\x3ealert(document.domain)\\x3c/script\\x3e
Submitting it will get you an alert clearing the stage!
Stage #16
This stage isn't available.
Stage #17 — #18
These stages seem to work in older versions of Internet Explorer only and can be skipped.
Stage #19
The hint says "Twitter DomXss at Sep 24, 2010".
Looking at a few articles about this, I found that Twitter had a code snippet like:
//<![CDATA[ (function(g){var a=location.href.split("#!")[1];if(a){g.location=g.HBR=a;}})(window); //]]>
This made it possible to inject Javascript scheme as: http://twitter.com/#!javascript:alert(document.domain);
to get an XSS.
We'll use the same strategy here.
Replace the 'href' in DevTools with javascript:alert(document.domain)
.
And BOOM! Just like that we have cleared all stages of the XSS Challenge (by yamagata21).
This series of challenges is indeed a great way to learn a few tricks to test for XSS and has introduced me to a whole lot of different techniques other than the classic <script>alert(1)</script>. Really enjoyed learning how creative you can get to trick the server into executing unintended scripts!