Exposed chrome:// resources allow browser version, OS, and locale detection
Categories
(Core :: Security, defect, P3)
Tracking
()
People
(Reporter: forwarding4, Unassigned)
References
(Blocks 1 open bug, )
Details
(Keywords: privacy, testcase, Whiteboard: [fingerprinting][tor 29745])
Attachments
(1 file)
|
369.78 KB,
image/png
|
Details |
User Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36
Steps to reproduce:
The default permissions defined in the chrome.manifest file allow specific paths to be called from any web page.
For example, chrome://browser/content/* or chrome://global/content/*.
Actual results:
In consequence of these default permissions, hundreds of chrome resources (e.g., JavaScript, CSS, image files such as JPG, PNG, or SVG, as well as other file types) can be loaded from web pages without the knowledge or consent of the browser user.
Differences in the presence of certain files can reveal Firefox versions as well as the operating systems used (Windows, Mac, Linux, Android).
This technique works alongside with Firefox's built-in fingerprinting protection activated, in private sessions and in the latest Firefox releases (tested on 66 - OS:Windows).
From Firefox version 21 (May 2013) each base version is uniquely identifiable - including operating system detection.
This website shows a live demonstration: https://privacycheck.sec.lrz.de/active/fp_cd/fp_chrome_detect.html (Screenshots are attached)
For version detection image resources are not necessary. Image resources are shown for demonstration purposes.
By only checking the availability of the filenames of JS and CSS files, all versions are identifiable.
From version 10 to 62, all versions from the releases repro (https://ftp.mozilla.org/pub/firefox/releases/) are included (for Windows/Linux/Mac)
in resource retrieval (for resources which will be checked for Version Detection).
Versions 63-66 were manually added for Windows and partially for Linux without adding/checking new resources, which are only present in newer versions.
If source inspections are performed (see attached image) even sub versions can be identified.
This version detection renders UA spoofing in Firefox completely useless.
For fingerprinting purposes this version detection gives persistent and reliable results.
Browser users/developers who modified access permissions or modified chrome resources may generate an individual, potentially unique resource combination.
The Tor default configuration allow this technique to work.
Tor Versions 4/6/8 on Windows and Tor 8 on Linux are added for demonstration.
All other Firefox based browsers with exposed omni.ja are vulnerable to the abovementioned detection technique:
- Detection for Cliz Version 1.23.3 (63.03+1.32.3, 2019) on Windows (32-bit) was added for demo (without checking Cliz exclusive files)
- Detection for Pale Moon 28 (2019) on Windows (32-bit) was added for demo (without checking Pale Moon exclusive files)
Expected results:
chrome resource permissions should be adapted, so that no website is allowed load internal resources (but Firefox based features should still remain functional)
Updated•7 years ago
|
Updated•7 years ago
|
Comment 1•7 years ago
|
||
I'm not sure the right person to look at this is; but I think I'll start with Christoph and see what he thinks. Why do we need this stuff to be web-accessible?
Comment 2•7 years ago
|
||
(In reply to Tom Ritter [:tjr] (On Leave) from comment #1)
I'm not sure the right person to look at this is; but I think I'll start with Christoph and see what he thinks. Why do we need this stuff to be web-accessible?
I agree, this is bad in terms of fingerprinting - but I don't know why those need to be web accessible at all - maybe legacy reasons? Gijs knows way more about packaging than I do.
Gijs, do you think we could remove permissions and not make those files accessible to web content?
Comment 3•7 years ago
|
||
Marking this sensitive for now - till we have more information.
Comment 4•7 years ago
|
||
(In reply to Christoph Kerschbaumer [:ckerschb] from comment #2)
(In reply to Tom Ritter [:tjr] (On Leave) from comment #1)
I'm not sure the right person to look at this is; but I think I'll start with Christoph and see what he thinks. Why do we need this stuff to be web-accessible?
I agree, this is bad in terms of fingerprinting - but I don't know why those need to be web accessible at all - maybe legacy reasons? Gijs knows way more about packaging than I do.
Gijs, do you think we could remove permissions and not make those files accessible to web content?
The short answer is that it'll break things.
These packages are content-accessible for legacy reasons; they contain e.g. stuff sourced from about:neterror and friends, which are unprivileged.
Separating out such files from the bits that don't need to be contentaccessible is possible, but a lot of work, and requires enumerating exactly which bits are and aren't accessible.
The other option here is to somehow use the new-ish (well, newer than contentaccessible) separation between unprivileged about pages and unlinkable about: pages to make contentaccessible resources not actually web-accessible (ie only accessible from unprivileged about: pages). That might be easier or might be harder to do, I wouldn't know without trying. There might still be other things that need to really really be content accessible (e.g. builtin cursor images, default stylesheets, etc.).
I'm surprised that people are surprised by this. It's been like this since bug 292789. I don't think there's any point keeping the bug secret.
Comment 5•7 years ago
|
||
(In reply to forwarding4 from comment #0)
This version detection renders UA spoofing in Firefox completely useless.
Well, to be fair, UA spoofing hides more than just the major OS (to four generic OSes), it also spoofs the platform version, so it's not entirely useless. But there are other ways such as math to detect architecture and even if the Firefox build is 32 or 64 bit build (not that we shouldn't try to close those as well)
Version info is also easily obtained by feature detection (features that have no pref and can't be changed by the end user) - see [1]. But this (i.e this bug) reveals dot releases
Browser users/developers who modified access permissions or modified chrome resources may generate an individual, potentially unique resource combination.
I can confirm that a modified Firefox (e.g a user.js with lots of pref changes) influences the result. I am not sure exactly which prefs are changing the result, and not sure if it's worth investigating that further
PS: I am investigating if this leaks the language build
[1] view-source:https://ghacksuserjs.github.io/TorZillaPrint/js/screen.js < the second function getVerNo() returns FF versions 60 thru to 67 as a PoC
Comment 6•7 years ago
|
||
(In reply to Simon Mainey from comment #5)
PS: I am investigating if this leaks the language build
That would be a very interesting fingerprinting leak.
Thanks Gijs for that analysis. sounds like something our ongoing about: cleanup could consider...
Comment 7•7 years ago
|
||
Thanks to OP for the code (I took your todo note and halved the size by using 4 variables for common chrome paths). I also removed all the logic for OS etc, and just output the hashes (I also only output the resources that were loaded, in a collapsed state) for each type so it's easy to inspect what "leaks". The hashes are based on a sorted array, as when unsorted the order of loaded resources can vary, even on the same browser and same machine. I also output a combined hash (I just concatenated the previous hashes and hashed that). I also set a 5 second delay to give all the resources time to succeed or fail - but see [1]
nice small test page (for as long as I let it live there)
and I also built it into TZP proper
PS: I just find this easier than the console hash outputs from OP's test page. No disrepect to OP. No scrolling :) I shall use this to compare hashes to see if pref changes and language builds etc vary
[1] chrome://global/content/TopLevelVideoDocument.js seems to take a very long time (30+ seconds, before it throws a TypeError) so I don't think that ever gets put into the hashes)
Comment 8•7 years ago
|
||
^^ I didn't run the hashing for 60 seconds, and nothing changed. Of course if anything throws an error, then it won't be in the results to hash anyway. So seems like a 5 seconds wait is fine
Comment 9•7 years ago
|
||
Tom made a few suggestions
I think it would be helpful if you could extend the test to output the value you're inputting to the hash function so we can compare it diff-wise and understand the differences.
I changed the output in details to be a single element (with line breaks so it's easier to read) of *all objects loaded and sorted. Now you have a single result for diffs. And the combined hash is now a hash of the sorted array used to build that.
Comment 10•7 years ago
|
||
Doesn't need to be hidden. Feature detection gets you pretty fine-grained version to start, and reading our resources is a long-known issue. We segregated things to reduce the amount of web-accessible resources, but perhaps we've junked it up since and could do with a spring cleaning.
Comment 11•7 years ago
|
||
(In reply to Tom Ritter [:tjr] (On Leave) from comment #6)
(In reply to Simon Mainey from comment #5)
PS: I am investigating if this leaks the language build
That would be a very interesting fingerprinting leak.
language build leak: https://bugzilla.mozilla.org/show_bug.cgi?id=467035
First reported 11 years ago and still vulnerable. And it can even leak with JS blocked.
Comment 12•7 years ago
|
||
Just FYI: I know OP only looked at chrome://, but there are also resource:// items, I have just never bothered to enumerate them
Comment 13•7 years ago
|
||
(In reply to Simon Mainey from comment #12)
Just FYI: I know OP only looked at
chrome://, but there are also
resource://items, I have just never bothered to enumerate them
Bug 863246 dealt with those. However, while re-reading that ticket I wonder what we actually achieved there given that we had chrome:// URIs on the radar back then (see comments 45-52 there)...
Comment 14•7 years ago
|
||
(In reply to Georg Koppen from comment #13)
(In reply to Simon Mainey from comment #12)
Just FYI: I know OP only looked at
chrome://, but there are also
resource://items, I have just never bothered to enumerate themBug 863246 dealt with those. However, while re-reading that ticket I wonder what we actually achieved there given that we had chrome:// URIs on the radar back then (see comments 45-52 there)...
I thought resource:// was primarily about extensions? I don't think extensions expose chrome:// URIs?
Comment 15•7 years ago
|
||
(In reply to Tom Ritter [:tjr] (On Leave) from comment #14)
(In reply to Georg Koppen from comment #13)
(In reply to Simon Mainey from comment #12)
Just FYI: I know OP only looked at
chrome://, but there are also
resource://items, I have just never bothered to enumerate themBug 863246 dealt with those. However, while re-reading that ticket I wonder what we actually achieved there given that we had chrome:// URIs on the radar back then (see comments 45-52 there)...
I thought resource:// was primarily about extensions?
No. resource:// is just another way of registering things in omni.ja and giving it a URL.
I don't think extensions expose chrome:// URIs?
They don't, and neither do they expose resource: ones - they (can) expose moz-extension URIs.
Comment 16•7 years ago
|
||
(In reply to Georg Koppen from comment #13)
(In reply to Simon Mainey from comment #12)
Just FYI: I know OP only looked at
chrome://, but there are also
resource://items, I have just never bothered to enumerate themBug 863246 dealt with those. However, while re-reading that ticket I wonder what we actually achieved there given that we had chrome:// URIs on the radar back then (see comments 45-52 there)...
I'm not entirely sure what you mean when you say "dealt with those". If you mean chrome://, about: and resource:// are all considered as the same issue by everyone, then cool :)
If you meant resource:// is already locked down, I guess that depends on how you define this - I can pull and read resource images (e.g on TB: resource://onboarding/img/tor-watermark.png, surely there are others in Firefox, not sure on how to enumerate them). I don't think this adds anything more to the PoC, just wanting to make sure we're all aware of the three sources
Comment 17•7 years ago
|
||
Using THIS test: https://ghacksuserjs.github.io/TorZillaPrint/extra.html (permanent home)
Conclusions (see results set below)
- does not leak 32 vs 64 bit browser build
- does not leak OS architecture (32 vs 64)
- does not leak OS beyond major family (Linux, Windows, Mac, Android)
- does not usually leak dot releases (as far as I can tell, moving forward). Obviously it depends if any resources were added/removed, and the list being checked being kept up to date, but looking at Windows results below,
ESR60.*+FF60.*builds are indistinguishable, as are61.*, and62.*releases. After that OP's list wasn't fully maintained. I think it may be rare that any resources ever change in dot releases (also see observation point 2)
Some observations
- some images can be detected by css alone (by using fallback images to see if they exist) - maybe all png and jpg images be converted to svg ? Not a high priority, but something to consider?
- if all users keep up to date with updates, then all users should fall into one of eight buckets (4xOS, 2x ESR/Stable) - even if dot releases were always detectable. These attributes are already easily obtained via other methods: e.g math routines alone provide more entropy
- I do not think you will ever get less than these 8 sets as a minimum: not that we shouldn't try and also make fingerprinting have to work for it (and also cater for accessing sites with JS blocked)
- for Georg: Tails vs Debian same release for TB is FP'able? I can understand
8.0.6vs8.0.7vs8.0.8etc being different (lots of changes with help, about:tor etc until you get it all done), but same version? maybe that's something you can discuss and re-test in the Tor ticket
Results: TB
8.0.7 (64) W7-64 a090c620d15a830c3e3c3eb987404334646ed1cb \
8.0.8 (54) W7-64 a090c620d15a830c3e3c3eb987404334646ed1cb /
8.5a7-10 (64) W7-64 8facaec56bb34f2f207fe79e14483b676598079d
--
8.0.6 (64) Mint 046d5d382f775e9357bc9d926d487a21abb5af1a
8.0.8 (64) Debian d0858cfd62b96f28190dee18a26ed6d9ab900754 \
8.0.8 (64) Tails 6e2534705c4d3cfdd43df8257bcf9a0680232f2b / why this change
FF Windows
ESR60.5.2(32) W7-64 b2325ec3bb0403f05717c7ebd33be926a09e5309
ESR60.6 (64) W7-64 b2325ec3bb0403f05717c7ebd33be926a09e5309
60.0 (64) W7-64 b2325ec3bb0403f05717c7ebd33be926a09e5309
60.0.2 (32) W7-64 b2325ec3bb0403f05717c7ebd33be926a09e5309
--
61.0 (64) W7-64 bacec337cb44885abe1faa091ff26ead44340d0b
61.0.2 (32) W7-64 bacec337cb44885abe1faa091ff26ead44340d0b
--
62.0 (64) W7-64 4f12f55667ddc3ae7e615da095924970533139d8
62.0.3 (32) W7-64 4f12f55667ddc3ae7e615da095924970533139d8 <-- en-US: baseline
^ Italian - 4f12f55667ddc3ae7e615da095924970533139d8
^ TradChinese - 4f12f55667ddc3ae7e615da095924970533139d8
^ Japanese - 4f12f55667ddc3ae7e615da095924970533139d8
^ Hindi - 4f12f55667ddc3ae7e615da095924970533139d8
^ Arabic - 4f12f55667ddc3ae7e615da095924970533139d8
^ Note: using 62 as a test since PoC's list stopped adding *new* resources after that
--
63.0 (64) W7-64 650b67bf99a1cd96e92f7039e13876f94599a34e
63.0.3 (32) W7-64 650b67bf99a1cd96e92f7039e13876f94599a34e
--
64.0.2 (64) W7-64 a195a0fc81a26f5f9687c2082d3b7318f9194a2a
64.0.2 (32) W7-64 a195a0fc81a26f5f9687c2082d3b7318f9194a2a
--
65.0.1 (32) W7-64 36ab1ad97058ad39c3648168d141962d27c356ee
65.0.2 (64) W7-64 36ab1ad97058ad39c3648168d141962d27c356ee
--
66.0.b10 (32) W7-64 10de8cf1a5eb3c0a6146aeeb58d992b5b08b02e8
66.0 (64) W7-64 10de8cf1a5eb3c0a6146aeeb58d992b5b08b02e8 <- w/w-out +300 pref changes
66.0.1 (64) W7-64 10de8cf1a5eb3c0a6146aeeb58d992b5b08b02e8
--
67.0b3 (64) W7-64 eca73bc2420d5910de366e90b179a9d793e5baec
--
68.0a1 (64) W7-64 601713641c34c9bc5eae66ca28322981d24ddc6b
Linux
ESR60.5.1(64) Mint 3239a59eec5e292152f89c5fcebf61e20c8fe22c
60.0.2 (64) Mint 3239a59eec5e292152f89c5fcebf61e20c8fe22c
--
61.0.2 (64) Mint 3d64122788ae0d3f735259ab60484e43213517ff
62.0.3 (64) Mint d66e58f991a03ee625a3c4db0ddbcdbd3b94a589
--
63.0.3 (64) Mint d49a2b94e7f273c076d8b9562d03ee8fec811171
--
64.0.2 (64) Mint 27b63c1b6c449ffa4ed16741fc3e26a0e8eb0df4
--
65.0.1 (64) Mint d4fa8c1dd50d669fbe93de61d9111f112d05f869
65.0.2 (64) Ubuntu d4fa8c1dd50d669fbe93de61d9111f112d05f869
--
66.0 (64) Ubuntu 442ae3d8efddac1393da6a3c8af8bfaa206c3be6
66.0 (64) Debian 442ae3d8efddac1393da6a3c8af8bfaa206c3be6
66.0 (64) Arch 442ae3d8efddac1393da6a3c8af8bfaa206c3be6
66.0 (64) Manjaro 442ae3d8efddac1393da6a3c8af8bfaa206c3be6
66.0b7 (64) Mint 442ae3d8efddac1393da6a3c8af8bfaa206c3be6 <-beta with same hash
Comment 18•7 years ago
|
||
(In reply to Simon Mainey from comment #17)
- does not leak OS architecture (32 vs 64)
Forgot to add the some results from W7-32 to illustrate that
8.0.6 (32) W7-32 a090c620d15a830c3e3c3eb987404334646ed1cb
ESR60.5.2(32) W7-32 b2325ec3bb0403f05717c7ebd33be926a09e5309
61.0.2 (32) W7-32 bacec337cb44885abe1faa091ff26ead44340d0b
65.0.1 (32) W7-32 36ab1ad97058ad39c3648168d141962d27c356ee
(In reply to Simon Mainey from comment #17)
I can confirm that a modified Firefox (e.g a
user.jswith lots of pref changes) influences the result
Forgot the mention that prefs do not change the hash. I jumped the gun, as OP's demo failed to return a version on my everyday FF with approx 300 pref changes from default values. Retested on a vanilla profile, and confirmed, no changes.
Comment 19•7 years ago
|
||
(In reply to :Gijs (he/him) from comment #4)
The short answer is that it'll break things.
These packages are content-accessible for legacy reasons; they contain e.g. stuff sourced from about:neterror and friends, which are unprivileged.
Separating out such files from the bits that don't need to be contentaccessible is possible, but a lot of work, and requires enumerating exactly which bits are and aren't accessible.
Okay, that's what we did in Bug 863246 for resource:// so it is possible
The other option here is to somehow use the new-ish (well, newer than contentaccessible) separation between unprivileged about pages and unlinkable about: pages to make contentaccessible resources not actually web-accessible (ie only accessible from unprivileged about: pages). That might be easier or might be harder to do, I wouldn't know without trying. There might still be other things that need to really really be content accessible (e.g. builtin cursor images, default stylesheets, etc.).
So it sounds like the path forward for this bug is:
- Figure out if some content accessible resources need to be fully content accessible.
- If not, try to make all resource:// URIs non-web-accessible and only loadable by privledged or unprivledged about: pages
- If yes, start by replicating Bug 863246 for chrome:// and make everything needed contentacessible
- Then, potentially as a followup, restrict contentaccessibility further by making some stuff non-webaccessible but leaving some stuff as web accessible.
Comment 20•6 years ago
|
||
(In reply to Tom Ritter [:tjr] (On Leave) from comment #19)
(In reply to :Gijs (he/him) from comment #4)
The short answer is that it'll break things.
These packages are content-accessible for legacy reasons; they contain e.g. stuff sourced from about:neterror and friends, which are unprivileged.
Separating out such files from the bits that don't need to be contentaccessible is possible, but a lot of work, and requires enumerating exactly which bits are and aren't accessible.
Okay, that's what we did in Bug 863246 for resource:// so it is possible
Sure, it's just work and regression-prone, and I don't know anyone who has cycles to tackle it.
The other option here is to somehow use the new-ish (well, newer than contentaccessible) separation between unprivileged about pages and unlinkable about: pages to make contentaccessible resources not actually web-accessible (ie only accessible from unprivileged about: pages). That might be easier or might be harder to do, I wouldn't know without trying. There might still be other things that need to really really be content accessible (e.g. builtin cursor images, default stylesheets, etc.).
So it sounds like the path forward for this bug is:
- Figure out if some content accessible resources need to be fully content accessible.
- If not, try to make all resource:// URIs non-web-accessible and only loadable by privledged or unprivledged about: pages
I assume you meant 'chrome://' rather than 'resource://' here?
For the resource: case, I can already tell you that we load browser (ie default) stylesheets and their resources using resource://, and making those not accessible from "normal" web content would presumably break web rendering... I don't /think/ that uses any chrome:// resources, but I could be wrong.
- If yes, start by replicating Bug 863246 for chrome:// and make everything needed contentacessible
- Then, potentially as a followup, restrict contentaccessibility further by making some stuff non-webaccessible but leaving some stuff as web accessible.
I don't understand what the difference is between (3) and (4). What I think we want to do is both:
(i) make all the current contentaccessible chrome packages non-contentaccessible (ie remove the "contentaccessible" annotations from jar.mn), then create separate (a) package(s) that is contentaccessible and only move the things there that really really need to be contentaccessible; and then
(ii) potentially restrict contentaccessible chrome:// and not have it be reachable/usable from web content at all, only from content-privileged about: pages.
While I understand that in theory, (ii) fixes this entire bug in one step and that might tempt us to skip (i) if possible, I expect it'll (a) be harder (mostly because of unit tests that rely on the current behavior) and (b) it loses us some separation of privilege between content-privileged about: pages (like about:neterror) and non-content-privileged ones, which is ultimately a "safety net" / "belt and suspenders" type thing that helps with keeping things as contained as possible. Things like script files being reachable from pages that don't normally load them has bitten us before now (cf. bug 1432358).
Comment 21•6 years ago
|
||
For what it is worth it's not just browser version and OS that leaks here but the locale can be detected as well even if privacy.spoof_english is enabled. z3t reported a nice PoC to HackerOne:
The French intl.css stylesheet applies a specific quotes property to q elements, changing their width
<html>
<head>
<link id="PoC_css" rel="stylesheet" href="chrome://global/locale/intl.css">
</head>
<body>
<q id="PoC" lang="fr"></q>
</body>
<script>
var width1 = document.getElementById("PoC").offsetWidth;
document.getElementById("PoC_css").disabled = true;
var width2 = document.getElementById("PoC").offsetWidth;
alert(width1 + " | " + width2);
</script>
</html>
Updated•6 years ago
|
Updated•6 years ago
|
Updated•3 years ago
|
Updated•1 year ago
|
Updated•11 months ago
|
Description
•