10

I'm having a hard time trying to make my local files accessible to javascript (for opening in a new window) from Chrome, and already found a workaround in Firefox. My question is: why javascript cannot open a file in a new browser window (with window.open) by default? I cannot see any security issues with this.

The only thing I'm reading everywhere on this topic is: "Web sites should not have access to my disk for reading files." But javascript actually can't possibly read the content of the files because of the Same-origin policy. You can test it as below.

For example, in the settings of NoScript you can choose Advanced->Trusted and mark "Allow local links". Now open Firefox console and execute (you should allow pop ups for this):

x = window.open('file:///%some_path_to_text_file%')
x.document

I'm getting 'Error: Permission denied to access property "document" [Learn More]'. So, what's the deal? Is it safe to keep option "Allow local links" in NoScript all the time?

Wolfram
  • 203
  • 2
  • 5
  • 6
    I still remember those shady advertisements from the late 90s and early 2000s which tried to scare you into downloading some dubious security tools by showing you the contents of your local filesystem. – Philipp Mar 13 '17 at 12:14

2 Answers2

8

This is a reasonable question to ask, because it's not immediately apparent why merely opening arbitrary file URLs is bad in the same way that reading arbitrary file URLs is bad. Here's the short answer:

These are the holes caused by letting sites link to local files:

A1. If the browser or any helper app (e.g. RealPlayer) puts untrusted files in a predictable location, any page can link to that file and thus read every file on your hard drive.

A2. Holes in same-origin policy (cross-domain) become read-any-file-on-your-hard-drive holes.

But same-origin holes are already considered serious enough to block releases (they let sites steal cookies, passwords, and info on intranet web servers).

A3. DoS attacks against the browser or even the OS using file:///con/con or /dev/stuff.

https://bugzilla.mozilla.org/show_bug.cgi?id=84128#c190

These issues are still relevant today with e.g. the 2017 exploit in Firefox for Android that allowed a malicious website to read files from /sdcard/Download/ (CVE-2017-7759).

Android intent URLs given to Firefox for Android can be used to navigate from HTTP or HTTPS URLs to local "file:" URLs, allowing for the reading of local data through a violation of same-origin policy.

https://nvd.nist.gov/vuln/detail/CVE-2017-7759

Steps to reproduce:

Visit an remote (http) webpage:

<script>
location="intent:file:///(path)#Intent;type=text/html;end";
</script>

Actual results:

The JS code above redirects the user to file: URL.

The redirection allows remote pages to exfiltrate files in /sdcard/Download/.

https://bugzilla.mozilla.org/show_bug.cgi?id=1356893

The browser security handbook gives a good explanation of the more general rationale:

In the case of file:, web sites are generally prevented from navigating to local resources at all. The three explanations given for this decision are as follows:

  • Many browsers and browser plugins keep their temporary files and cache data in predictable locations on the disk. The attacker could first plant a HTML file in one these spots during normal browsing activities, and then attempt to open it by invoking a carefully crafted file:/// URL. As noted earlier, many implementations of same-origin policies are eager to bestow special privileges on local HTML documents (more), and so this led to frequent trouble.

  • Users were uncomfortable with random, untrusted sites opening local, sensitive files, directories, or applications within <IFRAME> containers, even if the web page embedding them technically had no way to read back the data - a property that a casual user could not verify.

  • Lastly, tags such as <SCRIPT> or <LINK REL="stylesheet" HREF="..."> could be used to read back certain constrained formats of local files from the disk, and access the data from within cross-domain scripts. Although no particularly useful and universal attacks of this type were demonstrated, this posed a potential risk.

https://code.google.com/archive/p/browsersec/wikis/Part2.wiki

So the browser does its best to enforce the same-origin policy, but it doesn't always succeed, as demonstrated by the Firefox for Android bug and more generally the existence of XSS vulnerabilities.

Furthermore, because of cache files, remote files can possess real file:// URLs. Browsers are careful to make profiles and cache filenames unpredictable, but all it takes is one untrusted file in a known location and it's game over. Even if malicious remote Javascript can't directly access the filesystem, it can affect cache files and cookies.

if someone can cause a file to be downloaded to your machine (in a cache file, or by having the user consent to download it to a known directory), and the downloaded file contains JS, then referencing it via a file: URL on a hostile web page would cause the JS to be run, and since it's coming from the local drive, it would run with privileges.

https://bugzilla.mozilla.org/show_bug.cgi?id=40538

if an attacker can cause content to be placed on the user's hard drive, for example by setting a cookie, stuffing the cache, etc., and can cause that content to execute in the browser, then that content can communicate information back to the attacker, one way or another.

https://bugzilla.mozilla.org/show_bug.cgi?id=101207

It's also worth asking: what should "same origin" mean for a file:// URL? Should it be just that file's directory and its subdirectories, or should it be the entire filesystem?

In Gecko 1.8 or earlier, any two file: URIs are considered to be same-origin. In other words, any HTML file on your local disk can read any other file on your local disk.

Starting in Gecko 1.9, files are allowed to read only certain other files. Specifically, a file can read another file only if the parent directory of the originating file is an ancestor directory of the target file. Directories cannot be loaded this way, however.

https://developer.mozilla.org/en-US/docs/Archive/Misc_top_level/Same-origin_policy_for_file:_URIs

Finally, note that a malicious script with the ability to instruct the browser to load a file can cause harm even without the ability to read the file. Loading arbitrary file:// URLs can be used to crash the browser or interfere with keyboard input.

Not all URI loads are safe. For example, loading some file: URIs can hang the browser or even crash the operating system in some cases.

https://developer.mozilla.org/en-US/docs/Archive/Mozilla/Safely_loading_URIs

the server doesn't need to be able to read the result of the load to cause damage. On some Win98 systems, loading file:///C:/con/con causes a crash and data loss. Similar results could come from accessing something in file:///dev/* on Unix, and I believe similar problems exist on Mac as well.

https://bugzilla.mozilla.org/show_bug.cgi?id=101207

The following HTML will cause Mozilla (and Netscape 4.77) to open /dev/tty0, which will cause all keyboard input from /dev/tty0 to be eaten:

<img src="file:///dev/tty0">

I suggest that Mozilla should never attempt to open a file URI when the content has been loaded via something other than file (http, https, ftp, etc).

https://bugzilla.mozilla.org/show_bug.cgi?id=91316

As an example, on Unix systems, clicking a link like <A HREF="file:///dev/zero"> will cause the browser to start writing an infinitely large file of zeros. There are similar problems on Windows.

https://bugzilla.mozilla.org/show_bug.cgi?id=47988

So, to summarize:

  • Local files have greater privileges than remote files, so allowing remote Javascript to open local Javascript can allow for privilege escalation.

  • Browsers don't always perfectly enforce the same-origin policy, and bugs in the same-origin policy can allow arbitrary file access if all file:// URLs are considered to have the same origin.

  • Some file:// URLs can cause malicious effects just by allowing the browser to open them.

Related questions:

Are there any know browsers that support file URL redirection?

Same-origin policy for file: URLs in Android browser?

Can malicious Javascript in local HTML -file send files to internet in Firefox/Chrome?

4

If the browser is able to open a file from the computer I could see a malicious actor downloading a browser exploit payload to the user's computer and then having the js open that file exploiting something in the browser.

In this case the attacker would have to have an exploit for the user's browser that attacked the way that the browser reads a file. These exploits are fairly common to come by.

It also might be possible for the attacker to download a file to the user's computer that then uses it's system level context to grab other files and exfiltrate them via embedding them in the src of an image (I've used this one before). But I am not 100% sure if a file running in the browser from local could access other files, maybe someone else can charm in on that or I'll build a proof of concept if I get some extra time.

In most cases it's just not a great idea to mix internet content with local.

MikeSchem
  • 2,311
  • 1
  • 13
  • 36
  • 1
    This is interesting, but it sounds like speculation. Care to share a link to a statement from the Chrome developers? AKA [citation needed]. – A. Hersean Mar 14 '17 at 12:43
  • What can an exploit look like that the script can use it only if the script is executed in a local file? Honestly, I'm not sure about this, was there any real precedents? The concept that a downloaded script can break same-origin policy, because it is already on the drive, looks more plausible, and I really can get the content of another file of the same folder via console. (and not get this "Permission denied" message). However, for some reason I couldn't do the same via the script built into the first file (`x.document.body.innerText === ''` in this case). Maybe I'll experiment a bit more. – Wolfram Mar 14 '17 at 14:48
  • Real precedent: do you need more arguments than that if you have XSS attack that works between domains, it might also work between a webserver and local data? – Marcus Müller Mar 15 '17 at 00:07
  • @Wolfram try just putting the information you want to exfiltrate in the src tag of an image. Like `` . When the local page tries to load it, the image the sensitive data will be sent to the php, just log the get variables from the `infostealer.php` and you should see the data. – MikeSchem Mar 15 '17 at 00:22
  • @A.Hersean there is now a statement from Firefox: https://www.mozilla.org/en-US/security/advisories/mfsa2019-21/#CVE-2019-11730 – Wolfram Mar 10 '21 at 09:32