Closed Bug 1641487 (CVE-2020-15677) Opened 4 years ago Closed 4 years ago

Firefox Browser - Download Site Obscured from User

Categories

(Firefox :: Downloads Panel, defect, P1)

defect

Tracking

()

VERIFIED FIXED
81 Branch
Tracking Status
firefox-esr68 --- wontfix
firefox-esr78 81+ fixed
firefox79 --- wontfix
firefox80 --- wontfix
firefox81 --- verified

People

(Reporter: r.j.thomas, Assigned: Gijs)

Details

(Keywords: csectype-spoof, sec-moderate, Whiteboard: [reporter-external] [client-bounty-form] [verif?][adv-main81+][adv-esr78.3+])

Attachments

(6 files, 2 obsolete files)

University of Birmingham Vulnerability Report - Firefox Browser - Download Site Obscured from User

About this Document

This document details a vulnerability identified by the University of Birmingham in the Firefox Web Browser.

University of Birmingham Contact Information

The researchers, Richard Thomas and Tom Chothia can be contacted at {r.j.thomas,t.p.chothia}@cs.bham.ac.uk. Please contact us for our PGP key.

Crediting the University of Birmingham

The University of Birmingham would appreciate credit to the researchers and the University for any advisories which you may publish about this issue.

Please inform the researchers via their contact email addresses should you:

  • confirm that this is a security issue
  • allocate the issue a CVE identifier
  • determine a date to release a patch
  • determine a date to publish advisories

University of Birmingham Disclosure Policy

The University of Birmingham follows a responsible, coordinated disclosure approach with affected parties. We do not publicly disclose vulnerabilities without consulting the vendor.

The University of Birmingham recognises that vendors need a reasonable amount of time to mitigate a vulnerability, understand the impact to customers, triage other vulnerability reports and implement resolutions in coordination with others and its customers. The researchers are happy to discuss how such disclosures may take place.

If the researchers believe a vendor is not making appropriate progress with the resolution of this vulnerability, we may, following discussion with the vendor, choose to share details with the UK National Cyber Security Centre to protect UK interests.

Summary

A User Interface (UI) Misrepresentation of Critical Information issue exists on the Download UI process on the Firefox browser, and has been tested on Firefox 76.0.1 for Windows, MacOS and Linux (Kali Repositories). This can be exploited by an adversary exploiting an Open Redirect (CWE-601) on a trusted device to display the source of the download in the Download List UI as the trusted device, and not the true download site.

If a user is tricked into downloading and running a malicious file by making the trusted host appear in the downloads list, they will be more likely to run the malware.

These vulnerabilities have a Severity Score of 7.1 and a High Severity rating (based on the Common Vulnerability Scoring System v3.1).

CVSS

This vulnerability has a Severity Score of 7.1 and a High Severity rating (the CVSS Vector is AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:L).
The Common Weakness Enumeration ID is CWE-451: User Interface (UI) Misrepresentation of Critical Information.

Details

The Firefox browser is one of a number of cross-platform browsers which commonly used by end-users. Where an Open Redirect vulnerability (CWE-601) exists on a device that is trusted by the user, the response to a user request may redirect the user to untrusted content which was not initially requested. In Firefox, given an Open Redirect using the HTTP POST method, upon receipt of the HTTP 302 Redirect from the trusted device, the browser may start a download of a malicious file from the adversary. Where Firefox displays a dialog box for the user to select whether to Open or Save the file, the adversary host is displayed as the source, however, upon completion of the download, the Download UI on Firefox displays the trusted device as the source of the download in the list. Where the user has previously configured Firefox to automatically save files of a particular type, the user would see the trusted device as the download host, not the adversary's host.

On MacOS, if the user attempts to execute an installer downloaded via the Open Redirect, MacOS Gatekeeper will confirm that Firefox downloaded the file from the trusted device, and not the true download site.

This issue has been tested on Firefox 76.0.1. on Windows 10 Enterprise N (Version 1709), MacOS 10.15 Catalina and Kali Linux 2019.4.

Steps to reproduce:

  • Submit a HTTP POST request to a trusted device, which will issue a HTTP 302 Redirect to another site, hosting a download.
  • If a download prompt is displayed, the site should be shown as the one indicated in the 302 Redirect. Click Save.
  • Once the download has completed, click the Download UI Button, and the file should show there. No host is displayed. Click 'Show All Downloads' and the downloaded file will show in the list with the host shown as the trusted device, not the true download site.

PoC code is given at the bottom of this report.

Mitigation

Firefox should display the name of the host that the file was downloaded from in teh download list (i.e. the host stated in the download dialog), not the name of the host that issued the redirect.

Note

This issue was identified during the assessment of an Open Redirect Vulnerability using POST, which is undergoing responsible disclosure with the Vendor.

A minimal example demonstrating this behaviour is given below:

  1. Trusted Page simulating Open Redirect form behaviour (test.html)
    <!DOCTYPE html>
    <html>
    <body>
    <form action="index.php" method="POST">
    <input type="submit" value="Submit">
    </form>

<p>If you click the "Submit" button, the form-data will be sent to a page called "/index.php".</p>

</body>
</html>

  1. PHP (on server) to trigger the download and force this behaviour
    <?php
    Header("HTTP/1.1 302 Object Moved" );
    Header("Content-Type: text/html; charset=UTF-8");
    Header("Cache-Control: no-cache");
    Header("Pragma: no-cache");
    Header("Expires: 0");
    Header("Location: //<Download Page>");
    Header("Content-Length: 0");
    Header("Connection: close");
    exit();
    ?>
Flags: sec-bounty?

(In reply to Richard J. Thomas from comment #0)

Steps to reproduce:

  • Submit a HTTP POST request to a trusted device, which will issue a HTTP 302 Redirect to another site, hosting a download.

Is the POST part significant here, ie does it not happen with a 302 on a GET request?

  • If a download prompt is displayed, the site should be shown as the one indicated in the 302 Redirect. Click Save.

Which of the 2 sites is "the site" referring to, and when this says "should", does it mean that's the desired behaviour or that's what you're seeing as actual behaviour?

  • Once the download has completed, click the Download UI Button, and the file should show there. No host is displayed. Click 'Show All Downloads' and the downloaded file will show in the list with the host shown as the trusted device, not the true download site.

FWIW, I suspect the current behaviour is intentional... Showing the final origin of the file would mean always showing CDN domains, rather than the domain from which the user believes they downloaded something (because they clicked a link on that domain). Marco, thoughts?

On MacOS, if the user attempts to execute an installer downloaded via the Open Redirect, MacOS Gatekeeper will confirm that Firefox downloaded the file from the trusted device, and not the true download site.

What happens for this case in Safari? From some naive checks with other downloads (e.g. downloading the windows migration tool off of https://support.apple.com/en_GB/downloads , or downloading the Firefox dmg from mozilla.org ) and checking file info, it appears Safari registers both the page URL and the final, post-redirect URL, in the "where from" section shown by Get Info. I don't get a gatekeeper warning when expanding a Firefox dmg (maybe I've already told macOS I trust mozilla.org?) so I'm unsure which metadata attributes gatekeeper is using in your case - but are they different from what happens in Safari? In terms of the metadata I'm familiar with, I'm seeing exactly the same behaviour in Firefox (checking with xattr -lp com.apple.metadata:kMDItemWhereFroms path/to/file ) for the aforementioned download examples (the mozilla.org case redirects from https://download.mozilla.org/?product=firefox-latest-ssl&os=osx&lang=en-GB ).

Flags: needinfo?(r.j.thomas)
Flags: needinfo?(mak)
Type: task → defect
Component: Security → Downloads Panel
Attached file xattr-firefox.txt

xattr output for Firefox downloaded DMGs

Attached file xattr-safari.txt

xattr output for Safari

Attached image Safari-Gatekeeper.png

Safari Gatekeeper dialog

Attached image Firefox-Gatekeeper.png

Firefox Gatekeeper Dialog

Hi,
Thanks for the quick actioning on this.

(In reply to :Gijs (he/him) from comment #1)

(In reply to Richard J. Thomas from comment #0)

Steps to reproduce:

  • Submit a HTTP POST request to a trusted device, which will issue a HTTP 302 Redirect to another site, hosting a download.

Is the POST part significant here, ie does it not happen with a 302 on a GET request?

Yes - the download list shows the actual download site for GET requests, but POST triggers this disparity between the download dialog box (if shown) which has the real download site, and the download list showing the trusted device as the host.

  • If a download prompt is displayed, the site should be shown as the one indicated in the 302 Redirect. Click Save.

Which of the 2 sites is "the site" referring to, and when this says "should", does it mean that's the desired behaviour or that's what you're seeing as actual behaviour?

In the Download dialog (if shown to the user), it shows the real download site, not the trusted device as the 'from:' field.

  • Once the download has completed, click the Download UI Button, and the file should show there. No host is displayed. Click 'Show All Downloads' and the downloaded file will show in the list with the host shown as the trusted device, not the true download site.

FWIW, I suspect the current behaviour is intentional... Showing the final origin of the file would mean always showing CDN domains, rather than the domain from which the user believes they downloaded something (because they clicked a link on that domain). Marco, thoughts?

I trust the two previous clarifications clear this point up too - in a GET (i.e. a user clicking onto or navigating directly to a URL), the final origin matches the dialog, but in POST, the dialog 'from:' does not match the download host in the Download List.

On MacOS, if the user attempts to execute an installer downloaded via the Open Redirect, MacOS Gatekeeper will confirm that Firefox downloaded the file from the trusted device, and not the true download site.

What happens for this case in Safari? From some naive checks with other downloads (e.g. downloading the windows migration tool off of https://support.apple.com/en_GB/downloads , or downloading the Firefox dmg from mozilla.org ) and checking file info, it appears Safari registers both the page URL and the final, post-redirect URL, in the "where from" section shown by Get Info. I don't get a gatekeeper warning when expanding a Firefox dmg (maybe I've already told macOS I trust mozilla.org?) so I'm unsure which metadata attributes gatekeeper is using in your case - but are they different from what happens in Safari? In terms of the metadata I'm familiar with, I'm seeing exactly the same behaviour in Firefox (checking with xattr -lp com.apple.metadata:kMDItemWhereFroms path/to/file ) for the aforementioned download examples (the mozilla.org case redirects from https://download.mozilla.org/?product=firefox-latest-ssl&os=osx&lang=en-GB ).

In testing, we used Burp Suite Community as the example DMG, which is not signed, and triggers the Gatekeeper popup which displays where the file came from, where the user would have to press Ctrl and click to run the installer. The xattr outputs for Firefox and Safari are attached, as well as the Gatekeeper UI screengrabs. A quick look over the hex for the xattr output on the kMDItemWhereFroms between Safari and Firefox looks to be no different.

Best regards,
Richard

Flags: needinfo?(r.j.thomas)

(In reply to :Gijs (he/him) from comment #1)

  • Once the download has completed, click the Download UI Button, and the file should show there. No host is displayed. Click 'Show All Downloads' and the downloaded file will show in the list with the host shown as the trusted device, not the true download site.

FWIW, I suspect the current behaviour is intentional... Showing the final origin of the file would mean always showing CDN domains, rather than the domain from which the user believes they downloaded something (because they clicked a link on that domain). Marco, thoughts?

From a user point of view, showing the page they clicked seems to make more sense. The CDN case is a very good fit, it could completely differ from where the user downloaded the file, and then they could be confused.
On the other side, it seems to make sense to show the right origin of the file. Other browsers (I checked Chrome) show the complete final url, nothing about the originating page.
Omitting one of the two information seems a loss to me. Maybe we should show both, like "trusted -> actual"? Would users undestand that?

I'm not sure whether the Downloads Panel itself should show origin information, it may be handy to show it once a download is complete, but there are space limits that don't work well with a long origin string (the origin would end up being cut, that'd be bad for spoofing, but we could provide a tooltip with the full text). I also checked what Chrome does here, and it doesn't show an origin in their quick downloads UI. That seems unfortunate. I wonder if we assume, since those are just downloads for the session, the user knows where they came from? Though redirects are turning the table.

Flags: needinfo?(mak)

(In reply to Marco Bonardo [:mak] from comment #7)

(In reply to :Gijs (he/him) from comment #1)

  • Once the download has completed, click the Download UI Button, and the file should show there. No host is displayed. Click 'Show All Downloads' and the downloaded file will show in the list with the host shown as the trusted device, not the true download site.

FWIW, I suspect the current behaviour is intentional... Showing the final origin of the file would mean always showing CDN domains, rather than the domain from which the user believes they downloaded something (because they clicked a link on that domain). Marco, thoughts?

From a user point of view, showing the page they clicked seems to make more sense. The CDN case is a very good fit, it could completely differ from where the user downloaded the file, and then they could be confused.
On the other side, it seems to make sense to show the right origin of the file. Other browsers (I checked Chrome) show the complete final url, nothing about the originating page.
Omitting one of the two information seems a loss to me. Maybe we should show both, like "trusted -> actual"? Would users undestand that?

What's worth noting is that Firefox, in our opinion, correctly handles the UI Behaviour for HTTP GET requests - in our testing with the PoC given in the report, we set the redirect to the Burp Suite Community download, the dialog showed portswigger.net as the 'from:' before saving/opening the file, and also showed portswigger.net as the host in the Download List panel. For POST requests, however, the 'from:' correctly was displayed as portswigger.net, but the Download list panel listed cs.bham.ac.uk as the host (I ran the PoC on an internal server on our network).

If a user has developed trust in the Firefox download mechanism and its behaviour for GET requests, it is reasonable to assume they'll demonstrate the same behaviour on a POST request (if the dialog is not shown). If the dialog isn't shown, they are shown the host is the trusted device, in which case, most users would happily double click to launch, as they see the host as the trusted system. This then has a serious impact on trust, as a user trusts the device, and if it is exploited by an Open Redirect they will be very likely to run the file if the Download List panel states it came from an endpoint trusted by the user, and not the true download host.

I'm not sure whether the Downloads Panel itself should show origin information, it may be handy to show it once a download is complete, but there are space limits that don't work well with a long origin string (the origin would end up being cut, that'd be bad for spoofing, but we could provide a tooltip with the full text). I also checked what Chrome does here, and it doesn't show an origin in their quick downloads UI. That seems unfortunate. I wonder if we assume, since those are just downloads for the session, the user knows where they came from? Though redirects are turning the table.

Re: a user knowing where the download came from, my comment above should shed light on this - a user is not being told where the download really comes from, especially if the 'always save' checkbox has been checked at some point in time, where the first time they see the host would be through the download list panel.

You raise an interesting point. From testing just now, if you close Firefox fully down, reopen it and go to Library > Downloads, the host in the Download List panel for the download reverts to the true download host, where, in the previous session, it would have had the host issuing the redirect. This issue therefore doesn't persist across sessions, in which case it's too late as a user will typically immediately open the file they downloaded, rather than revisit the download via the Download panel, after restarting a session with Firefox. There's a definite disparity in the handling of the host between download and restarting a session.

I think that showing trusted -> actual would introduce some confusion to the user - however, telling the user the host that served the file is more worthwhile, since it a) reinforces a user decision if they knowingly saved/selected open via the download dialog, as they know the 'from' from that dialog and it would correspond to the download panel, and is the exact behaviour shown in GET requests, b) if they see a host they do not expect, they can apply reasonable judgement, (i.e. why did a Firefox download come from evil.com, not *.mozilla.com for example), and c) Firefox offers to give the user the download link page for the download.

a) is weakened somewhat if the 'always save' checkbox has been ticked at some point in time before the POST is followed, as the first time they see the download host is in the Download List panel.

OK, clearly I need to set this up to try and reproduce, and because it's crunch time for 78 (which will be an esr) branching to beta I can't do it literally right now, setting needinfo so I don't forget - I should still get to this by the end of the week at the latest.

Severity: normal → --
Flags: needinfo?(gijskruitbosch+bugs)

(In reply to Richard J. Thomas from comment #6)

(In reply to :Gijs (he/him) from comment #1)

(In reply to Richard J. Thomas from comment #0)

  • Submit a HTTP POST request to a trusted device, which will issue a HTTP 302 Redirect to another site, hosting a download.

Is the POST part significant here, ie does it not happen with a 302 on a GET request?

Yes - the download list shows the actual download site for GET requests, but POST triggers this disparity between the download dialog box (if shown) which has the real download site, and the download list showing the trusted device as the host.

[snip]

FWIW, I suspect the current behaviour is intentional... Showing the final origin of the file would mean always showing CDN domains, rather than the domain from which the user believes they downloaded something (because they clicked a link on that domain). Marco, thoughts?

I trust the two previous clarifications clear this point up too - in a GET (i.e. a user clicking onto or navigating directly to a URL), the final origin matches the dialog, but in POST, the dialog 'from:' does not match the download host in the Download List.

Sorry, this has taken me a while to get back to. But already early into my trying to dig into this, I'm a bit surprised. Because I figured, based on this comment, that there's a trivial good/bad difference - the form from comment #0 with a "GET" request to index.php should work (so shows portswigger in the downloads UI), and a form with a "POST" request doesn't (and shows the testcase host, localhost in my case). But that's not what I'm seeing, I'm seeing localhost everywhere, from a testcase that looks like this adaptation from comment #0:

<!DOCTYPE html>
<html>
<body>
<form action="index.php" method="GET">
  <input type="submit" value="Submit">
</form>

<p>If you click the "Submit" button, the form-data will be sent to a page called "/index.php".</p>

</body>
</html>

(OK, I actually created an <input type=radio> set of controls that lets me easily switch between POST and GET, but the effect is the same)

Does that match what you're seeing? Maybe I'm misunderstanding where you think the POST/GET difference comes into it? Were you comparing to clicking a link that points to index.php , maybe?

Flags: needinfo?(gijskruitbosch+bugs) → needinfo?(r.j.thomas)

(In reply to :Gijs (he/him) from comment #10)

Were you comparing to clicking a link that points to index.php , maybe?

I just tried this, too, and this too displays localhost.

(In reply to :Gijs (he/him) from comment #11)

(In reply to :Gijs (he/him) from comment #10)

Were you comparing to clicking a link that points to index.php , maybe?

I just tried this, too, and this too displays localhost.

I hadn't tried serving the pages locally, but can confirm the behaviour you're seeing if localhost is serving the redirect side, I am seeing localhost named as the host in the download list.

On an external host, however, Firefox demonstrates this behaviour (your bad difference to GET) - I've done a screen capture which I trust makes it clearer what is going on. This can be downloaded from https://www.dropbox.com/s/60onncb1a7jrpfv/firefox-download-ui.mov?dl=0

In this video, I run a cURL request using POST and GET to show the server is returning the same response, then connect to an external host serving that simple HTML form, and show that Firefox correctly tells you the host in the save/open dialog as portswigger.net, but the Download List shows bham.ac.uk as the host, and if you navigate directly to index.php, i.e. a GET, the save/open dialog host matches what it says in the download list. I also include what Gatekeeper reports for both downloads.

Flags: needinfo?(r.j.thomas)

(In reply to Richard J. Thomas from comment #12)

(In reply to :Gijs (he/him) from comment #11)

(In reply to :Gijs (he/him) from comment #10)

Were you comparing to clicking a link that points to index.php , maybe?

I just tried this, too, and this too displays localhost.

I hadn't tried serving the pages locally, but can confirm the behaviour you're seeing if localhost is serving the redirect side, I am seeing localhost named as the host in the download list.

On an external host, however, Firefox demonstrates this behaviour (your bad difference to GET) - I've done a screen capture which I trust makes it clearer what is going on. This can be downloaded from https://www.dropbox.com/s/60onncb1a7jrpfv/firefox-download-ui.mov?dl=0

In this video, I run a cURL request using POST and GET to show the server is returning the same response, then connect to an external host serving that simple HTML form, and show that Firefox correctly tells you the host in the save/open dialog as portswigger.net, but the Download List shows bham.ac.uk as the host, and if you navigate directly to index.php, i.e. a GET, the save/open dialog host matches what it says in the download list. I also include what Gatekeeper reports for both downloads.

I've also tested this by storing the HTML locally on my laptop and opening it in Firefox (via file:///..../test.html), hosting the PHP part on an external server and testing with POST - Firefox will show local file as the 'host' in the Download List.

(In reply to Richard J. Thomas from comment #12)

if you navigate directly to index.php, i.e. a GET, the save/open dialog host matches what it says in the download list. I also include what Gatekeeper reports for both downloads.

OK, so (based on the video) you're comparing to navigating to index.php from the URL bar. Thanks!

Flags: needinfo?(gijskruitbosch+bugs)

It would appear to be that the issue is caused by whether there is a referrer for the download. When submitting a form or clicking a link, a referrer is sent. When navigating directly to the URL that returns the 302 from the address bar, no referrer information is sent as part of that request, so no referrer info is available. Bug 675902 (!) which originally implemented the view, implemented the status text to include the referrer, falling back to the source URL if there was no referrer info available. That behaviour has been kept all these years over various refactors.

It's possible that after the ReferrerInfo work (where we potentially keep the completely referrer info internally even when it is not sent (or restricted to origin info only) as an actual header, e.g. due to referrer policy or other restrictions), we now have a referrer more often than before, and that this issue wasn't as noticeable before.

I don't really understand why we'd use the referrer at all here, unless it's for the reasons I outlined in comment #1. Marco, it's been a long time, but perhaps you remember?

(the difference after a restart is due to bug 829201 - we do not store the referrer info in the places DB that keeps the download records.)

I'm a little skeptical about exploitation here though - presumably it'd require user action on the trusted target page to submit the form, and this cannot be automated away, because loading index.php directly from the attacker page will use the attacker's referrer instead, which defeats the point (we'll show evil.com as the source of the download, instead of cs.bham.ac.uk or portswigger.net).

I haven't yet looked at the macOS gatekeeper stuff and where that data comes from / what macOS is doing there.

Flags: needinfo?(gijskruitbosch+bugs) → needinfo?(mak)

Thanks for the active discussion on this, especially with the context.

I can clarify the exploitation here. In comment 0, we found this issue whilst carrying out vulnerability research, where Open Redirect (CWE-601) vulnerabilities have been previously documented in the class of devices we are assessing. Previous exploitation of these vulnerabilities are typically achieved by a user receiving an email, say for a firmware update, where a convincing link to the update is given. In this case, the user will just need to press submit, and if, at some point, they checked the 'always save this type' checkbox, when they verify the source of the download, they would see the trusted device as the host, not evil.com, which is where the Open Redirect was exploited to refer the user to somewhere that isn't the trusted device. They are therefore more likely to open the downloaded file, as they trust the trusted device on their network.
In our PoC, we used cs.bham.ac.uk as the 'trusted device' to simulate such a vulnerable system where I would trust anything on cs.bham.ac.uk. If the open/save dialog is shown to the user, they may question why the 'from:' is evil.com when the source code shows the trusted device is where the request is going. If they continue to save, this provenance is lost for the session and the user will see the trusted device in the list, and then proceed to open the file.

I would say that bug 829201, on the face of it, works as I would expect - what the user sees in the open/save dialog is what they see in the download list. The problem is within the running session, this behaviour is different, where the 'from:' doesn't match the download host in the list which means that we lose what is possibly the last line of defence before a user runs malware.

(In reply to :Gijs (he/him) from comment #15)

I don't really understand why we'd use the referrer at all here, unless it's for the reasons I outlined in comment #1. Marco, it's been a long time, but perhaps you remember?

I don't remember, but I assume the scope was to show the closest thing to the origin from which the user downloaded the file, rather than the origin of the file itself. I also suspect we pretty much kept the behavior of the legacy toolkit download manager.
It's possible we're giving too much importance to the "user-facing" origin, since it's session-only the user is more likely to remember which page the download came from, and more interested to know from where it was actually downloaded.
Off-hand, the simplest approach here seems to just stop using the referrer. The downside is that the user may be a bit more confused in some cases (like the cdn example you pointed out), but in the end that confusion may actually be a safer path, bringing to more "do I trust this origin" questioning.
I still think the best approach would be to show both info, but considering the UX complications and lack of resources, I'd not hold my breath for that. I'd rather, once a download is complete, show the origin in the Downloads Panel too (must test appropriate cropping for long origins), potentially also in a follow-up.

Flags: needinfo?(mak)

The severity field is not set for this bug.
:mak, could you have a look please?

For more information, please visit auto_nag documentation.

Flags: needinfo?(mak)

Still looking at this, though I'm a little overloaded so it's been slow going.

Assignee: nobody → gijskruitbosch+bugs
Severity: -- → S3
Status: UNCONFIRMED → ASSIGNED
Ever confirmed: true
Flags: needinfo?(mak)
Priority: -- → P1

Hi,
Is there any update on this - if there's any support we can provide to replicate/demonstrate the issue, please let us know.

Best regards,
Richard

Flags: needinfo?(gijskruitbosch+bugs)

(In reply to Richard J. Thomas from comment #20)

Is there any update on this - if there's any support we can provide to replicate/demonstrate the issue, please let us know.

Apologies for the delay here. I've just been looking at this again. It's straightforward to remove the referrer from the internal downloads view; I have a patch in hand for that (though I've not checked what automated tests, if any, need updating).

However, the quarantine stuff is more confusing. I was initially not able to reproduce. It appears this is because Apple has some kind of exception for localhost. If I host a test page on my own (public internet) website instead of on localhost, I can reproduce, but the exact same download using localhost correctly shows portswigger.net as the origin of the download.

As your screenshots indicate, the "kMDItemWhereFroms" data is the same between Safari and Nightly. However, we have both that and the quarantine data, and that data is stored in a central DB, not in the file attributes.

Chrome has the same issue with macOS's UI (ie the gatekeeper dialog shows the referrer, not the origin). Our quarantine code is here: https://searchfox.org/mozilla-central/rev/ab81b8552f4aa9696a2524f97fdfeb59d4dc31c1/xpcom/io/CocoaFileUtils.mm#247-263 . The Chrome equivalent is at https://source.chromium.org/chromium/chromium/src/+/master:components/services/quarantine/quarantine_mac.mm;l=171-190?q=kLSQuarantineOriginURLKey&ss=chromium . As you can see we do more or less the same thing even if the code is a little different (and as is also obvious from these code snippets, Apple's variable naming is pretty confusing!).

This is what the quarantine DB looks like (with hashes/timestamps removed):

$ sqlite3 ~/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2 "select * from LSQuarantineEvent;" | grep --ignore-case burp|
org.mozilla.nightly|Firefox Nightly|https://portswigger.net/burp/releases/download?product=community&version=2020.4.1&type=MacOsx|||0||https://www.gijsk.com/temp/post-redirect-download/index.html|
com.google.Chrome|Chrome|https://portswigger.net/burp/releases/download?product=community&version=2020.4.1&type=MacOsx|||0||https://www.gijsk.com/temp/post-redirect-download/index.html|
com.apple.Safari|Safari|https://portswigger.net/burp/releases/download?product=community&version=2020.4.1&type=MacOsx|||0|||

As you can see, Safari omits the redirect info from the quarantine DB. Why this happens is a bit of a mystery to me. Chrome and Firefox both have devtools that let me see the request headers; I can't easily do this in Safari (and it's all TLS requests, so can't easily check with other tools) so I don't know if the difference is simply that Safari doesn't send the referrer for this download for some reason - though that'd be a bit odd - I see the same behaviour even if I have a simple link from gijsk.com to the dmg, which you'd definitely expect to have a referrer header.

So the question is whether we (and Chrome?) should stop passing the data to macOS, I guess? The documentation from Apple about the key where we put the referrer is at https://developer.apple.com/documentation/coreservices/klsquarantineoriginurlkey and says:

For web downloads, this property is the URL of the web page on which the user initiated the download. For attachments, this property is the URL of the resource to which the quarantined item was attached (e.g. the email message, calendar event, etc.). The origin URL may be a file URL for local resources, or a custom URL to which the quarantining app will respond when asked to open it. The quarantining app should respond by displaying the resource to the user.

The origin URL should not be set to the data URL, or the quarantining app may start downloading the file again if the user choses to view the origin URL while resolving a quarantine warning.

This implies that there is/was macOS quarantine UI that uses the referrer/origin URL in a way that's equivalent to Firefox's "Go To Download Page", where I think the resulting browser should show the original page (bham.ac.uk in the original report).

I agree that the current gatekeeper UI display can be confusing, but I don't see a good solution purely from Firefox/Chrome's perspective to resolve this dual purpose for the quarantine info; I think it's probably something to raise with Apple.

Does this all make sense?

(edited for clarity)

Flags: needinfo?(gijskruitbosch+bugs) → needinfo?(r.j.thomas)
Attached file Bug 1641487, r?jaws

Hi,
Thanks for looking into this. I think the patch you've suggested would bring the POST behaviour in line with what GET does for Firefox, and would remove that possible end-user confusion, and reduce the risk of successful exploitation (i.e. the user seeing a trusted device in the download list and continuing to run/execute that downloaded file). That would also resolve the issue across all of the Firefox installation base.

On the same day we raised this report with Mozilla, we did notify Apple about Gatekeeper and the report remains open - I'll update the report to see what the progress is on their side as this picks up the final thing that would prevent successful exploitation.

Best regards,
Richard

Flags: needinfo?(r.j.thomas) → needinfo?(gijskruitbosch+bugs)
Flags: needinfo?(gijskruitbosch+bugs)
Group: firefox-core-security → core-security-release
Status: ASSIGNED → RESOLVED
Closed: 4 years ago
Resolution: --- → FIXED
Target Milestone: --- → 81 Branch

Would you mind verifying that the issue in Firefox itself here is fixed in today's nightly? You can download nightly from https://nightly.mozilla.org/ . (Obviously I think it's fixed, but it'd be good to have confirmation we're on the same page. :-) )

Flags: needinfo?(r.j.thomas)

(In reply to :Gijs (he/him) from comment #26)

Would you mind verifying that the issue in Firefox itself here is fixed in today's nightly? You can download nightly from https://nightly.mozilla.org/ . (Obviously I think it's fixed, but it'd be good to have confirmation we're on the same page. :-) )

Hi,
I've loaded a fresh VM and installed nightly (81.0a1) and the latest production Firefox (79.0) and have tested this out using the same steps as in the report.
In nightly, I'm seeing the correct and same results as you (that is the hostname is the download host, not the redirect one) - GET and POST now have the same behaviour. In Firefox 79 (a version we know is affected), GET and POST result in different hostnames (one the true download site, the other the redirect source), so it looks like the patch has resolved the issue.

Thanks for you and your colleague's help in the resolution of this issue.

Best regards,
Richard

Flags: needinfo?(r.j.thomas)

Sorry - forgot to tag you back in the response.

Flags: needinfo?(gijskruitbosch+bugs)

Thank you!

Status: RESOLVED → VERIFIED
Flags: needinfo?(gijskruitbosch+bugs)

On second pass through going to call this one sec-moderate instead of sec-low -- making the OS lie to users seems slightly more serious than just bad UI.

Flags: sec-bounty? → sec-bounty+
Keywords: sec-lowsec-moderate

(In reply to Daniel Veditz [:dveditz] from comment #30)

On second pass through going to call this one sec-moderate instead of sec-low -- making the OS lie to users seems slightly more serious than just bad UI.

So to be clear, we didn't change anything in this bug regarding what we tell macOS. What we (and Chrome!) tell macOS matches what the docs say we should tell them (see comment #21). If I had any idea how to raise this with Apple, I would. (Edit: though also, comment #23 suggests the reporter has done so already)

Flags: needinfo?(dveditz)

Hi Gijs, does this need an ESR78 approval request?

Flags: needinfo?(gijskruitbosch+bugs)

Comment on attachment 9169497 [details]
Bug 1641487, r?jaws

ESR Uplift Approval Request

  • If this is not a sec:{high,crit} bug, please state case for ESR consideration: sec-moderate
  • User impact if declined: Potentially confusing UI around the origin of downloads
  • Fix Landed on Version: 81
  • Risk to taking this patch: Low
  • Why is the change risky/not risky? (and alternatives if risky): Strictly removal of a few lines of code
  • String or UUID changes made by this patch: None
Flags: needinfo?(gijskruitbosch+bugs)
Attachment #9169497 - Flags: approval-mozilla-esr78?

Comment on attachment 9169497 [details]
Bug 1641487, r?jaws

approved for 78.3

Attachment #9169497 - Flags: approval-mozilla-esr78? → approval-mozilla-esr78+
Whiteboard: [reporter-external] [client-bounty-form] [verif?] → [reporter-external] [client-bounty-form] [verif?][adv-main81+]
Whiteboard: [reporter-external] [client-bounty-form] [verif?][adv-main81+] → [reporter-external] [client-bounty-form] [verif?][adv-main81+][adv-esr78.3+]
Attachment #9175901 - Attachment is obsolete: true
Attached file advisory.txt
Attachment #9176112 - Attachment is obsolete: true
Alias: CVE-2020-15677
Group: core-security-release
Flags: needinfo?(dveditz)
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: