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>
None
Stage #1 hint and solution

You'll get an alert and the stage will be cleared!

None
Stage #1 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……

None
Stage #2 hint and solution

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

None

You'll get an alert and the stage will be cleared!

None
Stage #2 cleared!

Stage #3

The input field seems to be properly escaped. However, we are introduced to a new input field here; the dropdown.

None
Stage #3 hint

The previous payload fails because of HTML encoding. Try intercepting the traffic using Burp Suite.

You'll find another input field 'p2'.

None
p2 field

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!

None
Stage #3 cleared!

Stage #4

The hint says there's a hidden input field.

None
Stage #4 hint

We have a target to exploit. Intercept the traffic in Burp Suite.

You'll find another input field 'p3'.

None
p3 field

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!

None
Stage #4 cleared!

Stage #5

The hint says that the input field is now restricted to a certain input length.

None
Stage #5 hint

Open DevTools -> Elements and simply change the 'maxlength' and 'size' values to a big value like 50.

None

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.

None
Stage #5 cleared!

Stage #6

The hint says that this stage has something to do with event handler attributes.

None
Stage #6 hint

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)"
None
Payload

Submitting will get you an alert and the stage will be cleared.

None
Stage #6 cleared!

Stage #7

This stage seems to be similar to the previous one.

None
Stage #7 hint

The previous stage's payload won't work here, since this stage adds an extra " for every double quote entered.

None
First attempt

This payload works for this stage:

" onmousover=alert(document.domain)
None
Stage #7 cleared!

Stage #8

The hint mentions something about JavaScript scheme.

None
Stage #8 cleared!

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!

None
Stage #8 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.

None
Stage #10 hint

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.

None
Stage #10 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 " ".

None
Stage #12 hint

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);
None
Payload

The payload works and gives an alert on mouseover.

None
Stage #12 cleared!

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.

None
Stage #15 hint

I tried a test payload of the usual '<script>alert(document.domain)</script>' and observed that the characters '<', '>' are being HTML encoded.

None

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.

None
Backslashes ('\') removed from payload

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!

None
Stage #15 cleared!

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".

None
Stage #19 hint

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).

None
None
Stage #19 cleared!

And BOOM! Just like that we have cleared all stages of the XSS Challenge (by yamagata21).

None
All stages are cleared!

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!