Stealing tokens, hacking jQuery and bypassing Same-Origin Policy – how I won XSSMas Challenge 2016

In this article:

  • You will learn an interesting way to read tokens from another domain.
  • You will learn how to make XSS using jQuery.
  • You will see how to break Same-Origin Policy using Flash.

XSSMas Challenge is a challenge (in the style of CTF) organized for several years by Cure53. As you can guess from the name, tasks are always announced around Christmas and involve the use of XSS vulnerabilities. Of course, doing this XSS is not easy and usually requires the use of some specific browser features or new attack methods.

The task from the end of 2016 was available at https://xssmas2016.cure53.de/. On the main page we will find out that the goal is to execute XSS in the domain https://xssmas2016.cure53.de, which will display the token in the alert, extracted from the domain https://juicyfile.cure53.de. So it looks like the solution to the exercise will also require breaking the Same-Origin Policy in some way. Let’s see in order what was required to solve the exercise.

Step 1. Access to / pathway

On the homepage of the task in the red border, we find a link that leads to a page with a URL similar to https://xssmas2016.cure53.de/pathway?access_token=589df7f247923#employee. The URL has access_token, which is unique for each user (i.e., it is stored in the session). If we provide an incorrect access_token, we will, unfortunately, get a message about forbidden access (Figure 1).

Fig. 1. “Access denied” after providing an incorrect access_token

The conclusion is that the first step which we have to go through is to steal this access_token. This is very important, because, anticipating the facts, the website/pathway will be the entry point through which we will make XSS.

The access_token content is downloaded from https://xssmas2016.cure53.de/token.json?v=1.

Fig. 2. The contents of the token.json file

As we can see in Figure 2, in response to token.json we get a JSON object, in which one of the needed elements is access_token. We have control over the parameter v, which is rewritten in the answer in the version. My first idea to extract this token was to use the attack known as JSON hijacking. This method, however, turned out to be a dead end.

In fact, to extract the token you had to use CSS. One of the creators of the task – File Descriptor – once described on his blog how you can use style sheets to extract data from another domain using UTF-16 encoding. Let’s start with a few words about UTF-16 encoding: this is non-ASCII encoding, where each character is written on two or four bytes. For example, if we try to read the text written in UTF-8 in UTF-16 encoding, the most common is a series of “bushes”, resulting from the fact that UTF-16 “swallows” two bytes as one character. For example, suppose we have the “TEST” string. If we try to read it in UTF-16BE encoding (UTF-16 Big Endian), we will get a string: “瑥獴”. Why so? In the string “TEST”, subsequent characters have the following ASCII codes: 0x74, 0x65, 0x73, 0x74. When the text is interpreted as UTF-16, we suddenly get two characters U+7465 and U+7374.

So let’s go back to token.json. We can try to attach this file to HTML in two ways:

Fig. 3. Attaching the token.json file without any defined encoding
Fig. 4. Attaching token.json with UTF-16BE encoding

In Figure 3 and Figure 4, we see that the browser (Chrome) takes into consideration the encoding we have defined.

Then we will have to take advantage of two facts:

  • In token.json we have control over one parameter, which is reflected in the response.
  • In CSS, we are able to define certain properties that can later be read from within JavaScript.

So let’s try with the following code:

Thanks to this, we hope that we will inject in the CSS the following code fragment: ,  *{animation:, which will make every element on the page have an animation property defined with a value equal to that which is located further in token.json.

Fig. 5. The defined “animation” property in CSS
Fig. 6. The “Styles” tab shows that CSS was actually interpreted by the browser

In Figures 5 and 6, we see that the browser has interpreted the CSS fragment that we injected in token.json and assigned to the animation properties characters from one of the eastern alphabets.

Our last task is to get this value in JavaScript and convert these characters back to ASCII. We will use here the function getComputedStyle and escape/unescape. The next steps are shown in Figure 7.

Fig. 7. Step by step presentation of how to read access_token in JS

In this way we have completed the first stage of the task—we have extracted the access_token and are able to go to the pathway page with the correct token. As of now, the source code looks like this:

Step 2. XSS by jQuery

We already know how to get access_token to get to https://xssmas2016.cure53.de/pathway. The next step: we will perform an XSS from this page. At the very end of the page source is a piece of code that immediately notes:

The well-known XSS in jQuery is used here, consisting in the possibility of passing the HTML/JS code fragment in the selector. In older versions of jQuery, the following code was able to display an alert:

However, the task used the newest available version, jQuery, where this type of trick did not work. An attempt to refer to the address; e.g., https://xssmas2016.cure53.de/pathway?access_token=58c7ca43d2f27#<img src = 1 onerror = alert (1)>, resulted in displaying an error in the browser console (Figure 8).

Fig. 8. An attempt to execute XSS by jQuery causes an error

It seemed that it was necessary to find another way to make XSS.

But maybe let’s go back to the source code of the page/pathway for a moment:

JQuery is loaded in the first line. However, on the seventh line, we see verification if the jQuery object exists; if not, then jQuery is loaded again, but from a different path! It turns out that there is a much older version of jQuery in this path and it is vulnerable to XSS.

Cure53 as a hint for this part gave a link to the song Inner Circle – Sweat (A La La Long). And the tip is actually in the title – it’s about the word “long.”

When we send an HTTP query to a server, by default the browsers include a Referer header whose value indicates the URL of the page from which the query was made. Virtually all servers have restrictions on the permissible length of the header values. It turns out that the server code.jquery.com (with not entirely clear reasons) was closing the connection when the Referer header had at least 5,000 bytes.

Is it enough to add five thousand arbitrary characters to the URL? The page/pathway, and then after the hash we can put a fragment of the code executing XSS. Currently, the code looks like this:

Fig. 9. Execution of XSS in the domain xssmas2016.cure53.de

Compared to the previous code, the only change we did was adding five thousand ampersands to the path, and after the hash mark we have the most standard XSS code. Figure 9 shows that XSS is actually executing and in the background—in the browser console—ERR_CONNECTION_CLOSED error is seen when trying to load jQuery from code.jquery.com.

Step 3. Stealing the Token from juicyfile.cure53.de

Our last task is to steal the token from the domain https://juicyfile.cure53.de. After entering the site, we see that the token is displayed at the beginning, while underneath is a flash applet showing a bouncing Santa with a reindeer (Figure 10). Unless the flash applet itself was useful to us, it was most likely an indication that the solution would need something to do with the Flash.

Fig 10. The appearance of the site juicyfile.cure53.de

It turns out that at the address https://juicyfile.cure53.de/crossdomain.xml there is a policy file for Flash.

Policy defines that flash applets hosted in the xssmas2016.cure53.de domain are assigned permission to read data from the juicyfile.cure53.de domain. So we have to solve two problems:

  1. Prepare a flash applet for downloading data from the juicyfile.cure53.de domain.
  2. To host this flash in the domain xssmas2016.cure53.de.

To compile your own SWF file we will use the as3compile tool (available in the swftools package, for installation in Kali distribution). SWF files are compiled from ActionScript, which is the same standard as JavaScript. Below I will paste a simple example of an ActionScript file that will download data from the juicyfile.cure53.de domain and display an alert with the content of the token.

To compile this ActionScript file we can use the command:

As a result, the exploit.swf file with the compiled Flash code will be created in the same directory.

The last remaining problem is: how do we make this exploit.swf file hosted on the domain https://xssmas2016.cure53.de? We have XSS in this domain, but it still does not make us able to host our Flash file in this domain.

To the rescue comes Service Workers. In a nutshell: this is a fairly new mechanism in browsers that allows us to define in JavaScript a proxy that intercepts all queries sent by the web application to external servers. Hence, from the level of Service Workers we can replace the content of any HTTP response.

To be able to register a malicious Service Worker, the following conditions must be met:

  • The domain must work in HTTPS (which is true for xssmas2016.cure53.de).
  • We have to be able to upload our own JS code with the header Content-type: application/javascript set.

The second condition may seem quite a big hurdle, but in the domain xssmas2016.cure53.de there is an endpoint from JSONP, in which we have full control over the call back.

Fig. 11. JSONP with full control over callback

Let’s see what the Service Worker code looks like:

The Service Worker code must be included in the response from JSONP (Figure 12).

Fig 12. JSONP returning Service Worker

Still, a Service Worker has to be registered. We will use the following code for that purpose:

We register the Service Worker defined in JSONP, and after successful registration, we redirect it to any other subpage in the domain https://xssmas2016.cure53.de. As a result—after this redirection—the browser will refer to Flash, which will download and cause the alert token.

The final code looks like:

Figure 13 shows the working code.

Fig. 13. Final, working code

Summary

The solution to XSSMas Challenge 2016 required us to solve three problems:

  • Reading the access_token value from another domain.
  • Implementation of XSS by jQuery.
  • Reading the final token using Flash.

To solve them it was necessary to:

  • Refer to https://xssmas2016.cure53.de/token.json with forced UTF-16-BE encoding, which allows to interpret this page as CSS and later read access_token from JavaScript.
  • Make sure that the latest available jQuery version is not loaded. For this purpose, it was necessary to add a large number of characters to the URL so that the connection to code.jquery.com was blocked.
  • Read data from the domain juicyfile.cure53.de using Flash. For this purpose, it was necessary to first compile the appropriate SWF file. Next, using Service Workers, from the browser’s point of view, make the file appear to be hosted in the domain xssmas2016.cure53.de.After completing all the above steps, the task was solved.

What do you do to try to protect yourself against errors that were used in the task?

  • Remember to set the Content-Type header with encoding for all responses. The first part of the attack would not go past if the server returned the Content-Type: application/javascript;charset=utf-8.
  • When using JSONP, do not allow any characters to be defined in the call back, as well as limit its length (e.g., up to 20 characters).