Closed Bug 1245795 (CVE-2016-9061) Opened 4 years ago Closed 3 years ago

API Key (glocation) in broadcast protected with signature-level permission can be accessed by an application installed beforehand that defines the same permissions

Categories

(Firefox for Android :: General, defect)

47 Branch
defect
Not set

Tracking

()

RESOLVED FIXED
Firefox 50
Tracking Status
firefox49 --- wontfix
firefox-esr45 --- unaffected
fennec + ---
firefox50 --- fixed

People

(Reporter: kenken0980, Assigned: Grisha)

Details

(Keywords: sec-moderate, Whiteboard: [post-critsmash-triage][adv-main50+])

Attachments

(4 files, 2 obsolete files)

Attached file poc-apikey.apk
User Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.97 Safari/537.36

Steps to reproduce:

1. Launch an emulator (or device) whose API level is 19( or lower)
2. Install attached poc app (poc-apikey.apk) with adb
3. Install firefox for android (fennec) with adb
4. Launch and use firefox app


Actual results:

The poc app can receive a broadcast protedted with "org.mozilla.fennec.permission.PER_ANDROID_PACKAGE".
So, the poc app can read API Key in the broadcast.


Expected results:

The broadcast cannot be read from app whose signature is different from Mozilla's one.
Or the broadcast will change so that it does not have api key.
Flags: sec-bounty?
tracking-fennec: --- → ?
Ken, can you attach the source for your apk?
Flags: needinfo?(kenken0980)
Ah, source might not be very interesting. I guess the problem is that the poc app declares the permission first, and this somehow confuses the Android permission system. The Fennec permission protection is set to 'signature', but apparently that is not respected if the permission has already been declared elsewhere. Not sure what we can really do about this.
Flags: needinfo?(kenken0980)
There is a good description of the problem here: http://blog.trendmicro.com/trendlabs-security-intelligence/android-custom-permissions-leak-user-data/

This does appear to be a bug in Android, but we may be able to work around it by adding UID checks.
Actually, since we're broadcasting an intent here, I don't know if there is anything we can do other than not broadcast this...
This is the same as Bug 1229681, and I'm irritated that I didn't address these usages at the same time.

It's easy to address, though: make everything android:exported="false" as appropriate and remove the permissions.

This is a hold-over from the android-sync github repo days, when we had (mostly during development) multiple packages communicating in this way; and from the Old Sync days, when the account type was shared between Android packages.  That's no longer the case, so this can be addressed more simply.
Assignee: nobody → nalexander
tracking-fennec: ? → +
(In reply to James Willcox (:snorp) (jwillcox@mozilla.com) from comment #1)
> Ken, can you attach the source for your apk?

Hi, James

Here is my poc source code.
Attached file Poc(source).zip
Here is my poc source code.
Status: UNCONFIRMED → NEW
Ever confirmed: true
(In reply to Nick Alexander :nalexander from comment #5)
> This is the same as Bug 1229681, and I'm irritated that I didn't address
> these usages at the same time.
> 
> It's easy to address, though: make everything android:exported="false" as
> appropriate and remove the permissions.

As you point out, this is the same as Bug 1229681 from an attacker.
but I think it is only a little different in the perspective of countermeasure.

In Bug 1229681, the receiver must be modified so that it refuse access from other application.(e.g. exported="false")

In this bug, the sender must be corrected so that other application cannot access the intent which is thrown by the sender. (e.g. LocalBroadcastManager)
(In reply to Ken Okuyama from comment #8)
> (In reply to Nick Alexander :nalexander from comment #5)
> > This is the same as Bug 1229681, and I'm irritated that I didn't address
> > these usages at the same time.
> > 
> > It's easy to address, though: make everything android:exported="false" as
> > appropriate and remove the permissions.
> 
> As you point out, this is the same as Bug 1229681 from an attacker.
> but I think it is only a little different in the perspective of
> countermeasure.
> 
> In Bug 1229681, the receiver must be modified so that it refuse access from
> other application.(e.g. exported="false")
> 
> In this bug, the sender must be corrected so that other application cannot
> access the intent which is thrown by the sender. (e.g. LocalBroadcastManager)

Meh, a distinction without a difference.  This is part of a larger, long running project of separating Beta/Release and Aurora/Fennec apart.  Most of these things are holdovers from when we expected to really share data; that idea is dead.  We'll just do everything locally, android:exported="false", LocalBroadcastManager, and not worry about the signature permissions at all.
Nick won't be able to fix this any time soon. Grisha, could you look into this?
Flags: needinfo?(gkruglov)
Assignee: nalexander → gkruglov
Flags: needinfo?(gkruglov)
Grisha, any updates on this security bug? It has been a month.
Flags: needinfo?(gkruglov)
To address this, we need to remove the PER_ANDROID_PACKAGE permission at https://dxr.mozilla.org/mozilla-central/source/mobile/android/base/FennecManifest_permissions.xml.in#24.

First, expunge all traces of OrderedBroadcastHelper.  It's a nice hook into the Android system, but it's never been used and is a security vulnerability waiting to happen.  That's one consumer of PER_ANDROID_PACKAGE gone.

Second, the interaction with the stumbler at https://dxr.mozilla.org/mozilla-central/source/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java#1013.  I think we can use the LocalBroadcastManager, or invoke the service directly.  In both cases the stumbler receiver needs to be split into the external intents and this internal intent (see https://dxr.mozilla.org/mozilla-central/source/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/mainthread/PassiveServiceReceiver.java#57 and https://dxr.mozilla.org/mozilla-central/source/mobile/android/stumbler/manifests/StumblerManifest_services.xml.in#13).

Be aware that the stumbler can be compiled out of Fennec, so it's not easy to invoke the service directly *without an Intent filter*, because the stumbler service class may not present.  (I think the build system enforces this, probably crudely!)  Therefore, I think the path is to split the receiver, and then wire up the LBM listener.  Unfortunately, there's no good way for Fennec to talk to the stumbler, for exactly the build system reasons above!  So I'd suggest sending a "safe" Intent on Fennec app startup to the stumbler telling it to register the LBM listener, and then using the LBM broadcast.  (By safe I mean a broadcast that others can trigger and it'll just set up a listener, and even then only once.  If Android gives a way to figure out that your own APp has been launched, this would work -- but I don't think it does.)  That should work even when the stumbler isn't compiled into Fennec.
Attached patch stumbler.patch (obsolete) — Splinter Review
First pass.
Flags: needinfo?(gkruglov)
Attachment #8767815 - Flags: review?(nalexander)
Pre: Purge OrderedBroadcast
Attachment #8767815 - Attachment is obsolete: true
Attachment #8767815 - Flags: review?(nalexander)
Attachment #8768099 - Flags: review?(nalexander)
Part1: Split Stumbler BroadcastReceivers into Local, System and Safe

SafeReceiver is responsible for registering LocalReceiver with a LocalBroadcastManager.
SystemReceiver is responsible for handling BOOT_COMPLETE and EXTERNAL_APPLICATIONS_AVAILABLE intents.
LocalReceiver is responsible for handling passed in Stumbler preferences (enabled state, API key, user agent).

StumblerPreferences are now sent using LocalBroadcastManager, avoiding any possibility of leaking API key.
Attachment #8768101 - Flags: review?(nalexander)
Comment on attachment 8768099 [details] [diff] [review]
no-package-permission-pre1.patch

Review of attachment 8768099 [details] [diff] [review]:
-----------------------------------------------------------------

So sad.  If it works for you, it works for me!
Attachment #8768099 - Flags: review?(nalexander) → review+
Comment on attachment 8768101 [details] [diff] [review]
no-package-permission-part1.patch

Review of attachment 8768101 [details] [diff] [review]:
-----------------------------------------------------------------

This is looking solid.  I have a few nits and a few small issues, but overall this is fine.  Test plan must include enabling/disabling the stumbler, and ensuring that we can build with the stumbler off.  (This might not be trivial, since we don't build the stumbler off in automation these days.)

I would like to see a "messaging diagram" in comments, which probably should go in `StumblerManifest_services.xml.in`.  Something like:

Application.onCreate -> system broadcast STUMBLER_PREF.  This broadcast decouples the Fennec App from the Stumbler internal library.  Most systems would use dependency injection mechanism or a message bus for this; we use the system.

Stumbler receives STUMBLER_PREF, registers local broadcast receiver.  It's safe for other apps to maliciously send STUMBLER_PREF -- this doesn't turn things on or off, just (duplicates) the listener, potentially before Fennec even starts.

Fennec starts or Fennec toggles pref -> local broadcast on/off with sensitive information.

Stumbler receives local broadcast on/off with sensitive information, adjusts internal state.

::: mobile/android/stumbler/java/org/mozilla/mozstumbler/service/mainthread/SafeReceiver.java
@@ +21,5 @@
> +
> +    private boolean registeredLocalReceiver = false;
> +
> +    @Override
> +    public void onReceive(Context context, Intent intent) {

Either synchronize this method, or explain why this doesn't need to be synchronized.  (I think it does need to be synchronized :))

::: mobile/android/stumbler/java/org/mozilla/mozstumbler/service/mainthread/SystemReceiver.java
@@ +25,5 @@
> +        }
> +
> +        final String action = intent.getAction();
> +
> +        if (!action.equals(Intent.ACTION_BOOT_COMPLETED) && !action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE)) {

In general, `TextUtils.equals` or constant first -- this will NPE if action is null.  (Which might not be possible, but we've seen *all kinds* of Intents.)

::: mobile/android/stumbler/manifests/StumblerManifest_services.xml.in
@@ +5,5 @@
>  
>  <receiver android:name="org.mozilla.mozstumbler.service.uploadthread.UploadAlarmReceiver" />
>  <service android:name="org.mozilla.mozstumbler.service.uploadthread.UploadAlarmReceiver$UploadAlarmService" />
>  
> +<receiver android:name="org.mozilla.mozstumbler.service.mainthread.SafeReceiver">

This can be `android:exported="false"`, right?

@@ +12,4 @@
>    </intent-filter>
>  </receiver>
> +
> +<receiver android:name="org.mozilla.mozstumbler.service.mainthread.SystemReceiver">

This should be `android:exported="true"` for clarity, right?
Attachment #8768101 - Flags: review?(nalexander) → review+
Addressed feedback for patch: Split Stumbler BroadcastReceivers into Local, System and Safe
Attachment #8768101 - Attachment is obsolete: true
Attachment #8769021 - Flags: review?(nalexander)
Comment on attachment 8769021 [details] [diff] [review]
no-package-permission-part1.patch

Review of attachment 8769021 [details] [diff] [review]:
-----------------------------------------------------------------

If it works for you, it works for me!  Good job on these sec patches.
Attachment #8769021 - Flags: review?(nalexander) → review+
https://hg.mozilla.org/integration/fx-team/rev/3687f36b1f85c09aaa4c47c99a3286fd7975b9ff
Bug 1245795 - Pre: Purge OrderedBroadcast r=nalexander

https://hg.mozilla.org/integration/fx-team/rev/97ac5877d152245c846ce052f2a60e2a250f6b72
Bug 1245795 - Split Stumbler BroadcastReceivers into Local, System and Safe r=nalexander
https://hg.mozilla.org/mozilla-central/rev/3687f36b1f85
https://hg.mozilla.org/mozilla-central/rev/97ac5877d152
Status: ASSIGNED → RESOLVED
Closed: 3 years ago
Resolution: --- → FIXED
Target Milestone: --- → Firefox 50
The bounty on bug 1229681 was higher than justified by the rating/impact (too much holiday partying?) but we shouldn't hold that against this bug: this gets a bounty too.
Flags: sec-bounty? → sec-bounty+
Group: firefox-core-security → core-security-release
Flags: qe-verify-
Whiteboard: [post-critsmash-triage]
Whiteboard: [post-critsmash-triage] → [post-critsmash-triage][adv-main50+]
Alias: CVE-2016-9061
Group: core-security-release
You need to log in before you can comment on or make changes to this bug.