XSS Game walkthrough
https://xss-game.appspot.com/ -> game delveloped to learn XSS vulnerabilities
The Hacker's Guide to the Google XSS Game
Welcome, security apprentice! This guide is your field manual for conquering the Google XSS Game. We won't just give you the answers; we'll teach you the mindset. For each level, we'll follow a three-phase attack plan:
Reconnaissance: Observe the target's behavior and form a hypothesis.
Infiltration: Test the hypothesis with harmless probes to confirm the vulnerability.
Exploitation: Craft the final payload to achieve the objective.
Let's begin.
Level 1: The First Breach
Mission Brief: Inject a script that triggers a JavaScript alert()
.
Phase 1: Reconnaissance
First, we analyze the application. It's a simple search page.
Action: Enter a basic string like
test query
into the search field and submit.Observation: The page reloads and displays our input directly: "Your search for 'test query' returned...". The URL also contains our input:
.../level1/frame?query=test+query
.Hypothesis: The application is taking the
query
parameter from the URL and inserting it directly into the page's HTML without cleaning it. If true, any HTML we inject should be rendered by the browser.
Phase 2: Infiltration
Let's test if the application will render basic HTML tags. This is safer than starting with a script.
Probe: Use a non-malicious HTML tag. Let's try
<h2>Probe Successful</h2>
.Result: The text "Probe Successful" appears as a large heading on the page. Our hypothesis is confirmed! The application is vulnerable to HTML Injection.
Deeper Dive: View the Source Right-click on your injected heading and choose "Inspect Element". You'll see your
<h2>
tag sitting right in the HTML document, which is definitive proof. The application isn't treating your input as text; it's treating it as code.
Phase 3: Exploitation
Since we can inject HTML, we can inject a <script>
tag, the most direct way to execute JavaScript.
Payload Logic: A simple
<script>
tag containing thealert()
function.Final Payload:
<script>alert('XSS')</script>
Execution: Submitting this payload causes the browser to execute the script as it renders the page, popping the alert box. Mission complete.
This is a classic Reflected XSS attack. The payload travels from your browser to the server and is then "reflected" back and executed. The core vulnerability is a lack of output encoding. The server should have converted characters like
<
and>
into their safe equivalents (<
and>
) before displaying them.
Level 2: The Persistent Threat
Mission Brief: Inject a script that is stored on the server and executes for anyone visiting the page.
Phase 1: Reconnaissance
This application is a simple status-sharing board.
Action: Post a normal message like
Hello world
.Observation: The message appears in the list. When you reload the page, the message is still there. This is the crucial clue: the data is being stored (persisted) by the server.
Hypothesis: The application stores and displays user input. If it's not sanitizing this input before storing or before displaying it, we can inject a script that will execute for every visitor.
Phase 2: Infiltration
First, let's see if HTML injection is possible.
Probe: Submit the text
<b>This is a test</b>
.Result: The message appears in bold. HTML Injection is confirmed.
Now, let's try the payload from Level 1: <script>alert('XSS')</script>
.
Result 2: This fails. The text
<script>alert('XSS')</script>
is displayed, but no alert appears.Analysis: The developers have implemented a filter. They are likely using a "blacklist" that specifically removes or blocks the
<script>
tag. This is a weak defense.
Phase 3: Exploitation
We need a way to execute JavaScript without using <script>
tags. HTML event handlers are the perfect tool. The onerror
event on an image tag is a classic choice.
Payload Logic: We'll create an
<img>
tag with an invalid source. When the browser fails to load the broken image, it will trigger our code in theonerror
event handler.Final Payload:
<img src="x" onerror="alert('XSS')">
Execution: When you post this, the browser immediately tries to render the image, fails, and executes your
onerror
script, triggering the alert.
This is a Stored XSS attack, which is more dangerous than Reflected XSS because the payload is saved and automatically served to other users. The vulnerability is two-fold: storing unsanitized data and relying on an incomplete blacklist that fails to account for the many ways to execute scripts.
Level 3: Bypassing the Filter
Mission Brief: Inject a script in a context where you don't control the full HTML tag.
Phase 1: Reconnaissance
We have an image gallery. Clicking tabs changes the image.
Action: Click the different image tabs (1, 2, 3).
Observation: The URL's fragment (the part after
#
) changes:#1
,#2
, etc. The page doesn't fully reload, meaning client-side JavaScript is reading this fragment to decide which image to show.Hypothesis: A script is taking the value from the URL fragment and using it to construct the
src
attribute of the<img>
tag. The code might look like:img.src = '.../cloud' + fragmentValue + '.jpg';
. If so, we can manipulate the<img>
tag from within thesrc
attribute.
Phase 2: Infiltration
Let's see if we can break the syntax of the src
attribute. A single quote should do the trick.
Probe: Manually change the URL fragment to
#1'
.Result: The image breaks! This strongly indicates we successfully broke out of the string literal for the
src
attribute. The HTML was likely meant to be<img src='...cloud1.jpg'>
, but our probe turned it into<img src='...cloud1'.jpg'>
, which is invalid.
Phase 3: Exploitation
We have successfully closed the src
attribute. Now we can add our own attribute. Since the broken src
will cause an error, the onerror
event handler is our weapon of choice.
Payload Logic:
Start with
'
to close thesrc
attribute.Add a space and then our
onerror
attribute:onerror='alert("XSS")'
.
Final Payload:
' onerror='alert("XSS")'
Execution: Append this to the URL fragment:
.../level3/frame#1' onerror='alert("XSS")'
. When the page processes this fragment, it creates a broken image tag that executes our alert.
This is DOM-based XSS. The vulnerability lies entirely in the client-side code. A script is unsafely taking data from a source (
location.hash
) and writing it to a sink (an element'ssrc
property), allowing us to manipulate the page's structure (the DOM) and execute our code.
Level 4: The JavaScript Context
Mission Brief: Escape a JavaScript string to execute code.
Phase 1: Reconnaissance
This is a timer application. We provide a number, and a countdown begins.
Action: Enter
3
and create the timer.Observation: After 3 seconds, a message appears. This is clearly handled by JavaScript, likely with a function like
setTimeout()
.Hypothesis: Our input is being embedded inside a JavaScript string that will be executed later.
Phase 2: Infiltration
We need to see the code.
Probe: "View Page Source" or "Inspect". You'll find this gem:
setTimeout("startTimer('" + timer + "')", 3000);
.Analysis: This is a huge vulnerability. Our input is being placed directly inside a string that will be executed as code. Let's try to break the syntax by inputting a single quote:
3'
.Result: The timer fails, and the Developer Console (F12) shows a
SyntaxError
. We have confirmed control.
Phase 3: Exploitation
We are inside this code string: startTimer('OUR_INPUT')
.
Payload Logic:
Use
')
to properly close thestartTimer()
function call.Use
;
to end that JavaScript statement.Write our own code:
alert('XSS')
.Use
//
to comment out the remaining quote and prevent errors.
Final Payload:
');alert('XSS');//
Execution: This payload transforms the executed code into
startTimer('');alert('XSS');//')
. After the delay, the browser runs both valid commands, and our alert fires.
Another DOM-based XSS, this vulnerability occurs when user input is passed into an "execution sink" (
setTimeout
,eval
, etc.) without being properly sanitized. We escaped the string context to gain control of the execution context.
Level 5: Corrupted Link
Mission Brief: Manipulate a URL parameter to turn a link into an attack.
Phase 1: Reconnaissance
This is a two-page flow. The first page has a "Sign up" link.
Action: Click "Sign up".
Observation: The second page has a "Next >>" link, and the URL contains
?next=confirm
.Hypothesis: The
href
attribute of the "Next >>" link is being populated by thenext
URL parameter.
Phase 2: Infiltration
Let's test if we can control the link's destination.
Probe: In the address bar, change
?next=confirm
to?next=https://google.com
.Result: The page reloads. Hovering over the "Next >>" link now shows it points to Google. Our hypothesis is confirmed.
Phase 3: Exploitation
Links can do more than navigate. The javascript:
pseudo-protocol allows a link's href
to execute JavaScript directly.
Payload Logic: We will replace the URL parameter's value with a
javascript:
URI.Final Payload:
javascript:alert('XSS')
Execution: Change the URL to
.../signup?next=javascript:alert('XSS')
. Load the page, then click the newly weaponized "Next >>" link. The script will execute.
This is Reflected XSS. The server takes input from the URL and reflects it into a sensitive location (an
href
attribute). The vulnerability is a lack of validation; the server should have checked if thenext
parameter was a valid and safe URL (e.g., it starts withhttp
or is a relative path) before using it.
Level 6: The Trojan Script
Mission Brief: Trick the page into running a script from an external, attacker-controlled source.
Phase 1: Reconnaissance
The page is blank, but the URL is very revealing.
Action: Look at the address bar.
Observation: The URL's fragment is a full URL to a
.js
file:...#https://xss-game.appspot.com/static/gadget.js
.Hypothesis: There is a script on the page that reads the URL from the fragment and dynamically loads it as a new script. This is extremely dangerous.
Phase 2: Infiltration
We need to confirm the page will try to load a script from a URL we provide.
Probe: Change the fragment to
#https://example.com/fake.js
.Result: Open the Developer Console's "Network" tab. You will see a failed request to
fake.js
. The browser tried to load it. Confirmation is absolute.
Phase 3: Exploitation
We need to point the application to a script that contains alert('XSS')
. While you could host a file somewhere, a more elegant solution is the data:
URI, which lets you embed the file's content directly in the URL.
Payload Logic: A
data:
URI for JavaScript containing our alert code.Final Payload:
data:text/javascript,alert('XSS')
Execution: Replace the entire fragment in the URL with this payload and press Enter. The browser's script loader will fetch the "file" from your URL, which is simply your code, and execute it.
This is a severe DOM-based XSS. The vulnerability is that the application uses untrusted, user-controlled data (
location.hash
) as the source for dynamically loading a script. This effectively gives an attacker the ability to run any code they want in the context of the vulnerable page.
Last updated