Closed Bug 1661071 (CVE-2020-26975) Opened 5 years ago Closed 4 years ago

Missing restricted header check in Browser.EXTRA_HEADERS

Categories

(Fenix :: General, defect, P1)

Unspecified
Android
defect

Tracking

(firefox82 wontfix, firefox83 wontfix, firefox84 fixed)

RESOLVED FIXED
Tracking Status
firefox82 --- wontfix
firefox83 --- wontfix
firefox84 --- fixed

People

(Reporter: kanytu, Assigned: sebastian)

References

Details

(Keywords: reporter-external, sec-moderate, Whiteboard: [reporter-external] [client-bounty-form] [verif?][geckoview:m83][adv-main84+])

Attachments

(5 files)

2.44 MB, application/vnd.android.package-archive
Details
224.77 KB, video/mp4
Details
136.81 KB, application/zip
Details
349 bytes, text/x-python-script
Details
564 bytes, text/plain
Details
Attached file poc.apk

Summary

Missing restrictions in the way Mozilla Firefox for Android deals with headers from Browser.EXTRA_HEADERS allow a malicious application to inject sensitive headers in a request such as cookies, leading to session-fixation.

Environment

  • Device: HTC m8
  • OS version: Android 9
  • Package name: org.mozilla.firefox
  • App version: 79.0.5 (versionCode 2015758619)

Proof of concept

Pre-conditions:

  • PoC installed
  • Python3 installed
  • Mozilla Firefox installed
  • ngrok (optional for easy tunneling)

Steps:

  1. Start the server.py (see attachments) using the following command:
$ python3 server.py
  1. Start PoC app in the device
  2. Type the URL of the server (step 1) in the EditText of the application
  3. Tap "Start"

Result

A webpage opens in Firefox containing the Headers of the request. Cookie header can be seen there.

Expected result

Restricted headers should not be allowed to be set.


Detailed explanation

When the user taps in Start in the malicious app, the following intent is fired:

val intent = Intent(Intent.ACTION_VIEW)
intent.putExtra("android.support.customtabs.extra.SESSION", true)
intent.data = Uri.parse(edit.text.toString())
intent.`package` = "org.mozilla.firefox"
val bundle = Bundle()
bundle.putString("Cookie", "cookie_here")
bundle.putString("Sec-Fetch-Site", "same-site")
intent.putExtra(Browser.EXTRA_HEADERS, bundle)

This intent accepts a Bundle of headers the user wants to inject in the request. However, there are no restrictions to which headers can be set here.

According to this list, there are several headers that shouldn't be changed.

In this attack, these are passed to the server.

The server attached only prints the headers from the request.


Vulnerable code


Remediation

  • These headers should be cross checked with the list of forbidden headers.

Attachments

https://drive.google.com/drive/folders/1WR0oFzcxM568IB5GH-TG_G3k-TZP1x3Y?usp=sharing

  • server.py - Python3 HTTP server
  • poc.zip - Source code of the PoC
  • poc.apk - Compiled Android binary
  • video.mp4 - Video showing the exploit in action

Impact

Cookies can be changed, leading to session fixation.

Other impact of changing the forbidden headers apply.

Flags: sec-bounty?
Attached video video.mp4
Attached file poc.zip
Attached file server.py
Group: firefox-core-security → mobile-core-security
Type: task → defect
Component: Security → Security: Android
Product: Firefox → Fenix

This was added in bug 1567549 and the security concerns were considered at that time, but maybe we missed things. What do you see as the harm here? The malicious app is malicious, and could host a webview of its own and inject whatever headers into the request. Clearly this can do harm to the receiving web app, but it is a malicious app, after all. What are the advantages to the malicious app to loading this in a Firefox custom tab?

I suppose you could take advantage of ambient authority (the user's cookies). There's probably an argument to block any Sec- headers like XHR/Fetch do, but then again you could imagine apps wanting that.

You could certainly do session fixation with the cookies bit, and then maybe get the user's password manager to fill something in in a fake password form in the wrong user's account?

Component: Security: Android → General
Flags: needinfo?(ckerschb)
Product: Fenix → GeckoView

Taking this needinfo for ckerschb.
I can't think of any threats besides those you listed. Spoofing, abusing ambient authority (cookies) and session fixation.
We should restrict custom headers and only allow safelisted headers.

If the malicious app wanted to use custom headers, I suppose it ought to issue its own HTTP requests?

Flags: needinfo?(ckerschb)

Thank you for reporting, Pedro! I'm currently rating this sec-low as per our severity ratings, but I'd be curious if you can find attacks against common websites that are bad enough for us to make this sec-moderate.
To clarify: I'm willing to re-adjust in the light of new information, but this is not a "negotiation" ;-)

Flags: needinfo?(kanytu)
Keywords: sec-low

Hey again team,

Here is some extra info about this behaviour (which was reported to Chromium too):

https://bugs.chromium.org/p/chromium/issues/detail?id=873178

Thanks,
kanytu

Flags: needinfo?(kanytu)
Assignee: nobody → agi
Severity: -- → S3
Priority: -- → P1
Whiteboard: [reporter-external] [client-bounty-form] [verif?] → [reporter-external] [client-bounty-form] [verif?][geckoview:m83]

I could swear we didn't allow any of the Sec-* headers. But I can't find that code anywhere.

From Google's documentation: https://developers.google.com/web/android/custom-tabs/headers

From version 83 onward, Chrome started filtering all except whitelisted cross-origin headers, since non-whitelisted headers posed a security risk. Starting with Chrome 86, it is possible to attach non-whitelisted headers to cross-origin requests, when the server and client are related using a digital asset link.

So basically Comment #5 is what Chrome does until 85.

This sounds like something that should be handled in the app that implements CustomTab. Other uses of loadUri might have different requirements.

Status: UNCONFIRMED → NEW
Component: General → Security: Android
Ever confirmed: true
Product: GeckoView → Fenix
Assignee: agi → nobody

I'll take a look at this.

Assignee: nobody → s.kaspari
Status: NEW → ASSIGNED

(In reply to Agi Sferro | :agi | ⏰ PST | he/him from comment #10)

This sounds like something that should be handled in the app that implements CustomTab. Other uses of loadUri might have different requirements.

I'll look at implementing this on our side. But I'll also want to ask about how feasible this would be to add on the GeckoView side - since we already pass in other flags like "external". Mostly I am concerned about the future where the requirements may change. If there's already a similar check in Gecko then there's a higher chance that this one may get updated and we start using it automatically through GeckoView. No one will remember or update the Kotlin implementation.

Discussed with :sebastian on Slack, we're adding an API in GV to enforce CORS safelist and then AC can use that in CustomTab

@agi: Do I understand the new API correctly: We now filter additional headers by default and AC doesn't need to do anything to fix this bug here?

Flags: needinfo?(agi)

If you use the new API that's correct! The old loadUri still does not filter headers.

Flags: needinfo?(agi)

Ah, great, I'll focus on migrating to that then. :)

We just switched to the new Loader API in AC and also explicitly set the filter flag when headers are provided:
https://github.com/mozilla-mobile/android-components/commit/1ee9bb664de103f4326c632a02e444ad77749dba

This should go into Fenix Nightly later today and then ride the trains together with 84.

Status: ASSIGNED → RESOLVED
Closed: 4 years ago
Resolution: --- → FIXED
Flags: sec-bounty? → sec-bounty+
Keywords: sec-lowsec-moderate
Group: mobile-core-security → core-security-release
Whiteboard: [reporter-external] [client-bounty-form] [verif?][geckoview:m83] → [reporter-external] [client-bounty-form] [verif?][geckoview:m83][adv-main84+]
Attached file advisory.txt
Alias: CVE-2020-26975
Group: core-security-release
Component: Security: Android → General
OS: Unspecified → Android
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: