XSS (Cross-Site Scripting) is one of the most popular vulnerabilities in the world of web applications. On the OWASP TOP 10 list it has been ranked first in terms of popularity for many years. Until now, XSS has usually been identified only in the world of browsers. However, due to the fact that HTML and JavaScript have been increasingly used in the world of desktop applications (e.g., Electron framework) and mobile applications (e.g., Cordova), the effects of XSS can be more serious than ever before. In this article, we will look at the example of an application for macOS systems – BetterZip – and how an XSS can be used to execute arbitrary code on a computer.
What is XSS
XSS (Cross-Site Scripting) is the vulnerability of the Internet world, which allows the attacker to run their own JavaScript script in the context of the attacked website. The well-known example of this is when one of the HTTP query parameters is reflected directly in the HTML code. The simplest example is to execute a query to the following address:
/search.php?query=<script>alert(1)</script> , to receive:
1 |
<div>No results were found for <strong><script>alert(1)</script></strong></div> |
Usually, in the XSS examples is shown execution of the code alert(1), although, of course, displaying a message in JavaScript does not cause any serious consequences. However, this is sufficient proof that you can execute your own JS code. So how can XSS be used in real world? There are several effects:
● The possibility of stealing session cookies and, consequently, accessing the session of the user who has been attacked.
● The ability to read any data in the context of the compromised domain. For example, XSS in Gmail can allow all user emails to be read.
● The ability to perform any actions in the context of the compromised domain. For example, XSS on Facebook can allow you to like or share any pages.
● Attacks on a user’s network or computer; e.g., using browser exploits or performing basic port scans.
Later in the article we will focus on this third effect—the ability to perform any actions in the context of the attacked domain.
BetterZip and QuickLook
BetterZip is an application for viewing and creating archives (7z, rar, zip, etc.) for the macOS system. In the default installation, BetterZip is also attached to the QuickLook function in the system, by which pressing the space bar in the default file browser on macOS will display the preview of this file. When using QuickLook, archive contents are displayed on the zip files (Figure 1).
As you can see in Figure 1, the fragment of the name in one of the files is underlined. I noticed it once by accident when I ran QuickLook on one of the files that I had on the disk. Then I checked what the real file names were inside the archive, and it came out that the name of this “underlined” file was: something<u>other.jpg. This leads to the conclusion that in QuickLook it is possible inject your own HTML code.
An Attempt to Execute JavaScript Code
Since we already know that we can inject our own HTML code, the natural next step is to inject our own JavaScript code. The first thought would be to add the most standard injection; i.e., <script>alert(1)</script>. However, we cannot use it because it contains a slash (“/”) character that cannot be used in the file name; this sign is a folder separator in the path.
It is therefore necessary to use HTML without a slash, which brings to mind another standard injection of JS: <img src=1 onerror=alert(1)>. The HTML browser action is as follows:
- The browser tries to download a file named “1” (value of the src attribute).
- It is very likely that such a file will not exist or will not be a picture.
- Then the browser triggers the onerror event and, consequently, calls the alert(1) code.
So I prepared a file named <img src=1 onerror=alert(1)>, packed it into the zip archive, and tried to open QuickLook. The picture clearly appeared (Figure 2), but no alert was made.
This behavior could have resulted from one of two main reasons:
- In QuickLook, you can use the HTML code, but there is no JS engine connected to it. This means the code cannot be executed.
- The JS code has indeed been executed, but function alert is not defined in the context in which it is executed.
The second option seemed quite probable, so I decided to use a different JS code. Instead of trying to trigger an alert, I can simply try to replace the full content of the page. From JS, you can do this by referencing the document.body element and its innerHTML properties. So the new file name is: <img src=1 onerror=document.body.innerHTML=’AAAAAA’>. As a result the content of the page should change into several letter A’s. As you can see in Figure 3, it really happened!
This way I have already gained sufficient proof that I can execute my JavaScript code in QuickLook. The last and most important issue remained to be solved: what interesting thing can I do with this JS code?
“Install the Application for the User and Run”
It turns out that BetterZip provides several options from QuickLook to quickly unpack the archive. They are visible in Figure 4.
The third option is the most interesting: “Install the application for the user and run”. After selecting it, BetterZip unpacks the archive file to the ~/Applications directory and, if there is an executable inside, the application launches automatically!
Therefore, the user can ”click” this option from the menu, and we, as attackers, will want to automatically “click” it from the JavaScript level. To make this work a little easier, it’s a good idea to download the full HTML sources of this page with QuickLook. To achieve this, it was enough to retrieve the contents of document.documentElement (it corresponds to the main element of <html> in the document) as follows: <img src=1 onerror=document.documentElement.textContent=document.documentElement.outerHTML>. Thanks to this the content of the page will be replaced by its full HTML, which can then be copied to the clipboard and analyzed.
Let’s look at what the HTML fragment in which the element is defined <select>:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<a href="#" id="presetLink" name="presetLink"> <select name="preset" onchange="extractWithPreset(this);"> <option disabled="disabled" selected="selected"> Extract with preset </option> <option value="1-Click%20unpack"> 1-Click unpack </option> <option value="1-Click%20unpack%20and%20clear"> 1- Click unpack and clear </option> <option value="Install%20application%20for%20user%20and%20run"> Install application for user and run </option> </select> </a> |
Let’s analyze what happens when the user clicks on the “Install application for user and run” option from the interface. First of all, the index of the selected <option> element is set to 3 (this is the fourth consecutive element <option> with indexing from zero), then the onchange event is triggered, in which the extractWithPreset function is called (this function simply changes the href of the parental link) for which the argument is the <select> element. Finally, as the <select> element is nested in the <a> element, a click is clicked on the link from the <a> element.
From JavaScript, we’ll do exactly the same:
- We set the index of the selected element to 3.
- We trigger extractWithPreset function.
- We simulate clicking the link.
From the JS code level, it looks like this:
1 2 3 4 5 6 7 8 |
// We obtain a reference to the <select> element var select = document.querySelector('select'); // We choose the fourth element select.selectedIndex = 3; // We trigger the extractWithPreset function extractWithPreset(select); // We "Simulate" clicking the link with id presetLink document.querySelector('#presetLink').click(); |
Therefore, to perform an attack, we need to prepare a file with the extension .command (this is the macOS equivalent of .sh files), in which we can perform any malicious operation on the victim’s computer and give the file a name that will contain the JavaScript code. It may look like this: <img src=1 onerror=”select=document.querySelector(‘select’); select.selectedIndex=3;extractWithPreset(select); document.querySelector(‘#presetLink’).click();”> . Next, we need to pack the file into the zip file, send it to the victim and hope they run this QuickLook file.
The effect can be as shown in Figure 5.
Summary
The article shows, on the example of BetterZip, how the XSS vulnerability, usually associated with web applications, spreads into desktop applications. In this case, it could be used to execute any code on the victim’s computer. Due to the growing popularity of Electron frameworks, one can expect that such attacks in the coming years will become more and more popular.
This error in BetterZip was submitted to the author on June 25, 2016, and it was repaired in the version from July 14, 2016. As a reward for finding it, the author gave me a free license.
Autor Michał Bentkowski